• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
22 use crate::authgraph_dev::AgDevice;
23 
24 use authgraph_boringssl as boring;
25 use authgraph_core::keyexchange as ke;
26 use authgraph_core::key;
27 use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper
28     ::ISecretkeeper::ISecretkeeper;
29 use android_hardware_security_authgraph::aidl::android::hardware::security::authgraph::{
30     IAuthGraphKeyExchange::IAuthGraphKeyExchange, PlainPubKey::PlainPubKey, PubKey::PubKey,
31     SessionIdSignature::SessionIdSignature, Identity::Identity,
32 };
33 use coset::{CoseKey, CborSerializable, CoseEncrypt0};
34 use explicitkeydice::OwnedDiceArtifactsWithExplicitKey;
35 use secretkeeper_core::cipher;
36 use secretkeeper_comm::data_types::SeqNum;
37 use secretkeeper_comm::wire::ApiError;
38 use std::cell::RefCell;
39 use std::fmt;
40 use std::rc::Rc;
41 
42 /// A Secretkeeper session that can be used by client, this encapsulates the AuthGraph Key exchange
43 /// session as well as the encryption/decryption of request/response to/from Secretkeeper.
44 pub struct SkSession {
45     sk: binder::Strong<dyn ISecretkeeper>,
46     encryption_key: key::AesKey,
47     decryption_key: key::AesKey,
48     session_id: Vec<u8>,
49     // We allow seq numbers to be 0 to u64::MAX-1, increment beyond that fails
50     // Sequence number for next outgoing message encryption.
51     seq_num_outgoing: SeqNum,
52     // Sequence number for decrypting the next incoming message.
53     seq_num_incoming: SeqNum,
54     // The local AuthGraph Device impl - encapsulates the local identity etc.
55     authgraph_participant: AgDevice,
56 }
57 
58 impl SkSession {
59     /// Create a new Secretkeeper session. This triggers an AuthGraphKeyExchange protocol with a
60     /// local `source` and remote `sink`.
61     ///
62     /// # Arguments
63     /// `sk`: Secretkeeper instance
64     ///
65     /// `dice`: DiceArtifacts of the caller (i.e, Sk client)
66     ///
67     /// `expected_sk_key`: Expected Identity of Secretkeeper. If set, the claimed peer identity is
68     /// 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>69     pub fn new(
70         sk: binder::Strong<dyn ISecretkeeper>,
71         dice: &OwnedDiceArtifactsWithExplicitKey,
72         expected_sk_key: Option<CoseKey>,
73     ) -> Result<Self, Error> {
74         let authgraph_participant = AgDevice::new(dice, expected_sk_key)?;
75         let ([encryption_key, decryption_key], session_id) = authgraph_key_exchange(
76             sk.clone(),
77             Rc::new(RefCell::new(authgraph_participant.clone())),
78         )?;
79         Ok(Self {
80             sk,
81             encryption_key,
82             decryption_key,
83             session_id,
84             seq_num_outgoing: SeqNum::new(),
85             seq_num_incoming: SeqNum::new(),
86             authgraph_participant,
87         })
88     }
89 
90     /// Refresh the existing Secretkeeper session. This reuses the client
91     /// identity & per_boot_key, does AuthGraphKeyExchange resetting the keys!
refresh(&mut self) -> Result<(), Error>92     pub fn refresh(&mut self) -> Result<(), Error> {
93         let ([encryption_key, decryption_key], session_id) = authgraph_key_exchange(
94             self.sk.clone(),
95             Rc::new(RefCell::new(self.authgraph_participant.clone())),
96         )?;
97         self.encryption_key = encryption_key;
98         self.decryption_key = decryption_key;
99         self.session_id = session_id;
100         self.seq_num_outgoing = SeqNum::new();
101         self.seq_num_incoming = SeqNum::new();
102         Ok(())
103     }
104 
105     /// Wrapper around `ISecretkeeper::processSecretManagementRequest`. This additionally handles
106     /// encryption and decryption.
secret_management_request(&mut self, req_data: &[u8]) -> Result<Vec<u8>, Error>107     pub fn secret_management_request(&mut self, req_data: &[u8]) -> Result<Vec<u8>, Error> {
108         let aes_gcm = boring::BoringAes;
109         let rng = boring::BoringRng;
110         let req_aad = self.seq_num_outgoing.get_then_increment()?;
111         let request_bytes = cipher::encrypt_message(
112             &aes_gcm,
113             &rng,
114             &self.encryption_key,
115             &self.session_id,
116             req_data,
117             &req_aad,
118         )
119         .map_err(Error::CipherError)?;
120 
121         let response_bytes = self.sk.processSecretManagementRequest(&request_bytes)?;
122 
123         let response_encrypt0 = CoseEncrypt0::from_slice(&response_bytes)?;
124         let expected_res_aad = self.seq_num_incoming.get_then_increment()?;
125         cipher::decrypt_message(
126             &aes_gcm,
127             &self.decryption_key,
128             &response_encrypt0,
129             &expected_res_aad,
130         )
131         .map_err(Error::CipherError)
132     }
133 
134     /// Get the encryption key corresponding to the session. Note on usage: This (along with other
135     /// getters [`decryption_key()`] & [`session_id()`]) can be used for custom encrypting requests
136     /// (for ex, with different aad, instead of using [`secret_management_request`] method.
137     /// In that case, seq_num_outgoing & seq_num_incoming will be out of sync. Recommended use for
138     /// testing only.
encryption_key(&self) -> &key::AesKey139     pub fn encryption_key(&self) -> &key::AesKey {
140         &self.encryption_key
141     }
142 
143     /// Get the decryption key corresponding to the session.
decryption_key(&self) -> &key::AesKey144     pub fn decryption_key(&self) -> &key::AesKey {
145         &self.decryption_key
146     }
147 
148     /// Get the session_id.
session_id(&self) -> &[u8]149     pub fn session_id(&self) -> &[u8] {
150         &self.session_id
151     }
152 }
153 
154 impl fmt::Debug for SkSession {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result155     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
156         f.debug_struct("SkSession").field("session_id", &hex::encode(&self.session_id)).finish()
157     }
158 }
159 
160 /// Errors thrown by this SkSession.
161 #[derive(Debug)]
162 pub enum Error {
163     /// These are server errors : thrown from remote instance (of Authgraph or Secretkeeper)
164     BinderStatus(binder::Status),
165     /// These are errors thrown from (local) source Authgraph instance.
166     AuthgraphError(authgraph_core::error::Error),
167     /// Error originating while encryption/decryption of packets (at source).
168     CipherError(ApiError),
169     /// Errors originating in the coset library.
170     CoseError(coset::CoseError),
171     /// Unexpected item encountered (got, want).
172     UnexpectedItem(&'static str, &'static str),
173     /// The set of errors from secretkeeper_comm library.
174     SkCommError(secretkeeper_comm::data_types::error::Error),
175 }
176 
177 impl std::error::Error for Error {}
178 
179 impl std::fmt::Display for Error {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result180     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
181         match self {
182             Self::BinderStatus(e) => write!(f, "Binder error {e:?}"),
183             Self::AuthgraphError(e) => write!(f, "Local Authgraph instance error {e:?}"),
184             Self::CipherError(e) => write!(f, "Error in encryption/decryption of packets {e:?}"),
185             Self::CoseError(e) => write!(f, "Errors originating in the coset library {e:?}"),
186             Self::UnexpectedItem(got, want) => {
187                 write!(f, "Unexpected item - Got:{got}, Expected:{want}")
188             }
189             Self::SkCommError(e) => write!(f, "secretkeeper_comm error: {e:?}"),
190         }
191     }
192 }
193 
194 impl From<authgraph_core::error::Error> for Error {
from(e: authgraph_core::error::Error) -> Self195     fn from(e: authgraph_core::error::Error) -> Self {
196         Self::AuthgraphError(e)
197     }
198 }
199 
200 impl From<binder::Status> for Error {
from(s: binder::Status) -> Self201     fn from(s: binder::Status) -> Self {
202         Self::BinderStatus(s)
203     }
204 }
205 
206 impl From<coset::CoseError> for Error {
from(e: coset::CoseError) -> Self207     fn from(e: coset::CoseError) -> Self {
208         Self::CoseError(e)
209     }
210 }
211 
212 impl From<secretkeeper_comm::data_types::error::Error> for Error {
from(e: secretkeeper_comm::data_types::error::Error) -> Self213     fn from(e: secretkeeper_comm::data_types::error::Error) -> Self {
214         Self::SkCommError(e)
215     }
216 }
217 
218 /// 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>219 fn authgraph_key_exchange(
220     sk: binder::Strong<dyn ISecretkeeper>,
221     ag_dev: Rc<RefCell<AgDevice>>,
222 ) -> Result<([key::AesKey; 2], Vec<u8>), Error> {
223     let sink = sk.getAuthGraphKe()?;
224     let mut source = ke::AuthGraphParticipant::new(
225         boring::crypto_trait_impls(),
226         ag_dev,
227         1, // Each SkSession supports only 1 open Authgraph session.
228     )?;
229     key_exchange(&mut source, sink)
230 }
231 
232 /// Perform AuthGraph key exchange with the provided sink and local source implementation.
233 /// 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>234 fn key_exchange(
235     local_source: &mut ke::AuthGraphParticipant,
236     sink: binder::Strong<dyn IAuthGraphKeyExchange>,
237 ) -> Result<([key::AesKey; 2], Vec<u8>), Error> {
238     // Step 1: create an ephemeral ECDH key at the (local) source.
239     let source_init_info = local_source.create()?;
240 
241     // Step 2: pass the source's ECDH public key and other session info to the (remote) sink.
242     let init_result = sink.init(
243         &build_plain_pub_key(&source_init_info.ke_key.pub_key)?,
244         &vec_to_identity(&source_init_info.identity),
245         &source_init_info.nonce,
246         source_init_info.version,
247     )?;
248     let sink_init_info = init_result.sessionInitiationInfo;
249     let sink_pub_key = extract_plain_pub_key(&sink_init_info.key.pubKey)?;
250     let sink_info = init_result.sessionInfo;
251 
252     // Step 3: pass the sink's ECDH public key and other session info to the (local) source, so it
253     // can calculate the same pair of symmetric keys.
254     let source_info = local_source.finish(
255         &sink_pub_key.plainPubKey,
256         &sink_init_info.identity.identity,
257         &sink_info.signature.signature,
258         &sink_init_info.nonce,
259         sink_init_info.version,
260         source_init_info.ke_key,
261     )?;
262 
263     // Step 4: pass the (local) source's session ID signature back to the sink, so it can check it
264     // and update the symmetric keys so they're marked as authentication complete.
265     let _sink_arcs = sink.authenticationComplete(
266         &vec_to_signature(&source_info.session_id_signature),
267         &sink_info.sharedKeys,
268     )?;
269 
270     // Decrypt and return the session keys.
271     let decrypted_shared_keys_array = local_source
272         .decipher_shared_keys_from_arcs(&source_info.shared_keys)?
273         .try_into()
274         .map_err(|_| Error::UnexpectedItem("Array", "Array of size 2"))?;
275 
276     Ok((decrypted_shared_keys_array, source_info.session_id))
277 }
278 
build_plain_pub_key(pub_key: &Option<Vec<u8>>) -> Result<PubKey, Error>279 fn build_plain_pub_key(pub_key: &Option<Vec<u8>>) -> Result<PubKey, Error> {
280     Ok(PubKey::PlainKey(PlainPubKey {
281         plainPubKey: pub_key.clone().ok_or(Error::UnexpectedItem("None", "Some bytes"))?,
282     }))
283 }
284 
extract_plain_pub_key(pub_key: &Option<PubKey>) -> Result<&PlainPubKey, Error>285 fn extract_plain_pub_key(pub_key: &Option<PubKey>) -> Result<&PlainPubKey, Error> {
286     match pub_key {
287         Some(PubKey::PlainKey(pub_key)) => Ok(pub_key),
288         Some(PubKey::SignedKey(_)) => Err(Error::UnexpectedItem("Signed Key", "Public Key")),
289         None => Err(Error::UnexpectedItem("No key", "Public key")),
290     }
291 }
292 
vec_to_identity(data: &[u8]) -> Identity293 fn vec_to_identity(data: &[u8]) -> Identity {
294     Identity { identity: data.to_vec() }
295 }
296 
vec_to_signature(data: &[u8]) -> SessionIdSignature297 fn vec_to_signature(data: &[u8]) -> SessionIdSignature {
298     SessionIdSignature { signature: data.to_vec() }
299 }
300