1 // Copyright 2023, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! This library is a stub for Secretkeeper, which can be used by clients. It exposes
16 //! Secretkeeper Session which can be used for using the SecretManagement API.
17 //! It encapsulates the Cryptography! AuthgraphKeyExchange is triggered on creation of a session
18 //! and the messages is encrypted/decrypted using the shared keys.
19 
20 mod authgraph_dev;
21 pub mod dice;
22 
23 use crate::authgraph_dev::AgDevice;
24 use crate::dice::OwnedDiceArtifactsWithExplicitKey;
25 
26 use authgraph_boringssl as boring;
27 use authgraph_core::keyexchange as ke;
28 use authgraph_core::key;
29 use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper
30     ::ISecretkeeper::ISecretkeeper;
31 use android_hardware_security_authgraph::aidl::android::hardware::security::authgraph::{
32     IAuthGraphKeyExchange::IAuthGraphKeyExchange, PlainPubKey::PlainPubKey, PubKey::PubKey,
33     SessionIdSignature::SessionIdSignature, Identity::Identity,
34 };
35 use coset::{CoseKey, CborSerializable, CoseEncrypt0};
36 use secretkeeper_core::cipher;
37 use secretkeeper_comm::data_types::SeqNum;
38 use secretkeeper_comm::wire::ApiError;
39 use std::cell::RefCell;
40 use std::fmt;
41 use std::rc::Rc;
42 
43 /// A Secretkeeper session that can be used by client, this encapsulates the Authgraph Key exchange
44 /// session as well as the encryption/decryption of request/response to/from Secretkeeper.
45 pub struct SkSession {
46     sk: binder::Strong<dyn ISecretkeeper>,
47     encryption_key: key::AesKey,
48     decryption_key: key::AesKey,
49     session_id: Vec<u8>,
50     // We allow seq numbers to be 0 to u64::MAX-1, increment beyond that fails
51     // Sequence number for next outgoing message encryption.
52     seq_num_outgoing: SeqNum,
53     // Sequence number for decrypting the next incoming message.
54     seq_num_incoming: SeqNum,
55 }
56 
57 impl SkSession {
58     /// Create a new Secretkeeper session. This triggers an AuthgraphKeyExchange protocol with a
59     /// local `source` and remote `sink`.
60     ///
61     /// # Arguments
62     /// `sk`: Secretkeeper instance
63     ///
64     /// `dice`: DiceArtifacts of the caller (i.e, Sk client)
65     ///
66     /// `expected_sk_key`: Expected Identity of Secretkeeper. If set, the claimed peer identity is
67     /// matched against this and in cases of mismatch, error is returned.
new( sk: binder::Strong<dyn ISecretkeeper>, dice: &OwnedDiceArtifactsWithExplicitKey, expected_sk_key: Option<CoseKey>, ) -> Result<Self, Error>68     pub fn new(
69         sk: binder::Strong<dyn ISecretkeeper>,
70         dice: &OwnedDiceArtifactsWithExplicitKey,
71         expected_sk_key: Option<CoseKey>,
72     ) -> Result<Self, Error> {
73         let ag_dev = Rc::new(RefCell::new(AgDevice::new(dice, expected_sk_key)?));
74         let ([encryption_key, decryption_key], session_id) =
75             authgraph_key_exchange(sk.clone(), ag_dev.clone())?;
76         Ok(Self {
77             sk,
78             encryption_key,
79             decryption_key,
80             session_id,
81             seq_num_outgoing: SeqNum::new(),
82             seq_num_incoming: SeqNum::new(),
83         })
84     }
85 
86     /// Wrapper around `ISecretkeeper::processSecretManagementRequest`. This additionally handles
87     /// encryption and decryption.
secret_management_request(&mut self, req_data: &[u8]) -> Result<Vec<u8>, Error>88     pub fn secret_management_request(&mut self, req_data: &[u8]) -> Result<Vec<u8>, Error> {
89         let aes_gcm = boring::BoringAes;
90         let rng = boring::BoringRng;
91         let req_aad = self.seq_num_outgoing.get_then_increment()?;
92         let request_bytes = cipher::encrypt_message(
93             &aes_gcm,
94             &rng,
95             &self.encryption_key,
96             &self.session_id,
97             req_data,
98             &req_aad,
99         )
100         .map_err(Error::CipherError)?;
101 
102         let response_bytes = self.sk.processSecretManagementRequest(&request_bytes)?;
103 
104         let response_encrypt0 = CoseEncrypt0::from_slice(&response_bytes)?;
105         let expected_res_aad = self.seq_num_incoming.get_then_increment()?;
106         cipher::decrypt_message(
107             &aes_gcm,
108             &self.decryption_key,
109             &response_encrypt0,
110             &expected_res_aad,
111         )
112         .map_err(Error::CipherError)
113     }
114 
115     /// Get the encryption key corresponding to the session. Note on usage: This (along with other
116     /// getters [`decryption_key()`] & [`session_id()`]) can be used for custom encrypting requests
117     /// (for ex, with different aad, instead of using [`secret_management_request`] method.
118     /// In that case, seq_num_outgoing & seq_num_incoming will be out of sync. Recommended use for
119     /// testing only.
encryption_key(&self) -> &key::AesKey120     pub fn encryption_key(&self) -> &key::AesKey {
121         &self.encryption_key
122     }
123 
124     /// Get the decryption key corresponding to the session.
decryption_key(&self) -> &key::AesKey125     pub fn decryption_key(&self) -> &key::AesKey {
126         &self.decryption_key
127     }
128 
129     /// Get the session_id.
session_id(&self) -> &[u8]130     pub fn session_id(&self) -> &[u8] {
131         &self.session_id
132     }
133 }
134 
135 impl fmt::Debug for SkSession {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result136     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
137         f.debug_struct("SkSession").field("session_id", &hex::encode(&self.session_id)).finish()
138     }
139 }
140 
141 /// Errors thrown by this SkSession.
142 #[derive(Debug)]
143 pub enum Error {
144     /// These are server errors : thrown from remote instance (of Authgraph or Secretkeeper)
145     BinderStatus(binder::Status),
146     /// These are errors thrown from (local) source Authgraph instance.
147     AuthgraphError(authgraph_core::error::Error),
148     /// Error originating while encryption/decryption of packets (at source).
149     CipherError(ApiError),
150     /// Errors originating in the coset library.
151     CoseError(coset::CoseError),
152     /// Unexpected item encountered (got, want).
153     UnexpectedItem(&'static str, &'static str),
154     /// The set of errors from secretkeeper_comm library.
155     SkCommError(secretkeeper_comm::data_types::error::Error),
156 }
157 
158 impl std::error::Error for Error {}
159 
160 impl std::fmt::Display for Error {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result161     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
162         match self {
163             Self::BinderStatus(e) => write!(f, "Binder error {e:?}"),
164             Self::AuthgraphError(e) => write!(f, "Local Authgraph instance error {e:?}"),
165             Self::CipherError(e) => write!(f, "Error in encryption/decryption of packets {e:?}"),
166             Self::CoseError(e) => write!(f, "Errors originating in the coset library {e:?}"),
167             Self::UnexpectedItem(got, want) => {
168                 write!(f, "Unexpected item - Got:{got}, Expected:{want}")
169             }
170             Self::SkCommError(e) => write!(f, "secretkeeper_comm error: {e:?}"),
171         }
172     }
173 }
174 
175 impl From<authgraph_core::error::Error> for Error {
from(e: authgraph_core::error::Error) -> Self176     fn from(e: authgraph_core::error::Error) -> Self {
177         Self::AuthgraphError(e)
178     }
179 }
180 
181 impl From<binder::Status> for Error {
from(s: binder::Status) -> Self182     fn from(s: binder::Status) -> Self {
183         Self::BinderStatus(s)
184     }
185 }
186 
187 impl From<coset::CoseError> for Error {
from(e: coset::CoseError) -> Self188     fn from(e: coset::CoseError) -> Self {
189         Self::CoseError(e)
190     }
191 }
192 
193 impl From<secretkeeper_comm::data_types::error::Error> for Error {
from(e: secretkeeper_comm::data_types::error::Error) -> Self194     fn from(e: secretkeeper_comm::data_types::error::Error) -> Self {
195         Self::SkCommError(e)
196     }
197 }
198 
199 /// Perform AuthGraph key exchange, returning the session keys and session ID.
authgraph_key_exchange( sk: binder::Strong<dyn ISecretkeeper>, ag_dev: Rc<RefCell<AgDevice>>, ) -> Result<([key::AesKey; 2], Vec<u8>), Error>200 fn authgraph_key_exchange(
201     sk: binder::Strong<dyn ISecretkeeper>,
202     ag_dev: Rc<RefCell<AgDevice>>,
203 ) -> Result<([key::AesKey; 2], Vec<u8>), Error> {
204     let sink = sk.getAuthGraphKe()?;
205     let mut source = ke::AuthGraphParticipant::new(
206         boring::crypto_trait_impls(),
207         ag_dev,
208         1, // Each SkSession supports only 1 open Authgraph session.
209     )?;
210     key_exchange(&mut source, sink)
211 }
212 
213 /// Perform AuthGraph key exchange with the provided sink and local source implementation.
214 /// Return the agreed AES keys in plaintext, together with the session ID.
key_exchange( local_source: &mut ke::AuthGraphParticipant, sink: binder::Strong<dyn IAuthGraphKeyExchange>, ) -> Result<([key::AesKey; 2], Vec<u8>), Error>215 fn key_exchange(
216     local_source: &mut ke::AuthGraphParticipant,
217     sink: binder::Strong<dyn IAuthGraphKeyExchange>,
218 ) -> Result<([key::AesKey; 2], Vec<u8>), Error> {
219     // Step 1: create an ephemeral ECDH key at the (local) source.
220     let source_init_info = local_source.create()?;
221 
222     // Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
223     let init_result = sink.init(
224         &build_plain_pub_key(&source_init_info.ke_key.pub_key)?,
225         &vec_to_identity(&source_init_info.identity),
226         &source_init_info.nonce,
227         source_init_info.version,
228     )?;
229     let sink_init_info = init_result.sessionInitiationInfo;
230     let sink_pub_key = extract_plain_pub_key(&sink_init_info.key.pubKey)?;
231     let sink_info = init_result.sessionInfo;
232 
233     // Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
234     // can calculate the same pair of symmetric keys.
235     let source_info = local_source.finish(
236         &sink_pub_key.plainPubKey,
237         &sink_init_info.identity.identity,
238         &sink_info.signature.signature,
239         &sink_init_info.nonce,
240         sink_init_info.version,
241         source_init_info.ke_key,
242     )?;
243 
244     // Step 4: pass the (local) source's session ID signature back to the sink, so it can check it
245     // and update the symmetric keys so they're marked as authentication complete.
246     let _sink_arcs = sink.authenticationComplete(
247         &vec_to_signature(&source_info.session_id_signature),
248         &sink_info.sharedKeys,
249     )?;
250 
251     // Decrypt and return the session keys.
252     let decrypted_shared_keys_array = local_source
253         .decipher_shared_keys_from_arcs(&source_info.shared_keys)?
254         .try_into()
255         .map_err(|_| Error::UnexpectedItem("Array", "Array of size 2"))?;
256 
257     Ok((decrypted_shared_keys_array, source_info.session_id))
258 }
259 
build_plain_pub_key(pub_key: &Option<Vec<u8>>) -> Result<PubKey, Error>260 fn build_plain_pub_key(pub_key: &Option<Vec<u8>>) -> Result<PubKey, Error> {
261     Ok(PubKey::PlainKey(PlainPubKey {
262         plainPubKey: pub_key.clone().ok_or(Error::UnexpectedItem("None", "Some bytes"))?,
263     }))
264 }
265 
extract_plain_pub_key(pub_key: &Option<PubKey>) -> Result<&PlainPubKey, Error>266 fn extract_plain_pub_key(pub_key: &Option<PubKey>) -> Result<&PlainPubKey, Error> {
267     match pub_key {
268         Some(PubKey::PlainKey(pub_key)) => Ok(pub_key),
269         Some(PubKey::SignedKey(_)) => Err(Error::UnexpectedItem("Signed Key", "Public Key")),
270         None => Err(Error::UnexpectedItem("No key", "Public key")),
271     }
272 }
273 
vec_to_identity(data: &[u8]) -> Identity274 fn vec_to_identity(data: &[u8]) -> Identity {
275     Identity { identity: data.to_vec() }
276 }
277 
vec_to_signature(data: &[u8]) -> SessionIdSignature278 fn vec_to_signature(data: &[u8]) -> SessionIdSignature {
279     SessionIdSignature { signature: data.to_vec() }
280 }
281 
282 #[cfg(test)]
283 rdroidtest::test_main!();
284