xref: /aosp_15_r20/system/secretkeeper/core/src/ta.rs (revision 3f8e9d82f4020c68ad19a99fc5fdc1fc90b79379)
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //! Implementation of a Secretkeeper trusted application (TA).
18 
19 use crate::alloc::string::ToString;
20 use crate::cipher;
21 use crate::store::{KeyValueStore, PolicyGatedStorage};
22 use alloc::boxed::Box;
23 use alloc::collections::VecDeque;
24 use alloc::vec::Vec;
25 use authgraph_core::ag_err;
26 use authgraph_core::error::Error;
27 use authgraph_core::key::{
28     AesKey, CertChain, EcSignKey, Identity, IdentityVerificationDecision,
29     EXPLICIT_KEY_DICE_CERT_CHAIN_VERSION, IDENTITY_VERSION,
30 };
31 use authgraph_core::traits::{AesGcm, CryptoTraitImpl, Device, EcDsa, Rng, Sha256};
32 use authgraph_wire::{ErrorCode, SESSION_ID_LEN};
33 use coset::{iana, CborSerializable, CoseEncrypt0};
34 use log::{error, trace, warn};
35 use secretkeeper_comm::data_types::{
36     error::Error as SkInternalError,
37     error::SecretkeeperError,
38     packet::{RequestPacket, ResponsePacket},
39     request::Request,
40     request_response_impl::{
41         GetSecretRequest, GetSecretResponse, GetVersionRequest, GetVersionResponse, Opcode,
42         StoreSecretRequest, StoreSecretResponse,
43     },
44     response::Response,
45     Id, SeqNum,
46 };
47 use secretkeeper_comm::wire::{
48     AidlErrorCode, ApiError, PerformOpReq, PerformOpResponse, PerformOpSuccessRsp, SecretId,
49 };
50 
51 pub mod bootloader;
52 
53 /// Current Secretkeeper version.
54 const CURRENT_VERSION: u64 = 1;
55 
56 /// Default maximum number of live session keys.
57 const MAX_SESSIONS_DEFAULT: usize = 4;
58 
59 /// Macro to build an [`ApiError`] instance.
60 /// E.g. use: `aidl_err!(InternalError, "some {} format", arg)`.
61 #[macro_export]
62 macro_rules! aidl_err {
63     { $error_code:ident, $($arg:tt)+ } => {
64         ApiError {
65             err_code: AidlErrorCode::$error_code,
66             msg: alloc::format!("{}:{}: {}", file!(), line!(), format_args!($($arg)+))
67         }
68     };
69 }
70 
71 /// Secretkeeper trusted application instance.
72 pub struct SecretkeeperTa {
73     /// AES-GCM implementation.
74     aes_gcm: Box<dyn AesGcm>,
75 
76     /// RNG implementation.
77     rng: Box<dyn Rng>,
78 
79     /// AuthGraph per-boot-key.
80     per_boot_key: AesKey,
81 
82     /// The signing key corresponding to the leaf of the Secretkeeper identity DICE chain.
83     identity_sign_key: EcSignKey,
84 
85     /// Secretkeeper identity.
86     identity: Identity,
87 
88     /// Current sessions.
89     session_artifacts: VecDeque<SessionArtifacts>,
90 
91     /// Maximum number of current sessions.
92     max_sessions: usize,
93 
94     /// Storage of secrets (& sealing policy)
95     store: PolicyGatedStorage,
96 }
97 
98 impl SecretkeeperTa {
99     /// Create a TA instance using the provided trait implementations.
new( ag_impls: &mut CryptoTraitImpl, storage_impl: Box<dyn KeyValueStore>, identity_curve: iana::EllipticCurve, ) -> Result<Self, SkInternalError>100     pub fn new(
101         ag_impls: &mut CryptoTraitImpl,
102         storage_impl: Box<dyn KeyValueStore>,
103         identity_curve: iana::EllipticCurve,
104     ) -> Result<Self, SkInternalError> {
105         Self::new_with_session_limit(ag_impls, storage_impl, identity_curve, MAX_SESSIONS_DEFAULT)
106     }
107 
108     /// Create a TA instance using the provided trait implementations.
new_with_session_limit( ag_impls: &mut CryptoTraitImpl, storage_impl: Box<dyn KeyValueStore>, identity_curve: iana::EllipticCurve, max_sessions: usize, ) -> Result<Self, SkInternalError>109     pub fn new_with_session_limit(
110         ag_impls: &mut CryptoTraitImpl,
111         storage_impl: Box<dyn KeyValueStore>,
112         identity_curve: iana::EllipticCurve,
113         max_sessions: usize,
114     ) -> Result<Self, SkInternalError> {
115         // Create a per-boot-key for AuthGraph to use.
116         let aes_gcm = ag_impls.aes_gcm.box_clone();
117         let rng = ag_impls.rng.box_clone();
118         let per_boot_key = aes_gcm.generate_key(&mut *ag_impls.rng).map_err(|e| {
119             error!("Failed to generate per-boot key: {e:?}");
120             SkInternalError::UnexpectedError
121         })?;
122 
123         let (identity_sign_key, mut pub_key) =
124             ag_impls.ecdsa.generate_key(identity_curve).map_err(|e| {
125                 error!("Failed to generate {identity_curve:?} keypair: {e:?}");
126                 SkInternalError::UnexpectedError
127             })?;
128         pub_key.canonicalize_cose_key();
129         let identity = Identity {
130             version: IDENTITY_VERSION,
131             cert_chain: CertChain {
132                 version: EXPLICIT_KEY_DICE_CERT_CHAIN_VERSION,
133                 root_key: pub_key,
134                 dice_cert_chain: None,
135             },
136             policy: None,
137         };
138         let store = PolicyGatedStorage::init(storage_impl);
139 
140         Ok(Self {
141             aes_gcm,
142             rng,
143             per_boot_key,
144             identity_sign_key,
145             identity,
146             max_sessions,
147             session_artifacts: VecDeque::new(),
148             store,
149         })
150     }
151 
152     /// Process a single serialized request from the bootloader, returning a serialized response
153     /// (even on failure).
process_bootloader(&self, req_data: &[u8]) -> Vec<u8>154     pub fn process_bootloader(&self, req_data: &[u8]) -> Vec<u8> {
155         use bootloader as bl;
156         let req = match bl::Request::from_slice(req_data) {
157             Ok(req) => req,
158             Err(e) => {
159                 error!("Failed to deserialize bootloader request: {e:?}");
160                 return bl::Response::Error(bl::OpCode::Unknown, bl::ErrorCode::CborFailure)
161                     .into_vec();
162             }
163         };
164         let rsp = match req {
165             bl::Request::GetIdentityKey => {
166                 let cose_key = self.identity.cert_chain.root_key.clone().get_key();
167                 let cose_data = match cose_key.to_vec() {
168                     Ok(data) => data,
169                     Err(e) => {
170                         error!("Failed to serialize COSE key: {e:?}");
171                         return bl::Response::Error(
172                             bl::OpCode::GetIdentityKey,
173                             bl::ErrorCode::CborFailure,
174                         )
175                         .into_vec();
176                     }
177                 };
178                 bl::Response::IdentityKey(cose_data)
179             }
180         };
181         rsp.into_vec()
182     }
183 
184     /// Process a single serialized request, returning a serialized response (even on failure).
process(&mut self, req_data: &[u8]) -> Vec<u8>185     pub fn process(&mut self, req_data: &[u8]) -> Vec<u8> {
186         let (req_code, rsp) = match PerformOpReq::from_slice(req_data) {
187             Ok(req) => {
188                 trace!("-> TA: received request {:?}", req.code());
189                 (Some(req.code()), self.process_req(req))
190             }
191             Err(e) => {
192                 error!("failed to decode CBOR request: {:?}", e);
193                 (None, PerformOpResponse::Failure(aidl_err!(InternalError, "CBOR decode failure")))
194             }
195         };
196         trace!("<- TA: send response for {:?} rc {:?}", req_code, rsp.err_code());
197         rsp.to_vec().unwrap_or_else(|e| {
198             error!("failed to encode CBOR response: {:?}", e);
199             invalid_cbor_rsp_data().to_vec()
200         })
201     }
202 
203     /// Process a single request, returning a [`PerformOpResponse`].
process_req(&mut self, req: PerformOpReq) -> PerformOpResponse204     fn process_req(&mut self, req: PerformOpReq) -> PerformOpResponse {
205         let code = req.code();
206         let result = match req {
207             PerformOpReq::SecretManagement(encrypt0) => {
208                 self.secret_management(&encrypt0).map(PerformOpSuccessRsp::ProtectedResponse)
209             }
210             PerformOpReq::DeleteIds(ids) => {
211                 self.delete_ids(ids).map(|_| PerformOpSuccessRsp::Empty)
212             }
213             PerformOpReq::DeleteAll => self.delete_all().map(|_| PerformOpSuccessRsp::Empty),
214             PerformOpReq::GetSecretkeeperIdentity => {
215                 let Identity { cert_chain: CertChain { root_key, .. }, .. } = &self.identity;
216                 root_key
217                     .clone()
218                     .get_key()
219                     .to_vec()
220                     .map_err(|e| ApiError {
221                         err_code: AidlErrorCode::InternalError,
222                         msg: e.to_string(),
223                     })
224                     .map(PerformOpSuccessRsp::ProtectedResponse)
225             }
226         };
227         match result {
228             Ok(rsp) => PerformOpResponse::Success(rsp),
229             Err(err) => {
230                 warn!("failing {:?} request: {:?}", code, err);
231                 PerformOpResponse::Failure(err)
232             }
233         }
234     }
235 
delete_ids(&mut self, ids: Vec<SecretId>) -> Result<(), ApiError>236     fn delete_ids(&mut self, ids: Vec<SecretId>) -> Result<(), ApiError> {
237         for id in ids {
238             self.store
239                 .delete(&Id(id))
240                 .map_err(|e| aidl_err!(InternalError, "failed to delete id: {e:?}"))?;
241         }
242         Ok(())
243     }
244 
delete_all(&mut self) -> Result<(), ApiError>245     fn delete_all(&mut self) -> Result<(), ApiError> {
246         warn!("deleting all Secretkeeper secrets");
247         self.store.delete_all().map_err(|e| aidl_err!(InternalError, "failed to delete all: {e:?}"))
248     }
249 
250     // "SSL added and removed here :-)"
secret_management(&mut self, encrypt0: &[u8]) -> Result<Vec<u8>, ApiError>251     fn secret_management(&mut self, encrypt0: &[u8]) -> Result<Vec<u8>, ApiError> {
252         let encrypt0 = CoseEncrypt0::from_slice(encrypt0)
253             .map_err(|_e| aidl_err!(RequestMalformed, "malformed COSE_Encrypt0"))?;
254         let kid: &[u8; SESSION_ID_LEN] = key_id(&encrypt0)
255             .try_into()
256             .map_err(|e| aidl_err!(RequestMalformed, "session key of unexpected size: {e:?}"))?;
257         let peer_cert_chain = self.peer_cert_chain(kid)?;
258         let req = self.decrypt_request(&encrypt0, kid)?;
259         let result = self.process_inner(&req, &peer_cert_chain);
260 
261         // An inner failure still converts to a response message that gets encrypted.
262         let rsp_data = match result {
263             Ok(data) => data,
264             Err(e) => e
265                 .serialize_to_packet()
266                 .to_vec()
267                 .map_err(|_e| aidl_err!(InternalError, "failed to encode err rsp"))?,
268         };
269         self.encrypt_response(&rsp_data, kid)
270     }
271 
peer_cert_chain(&self, kid: &[u8; SESSION_ID_LEN]) -> Result<Vec<u8>, ApiError>272     fn peer_cert_chain(&self, kid: &[u8; SESSION_ID_LEN]) -> Result<Vec<u8>, ApiError> {
273         let cert_chain = self
274             .session_artifacts
275             .iter()
276             .find_map(|info| {
277                 if info.session_keys.session_id == *kid {
278                     Some(info.session_keys.peer_cert_chain.clone())
279                 } else {
280                     None
281                 }
282             })
283             .ok_or_else(|| aidl_err!(UnknownKeyId, "session info not found"))?;
284         Ok(cert_chain)
285     }
286 
process_inner( &mut self, req: &[u8], peer_cert_chain: &[u8], ) -> Result<Vec<u8>, SecretkeeperError>287     fn process_inner(
288         &mut self,
289         req: &[u8],
290         peer_cert_chain: &[u8],
291     ) -> Result<Vec<u8>, SecretkeeperError> {
292         let req_packet = RequestPacket::from_slice(req).map_err(|e| {
293             error!("Failed to get Request packet from bytes: {e:?}");
294             SecretkeeperError::RequestMalformed
295         })?;
296         let rsp_packet =
297             match req_packet.opcode().map_err(|_| SecretkeeperError::RequestMalformed)? {
298                 Opcode::GetVersion => Self::get_version(req_packet)?,
299                 Opcode::StoreSecret => self.store_secret(req_packet, peer_cert_chain)?,
300                 Opcode::GetSecret => self.get_secret(req_packet, peer_cert_chain)?,
301                 _ => panic!("Unknown operation.."),
302             };
303         rsp_packet.to_vec().map_err(|_| SecretkeeperError::UnexpectedServerError)
304     }
305 
get_version(req: RequestPacket) -> Result<ResponsePacket, SecretkeeperError>306     fn get_version(req: RequestPacket) -> Result<ResponsePacket, SecretkeeperError> {
307         // Deserialization really just verifies the structural integrity of the request such
308         // as args being empty.
309         let _req = GetVersionRequest::deserialize_from_packet(req)
310             .map_err(|_| SecretkeeperError::RequestMalformed)?;
311         let rsp = GetVersionResponse { version: CURRENT_VERSION };
312         Ok(rsp.serialize_to_packet())
313     }
314 
store_secret( &mut self, request: RequestPacket, peer_cert_chain: &[u8], ) -> Result<ResponsePacket, SecretkeeperError>315     fn store_secret(
316         &mut self,
317         request: RequestPacket,
318         peer_cert_chain: &[u8],
319     ) -> Result<ResponsePacket, SecretkeeperError> {
320         let request = StoreSecretRequest::deserialize_from_packet(request)
321             .map_err(|_| SecretkeeperError::RequestMalformed)?;
322         self.store.store(request.id, request.secret, request.sealing_policy, peer_cert_chain)?;
323         let response = StoreSecretResponse {};
324         Ok(response.serialize_to_packet())
325     }
326 
get_secret( &mut self, request: RequestPacket, peer_cert_chain: &[u8], ) -> Result<ResponsePacket, SecretkeeperError>327     fn get_secret(
328         &mut self,
329         request: RequestPacket,
330         peer_cert_chain: &[u8],
331     ) -> Result<ResponsePacket, SecretkeeperError> {
332         let request = GetSecretRequest::deserialize_from_packet(request)
333             .map_err(|_| SecretkeeperError::RequestMalformed)?;
334         let secret =
335             self.store.get(&request.id, peer_cert_chain, request.updated_sealing_policy)?;
336         let response = GetSecretResponse { secret };
337         Ok(response.serialize_to_packet())
338     }
339 
keys_for_session( &mut self, session_id: &[u8; SESSION_ID_LEN], ) -> Option<&mut SessionArtifacts>340     fn keys_for_session(
341         &mut self,
342         session_id: &[u8; SESSION_ID_LEN],
343     ) -> Option<&mut SessionArtifacts> {
344         self.session_artifacts.iter_mut().find(|info| info.session_keys.session_id == *session_id)
345     }
346 
decrypt_request( &mut self, encrypt0: &CoseEncrypt0, kid: &[u8; SESSION_ID_LEN], ) -> Result<Vec<u8>, ApiError>347     fn decrypt_request(
348         &mut self,
349         encrypt0: &CoseEncrypt0,
350         kid: &[u8; SESSION_ID_LEN],
351     ) -> Result<Vec<u8>, ApiError> {
352         let session_artifacts = self
353             .keys_for_session(kid)
354             .ok_or_else(|| aidl_err!(UnknownKeyId, "session info not found"))?;
355 
356         let seq_num_incoming =
357             session_artifacts.seq_num_incoming.get_then_increment().map_err(|e| {
358                 aidl_err!(InternalError, "Couldn't get the expected request seq_num: {e:?}")
359             })?;
360         let recv_key: &AesKey = &session_artifacts.session_keys.recv_key.clone();
361 
362         cipher::decrypt_message(self.aes_gcm.as_ref(), recv_key, encrypt0, &seq_num_incoming)
363     }
364 
encrypt_response( &mut self, rsp: &[u8], kid: &[u8; SESSION_ID_LEN], ) -> Result<Vec<u8>, ApiError>365     fn encrypt_response(
366         &mut self,
367         rsp: &[u8],
368         kid: &[u8; SESSION_ID_LEN],
369     ) -> Result<Vec<u8>, ApiError> {
370         let session_artifacts = self
371             .keys_for_session(kid)
372             .ok_or_else(|| aidl_err!(UnknownKeyId, "session info not found"))?;
373         let seq_num_outgoing = session_artifacts
374             .seq_num_outgoing
375             .get_then_increment()
376             .map_err(|e| aidl_err!(InternalError, "Couldn't get a seq number: {e:?}"))?;
377         let send_key: &AesKey = &session_artifacts.session_keys.send_key.clone();
378         cipher::encrypt_message(&*self.aes_gcm, &*self.rng, send_key, kid, rsp, &seq_num_outgoing)
379     }
380 }
381 
382 impl Device for SecretkeeperTa {
get_or_create_per_boot_key(&self, _: &dyn AesGcm, _: &mut dyn Rng) -> Result<AesKey, Error>383     fn get_or_create_per_boot_key(&self, _: &dyn AesGcm, _: &mut dyn Rng) -> Result<AesKey, Error> {
384         self.get_per_boot_key()
385     }
get_per_boot_key(&self) -> Result<AesKey, Error>386     fn get_per_boot_key(&self) -> Result<AesKey, Error> {
387         Ok(self.per_boot_key.clone())
388     }
get_identity(&self) -> Result<(Option<EcSignKey>, Identity), Error>389     fn get_identity(&self) -> Result<(Option<EcSignKey>, Identity), Error> {
390         Ok((Some(self.identity_sign_key.clone()), self.identity.clone()))
391     }
get_cose_sign_algorithm(&self) -> Result<iana::Algorithm, Error>392     fn get_cose_sign_algorithm(&self) -> Result<iana::Algorithm, Error> {
393         match &self.identity_sign_key {
394             EcSignKey::Ed25519(_) => Ok(iana::Algorithm::EdDSA),
395             EcSignKey::P256(_) => Ok(iana::Algorithm::ES256),
396             EcSignKey::P384(_) => Ok(iana::Algorithm::ES384),
397         }
398     }
399 
sign_data(&self, _ecdsa: &dyn EcDsa, _data: &[u8]) -> Result<Vec<u8>, Error>400     fn sign_data(&self, _ecdsa: &dyn EcDsa, _data: &[u8]) -> Result<Vec<u8>, Error> {
401         // `get_identity()` returns a key, so signing should be handled elsewhere.
402         Err(ag_err!(Unimplemented, "unexpected signing request"))
403     }
404 
evaluate_identity( &self, _curr: &Identity, _prev: &Identity, ) -> Result<IdentityVerificationDecision, Error>405     fn evaluate_identity(
406         &self,
407         _curr: &Identity,
408         _prev: &Identity,
409     ) -> Result<IdentityVerificationDecision, Error> {
410         Err(ag_err!(Unimplemented, "not yet required"))
411     }
412 
record_shared_sessions( &mut self, peer_identity: &Identity, session_id: &[u8; 32], shared_keys: &[Vec<u8>; 2], _sha256: &dyn Sha256, ) -> Result<(), Error>413     fn record_shared_sessions(
414         &mut self,
415         peer_identity: &Identity,
416         session_id: &[u8; 32],
417         shared_keys: &[Vec<u8>; 2],
418         _sha256: &dyn Sha256,
419     ) -> Result<(), Error> {
420         if self.session_artifacts.len() >= self.max_sessions {
421             warn!("Dropping oldest session key");
422             self.session_artifacts.pop_front();
423         }
424         let send_key =
425             authgraph_core::arc::decipher_arc(&self.per_boot_key, &shared_keys[0], &*self.aes_gcm)?;
426         let recv_key =
427             authgraph_core::arc::decipher_arc(&self.per_boot_key, &shared_keys[1], &*self.aes_gcm)?;
428         let peer_cert_chain = peer_identity
429             .cert_chain
430             .clone()
431             .to_vec()
432             .map_err(|e| ag_err!(InternalError, "Failed to encode peer's cert chain: {e:?}"))?;
433 
434         // We assume that the session ID is unique and not already present in `session_keys`.
435         self.session_artifacts.push_back(SessionArtifacts {
436             session_keys: AgSessionKeys {
437                 peer_cert_chain,
438                 session_id: *session_id,
439                 send_key: send_key.payload.try_into()?,
440                 recv_key: recv_key.payload.try_into()?,
441             },
442             seq_num_outgoing: SeqNum::new(),
443             seq_num_incoming: SeqNum::new(),
444         });
445         Ok(())
446     }
447 
validate_shared_sessions( &self, _peer_identity: &Identity, _session_id: &[u8; 32], _shared_keys: &[Vec<u8>], _sha256: &dyn Sha256, ) -> Result<(), Error>448     fn validate_shared_sessions(
449         &self,
450         _peer_identity: &Identity,
451         _session_id: &[u8; 32],
452         _shared_keys: &[Vec<u8>],
453         _sha256: &dyn Sha256,
454     ) -> Result<(), Error> {
455         // Secretkeeper does not need to validate shared session after successful Key Exchange.
456         Ok(())
457     }
458 }
459 
key_id(encrypted_packet: &CoseEncrypt0) -> &[u8]460 fn key_id(encrypted_packet: &CoseEncrypt0) -> &[u8] {
461     &encrypted_packet.protected.header.key_id
462 }
463 
464 // In addition to `session_keys` (received from authgraph key exchange protocol), Secretkeeper
465 // session maintains `sequence_numbers`. These change within session (for each message).
466 // Avoid cloning!
467 struct SessionArtifacts {
468     session_keys: AgSessionKeys,
469     // Sequence number to be used in next outgoing message encryption.
470     seq_num_outgoing: SeqNum,
471     // Sequence number to be used for decrypting the next incoming message.
472     seq_num_incoming: SeqNum,
473 }
474 
475 struct AgSessionKeys {
476     peer_cert_chain: Vec<u8>,
477     session_id: [u8; 32],
478     send_key: AesKey,
479     recv_key: AesKey,
480 }
481 
482 /// Hand-encoded [`PerformOpResponse`] data for [`AidlErrorCode::InternalError`].
483 /// Does not perform CBOR serialization (and so is suitable for error reporting if/when
484 /// CBOR serialization fails).
invalid_cbor_rsp_data() -> [u8; 3]485 fn invalid_cbor_rsp_data() -> [u8; 3] {
486     [
487         0x82, // 2-arr
488         0x02, // int, value 2
489         0x60, // 0-tstr
490     ]
491 }
492 
493 #[cfg(test)]
494 mod tests {
495     use super::*;
496     use secretkeeper_comm::wire::{AidlErrorCode, ApiError, PerformOpResponse};
497 
498     #[test]
test_invalid_data()499     fn test_invalid_data() {
500         // Cross-check that the hand-encoded invalid CBOR data matches an auto-encoded equivalent.
501         let rsp = PerformOpResponse::Failure(ApiError {
502             err_code: AidlErrorCode::InternalError,
503             msg: alloc::string::String::new(),
504         });
505         let rsp_data = rsp.to_vec().unwrap();
506         assert_eq!(rsp_data, invalid_cbor_rsp_data());
507     }
508 }
509