1 // Copyright 2023 Google LLC
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 ////////////////////////////////////////////////////////////////////////////////
16 
17 //! Authenticated Key Exchange (AKE) related operations. AKE is executed between two parties P1
18 //! (source) and P2 (sink).
19 use crate::{
20     ag_err, arc,
21     error::Error,
22     key::{
23         check_cose_key_params, AesKey, EcExchangeKey, EcExchangeKeyPriv, EcExchangeKeyPub,
24         EcSignKey, EcVerifyKey, EcdhSecret, HmacKey, Identity, Key, Nonce16, PseudoRandKey,
25         SaltInput, SessionIdInput, AES_256_KEY_LEN, SHA_256_LEN,
26     },
27     traits::{CryptoTraitImpl, Device, EcDh, Hkdf, Sha256},
28     try_to_vec, FallibleAllocExt,
29 };
30 use alloc::collections::VecDeque;
31 use alloc::rc::Rc;
32 use alloc::vec::Vec;
33 use authgraph_wire as wire;
34 use core::cell::RefCell;
35 use core::mem::take;
36 use coset::{
37     cbor::value::Value, iana, AsCborValue, CborSerializable, CoseKey, CoseSign1, CoseSign1Builder,
38     HeaderBuilder, Label,
39 };
40 use log::info;
41 use wire::{ErrorCode, SESSION_ID_LEN};
42 
43 pub use wire::{KeInitResult, SessionInfo, SessionInitiationInfo};
44 
45 /// Context for deriving the first shared encryption key
46 pub const CONTEXT_KE_ENCRYPTION_KEY_1: &[u8] = b"KE_ENCRYPTION_KEY_SOURCE_TO_SINK";
47 /// Context for deriving the second shared encryption key
48 pub const CONTEXT_KE_ENCRYPTION_KEY_2: &[u8] = b"KE_ENCRYPTION_KEY_SINK_TO_SOURCE";
49 /// Context for deriving the shared HMAC key
50 pub const CONTEXT_KE_HMAC_KEY: &[u8] = b"KE_HMAC_KEY";
51 /// Default limit for opened sessions for either source or sink operationss
52 pub const MAX_OPENED_SESSIONS: usize = 16;
53 
54 /// Enum defining the roles played by the two AuthGraph participants
55 #[derive(Clone, Copy)]
56 pub enum Role {
57     /// AuthGraph source
58     Source = 1,
59     /// AuthGraph sink
60     Sink = 2,
61 }
62 
63 /// Encapsulation of an AuthGraph Source
64 pub struct AuthGraphParticipant {
65     crypto: CryptoTraitImpl,
66     device: Rc<RefCell<dyn Device>>,
67     opened_ke_sessions: OpenedSessions,
68     opened_shared_sessions: OpenedSessions,
69 }
70 
71 // Session identifier is the computation of HMAC over the concatenation of the nonces of source
72 // and sink with the HMAC key derived from the shared secret computed via the key exchange protocol.
73 type SessionIdentifier = [u8; SESSION_ID_LEN];
74 
75 // Session digest is computed as the SHA-256 digest of the concatenation of the peer identity and
76 // the session identifier
77 type SessionDigest = [u8; SHA_256_LEN];
78 
79 /// Data structure to hold the information about opened sessions during key exchange
80 struct OpenedSessions {
81     capacity: usize,
82     sessions: VecDeque<SessionDigest>,
83 }
84 
85 impl OpenedSessions {
new(max_num_sessions: usize) -> Result<Self, Error>86     fn new(max_num_sessions: usize) -> Result<Self, Error> {
87         let mut sessions = VecDeque::new();
88         sessions.try_reserve(max_num_sessions)?;
89         Ok(OpenedSessions { capacity: max_num_sessions, sessions })
90     }
91 
add(&mut self, opened_session: SessionDigest)92     fn add(&mut self, opened_session: SessionDigest) {
93         if self.sessions.len() == self.capacity {
94             info!("Max number of opened sessions reached. Removing the oldest session.");
95             self.sessions.pop_front();
96         }
97         self.sessions.push_back(opened_session);
98     }
99 
100     // Remove a tracked session; return `InternalError`` if the provided session is not tracked.
remove(&mut self, opened_session: SessionDigest) -> Result<(), Error>101     fn remove(&mut self, opened_session: SessionDigest) -> Result<(), Error> {
102         if self.sessions.contains(&opened_session) {
103             self.sessions.retain(|&session| session != opened_session);
104             Ok(())
105         } else {
106             Err(ag_err!(InternalError, "session not found"))
107         }
108     }
109 }
110 
111 impl AuthGraphParticipant {
112     /// Creates an instance of AuthGraphParticipant
new( crypto: CryptoTraitImpl, device: Rc<RefCell<dyn Device>>, max_num_sessions: usize, ) -> Result<Self, Error>113     pub fn new(
114         crypto: CryptoTraitImpl,
115         device: Rc<RefCell<dyn Device>>,
116         max_num_sessions: usize,
117     ) -> Result<Self, Error> {
118         Ok(AuthGraphParticipant {
119             crypto,
120             device,
121             opened_ke_sessions: OpenedSessions::new(max_num_sessions)?,
122             opened_shared_sessions: OpenedSessions::new(max_num_sessions)?,
123         })
124     }
125 
126     /// First step in the key exchange protocol.
create(&mut self) -> Result<SessionInitiationInfo, Error>127     pub fn create(&mut self) -> Result<SessionInitiationInfo, Error> {
128         // Create an EC key for ECDH
129         let EcExchangeKey { pub_key: pub_key_for_ecdh, priv_key: mut priv_key_for_ecdh } =
130             self.crypto.ecdh.generate_key()?;
131         // Create a nonce for key agreement
132         let nonce_for_ke = Nonce16::new(&*self.crypto.rng);
133 
134         let pbk = self
135             .device
136             .borrow()
137             .get_or_create_per_boot_key(&*self.crypto.aes_gcm, &mut *self.crypto.rng)?;
138         let mut protected_headers = Vec::<(Label, Value)>::new();
139         protected_headers
140             .try_push((arc::KE_NONCE, Value::Bytes(nonce_for_ke.0.clone().to_vec())))?;
141         let priv_key_arc = arc::create_arc(
142             &pbk,
143             arc::ArcContent {
144                 payload: arc::ArcPayload(take(&mut priv_key_for_ecdh.0)),
145                 protected_headers,
146                 ..Default::default()
147             },
148             &*self.crypto.aes_gcm,
149             &mut *self.crypto.rng,
150         )?;
151         let (_sign_key, identity) = self.device.borrow().get_identity()?;
152         // Validate the identity returned from the trait implementation during the first time it is
153         // retrieved from the AuthGraphParticipant.
154         identity.validate(&*self.crypto.ecdsa)?;
155         let ke_key =
156             Key { pub_key: Some(pub_key_for_ecdh.0.to_vec()?), arc_from_pbk: Some(priv_key_arc) };
157         let ke_digest = compute_ke_key_digest(&ke_key, &*self.crypto.sha256)?;
158         self.opened_ke_sessions.add(ke_digest);
159         Ok(SessionInitiationInfo {
160             ke_key,
161             identity: identity.to_vec()?,
162             nonce: nonce_for_ke.0.to_vec(),
163             version: self.get_version(),
164         })
165     }
166 
167     /// Second step in the key exchange protocol.
init( &mut self, peer_key: &[u8], peer_id: &[u8], peer_nonce: &[u8], peer_version: i32, ) -> Result<KeInitResult, Error>168     pub fn init(
169         &mut self,
170         peer_key: &[u8],
171         peer_id: &[u8],
172         peer_nonce: &[u8],
173         peer_version: i32,
174     ) -> Result<KeInitResult, Error> {
175         if self.device.borrow().get_negotiated_version(peer_version) > peer_version {
176             return Err(ag_err!(InternalError, "protocol version is greater than peer's version"));
177         }
178         let key_for_ecdh = self.crypto.ecdh.generate_key()?;
179         let own_nonce = Nonce16::new(&*self.crypto.rng);
180 
181         let (peer_pub_key, peer_identity, peer_nonce) =
182             decode_peer_info(peer_key, peer_id, peer_nonce)?;
183 
184         let ecdh_secret =
185             compute_shared_secret(&*self.crypto.ecdh, &key_for_ecdh.priv_key, &peer_pub_key)?;
186         let (sign_key, own_identity) = self.device.borrow().get_identity()?;
187         // Validate the identity returned from the trait implementation during the first time it is
188         // retrieved from the AuthGraphParticipant.
189         own_identity.validate(&*self.crypto.ecdsa)?;
190         let salt_input = SaltInput {
191             source_version: peer_version,
192             sink_ke_pub_key: key_for_ecdh.pub_key.clone(),
193             source_ke_pub_key: peer_pub_key,
194             sink_ke_nonce: own_nonce.clone(),
195             source_ke_nonce: peer_nonce.clone(),
196             sink_cert_chain: own_identity.cert_chain.clone(),
197             source_cert_chain: peer_identity.cert_chain.clone(),
198         };
199 
200         let salt = compute_salt(salt_input, &*self.crypto.sha256)?;
201         let (in_encrypt_key, out_encrypt_key, hmac_key) =
202             derive_shared_keys(&ecdh_secret, &salt, Role::Sink, &*self.crypto.hkdf)?;
203 
204         let (session_id, signature) = self.compute_sign_session_id(
205             SessionIdInput { sink_ke_nonce: own_nonce.clone(), source_ke_nonce: peer_nonce },
206             HmacKey(hmac_key.0),
207             sign_key,
208         )?;
209 
210         // create two arcs encrypting the two shared encrypting keys with the per-boot-key
211         let shared_keys = self.create_shared_key_arcs(
212             own_identity.clone(),
213             peer_identity.clone(),
214             AesKey(in_encrypt_key.0),
215             AesKey(out_encrypt_key.0),
216             &session_id,
217             arc::AuthenticationCompleted(false),
218         )?;
219         let session_digest =
220             compute_session_digest(&peer_identity, &session_id, &*self.crypto.sha256)?;
221         self.opened_shared_sessions.add(session_digest);
222         Ok(KeInitResult {
223             session_init_info: SessionInitiationInfo {
224                 ke_key: Key { pub_key: Some(key_for_ecdh.pub_key.0.to_vec()?), arc_from_pbk: None },
225                 identity: own_identity.to_vec()?,
226                 nonce: own_nonce.0.to_vec(),
227                 version: self.device.borrow().get_negotiated_version(peer_version),
228             },
229             session_info: SessionInfo {
230                 shared_keys,
231                 session_id: session_id.to_vec(),
232                 session_id_signature: signature,
233             },
234         })
235     }
236 
237     /// Third step in the key exchange protocol.
finish( &mut self, peer_key: &[u8], peer_id: &[u8], peer_sig: &[u8], peer_nonce: &[u8], peer_version: i32, own_ke_key: Key, ) -> Result<SessionInfo, Error>238     pub fn finish(
239         &mut self,
240         peer_key: &[u8],
241         peer_id: &[u8],
242         peer_sig: &[u8],
243         peer_nonce: &[u8],
244         peer_version: i32,
245         own_ke_key: Key,
246     ) -> Result<SessionInfo, Error> {
247         let ke_digest = compute_ke_key_digest(&own_ke_key, &*self.crypto.sha256)?;
248         self.opened_ke_sessions
249             .remove(ke_digest)
250             .map_err(|_| ag_err!(InvalidKeKey, "finish is called on invalid session"))?;
251         if self.get_version() < peer_version {
252             return Err(ag_err!(
253                 IncompatibleProtocolVersion,
254                 "peer's protocol version is incompatible"
255             ));
256         }
257         let pbk = self.per_boot_key()?;
258         let mut own_ke_key_arc_content = arc::decipher_arc(
259             &pbk,
260             &own_ke_key
261                 .arc_from_pbk
262                 .ok_or(ag_err!(InvalidPrivKeyArcInKey, "missing priv key arc"))?,
263             &*self.crypto.aes_gcm,
264         )
265         .map_err(|e| ag_err!(InvalidPrivKeyArcInKey, "failed to decrypt arc: {e:?}"))?;
266 
267         let own_ke_nonce = extract_nonce(&own_ke_key_arc_content.protected_headers)?;
268 
269         let (peer_pub_key, peer_identity, peer_nonce) =
270             decode_peer_info(peer_key, peer_id, peer_nonce)?;
271 
272         let ecdh_secret = compute_shared_secret(
273             &*self.crypto.ecdh,
274             &EcExchangeKeyPriv(take(&mut own_ke_key_arc_content.payload.0)),
275             &peer_pub_key,
276         )?;
277 
278         let (sign_key, own_identity) = self.device.borrow().get_identity()?;
279         let own_ke_pub_key = own_ke_key
280             .pub_key
281             .ok_or(ag_err!(InvalidPubKeyInKey, "own public key is missing for key agreement"))?;
282         let own_ke_pub_key =
283             EcExchangeKeyPub(CoseKey::from_slice(&own_ke_pub_key).map_err(|e| {
284                 ag_err!(InvalidPubKeyInKey, "invalid own key for key agreement: {:?}", e)
285             })?);
286 
287         let salt_input = SaltInput {
288             source_version: self.get_version(),
289             sink_ke_pub_key: peer_pub_key,
290             source_ke_pub_key: own_ke_pub_key,
291             sink_ke_nonce: peer_nonce.clone(),
292             source_ke_nonce: own_ke_nonce.clone(),
293             sink_cert_chain: peer_identity.cert_chain.clone(),
294             source_cert_chain: own_identity.cert_chain.clone(),
295         };
296 
297         let salt = compute_salt(salt_input, &*self.crypto.sha256)?;
298 
299         let (in_encrypt_key, out_encrypt_key, hmac_key) =
300             derive_shared_keys(&ecdh_secret, &salt, Role::Source, &*self.crypto.hkdf)?;
301 
302         let (session_id, signature) = self.compute_sign_session_id(
303             SessionIdInput { sink_ke_nonce: peer_nonce, source_ke_nonce: own_ke_nonce },
304             HmacKey(hmac_key.0),
305             sign_key,
306         )?;
307 
308         // Validate peer's identity and the peer's signature on the session id
309         let verify_key =
310             self.device.borrow().validate_peer_identity(&peer_identity, &*self.crypto.ecdsa)?;
311         self.verify_signature_on_session_id(&verify_key, &session_id, peer_sig)?;
312 
313         // create two arcs encrypting the two shared encrypting keys with the per-boot-key
314         let shared_keys = self.create_shared_key_arcs(
315             peer_identity.clone(),
316             own_identity,
317             AesKey(in_encrypt_key.0),
318             AesKey(out_encrypt_key.0),
319             &session_id,
320             arc::AuthenticationCompleted(true),
321         )?;
322 
323         self.device.borrow_mut().record_shared_sessions(
324             &peer_identity,
325             &session_id,
326             &shared_keys,
327             &*self.crypto.sha256,
328         )?;
329         Ok(SessionInfo {
330             shared_keys,
331             session_id: session_id.to_vec(),
332             session_id_signature: signature,
333         })
334     }
335 
336     /// Fourth step in the key exchange protocol.
authentication_complete( &mut self, peer_sig: &[u8], shared_keys: [Vec<u8>; 2], ) -> Result<[Vec<u8>; 2], Error>337     pub fn authentication_complete(
338         &mut self,
339         peer_sig: &[u8],
340         shared_keys: [Vec<u8>; 2],
341     ) -> Result<[Vec<u8>; 2], Error> {
342         let in_key_arc = &shared_keys[0];
343         let out_key_arc = &shared_keys[1];
344 
345         let pbk = self.per_boot_key()?;
346 
347         let in_key_arc_content = arc::decipher_arc(&pbk, in_key_arc, &*self.crypto.aes_gcm)
348             .map_err(|e| {
349                 ag_err!(InvalidSharedKeyArcs, "failed to decrypt inbound shared key: {e:?}")
350             })?;
351         let (in_session_id, in_source_identity, _) = process_shared_key_arc_headers(
352             &in_key_arc_content.protected_headers,
353             &arc::AuthenticationCompleted(false),
354         )?;
355 
356         let out_key_arc_content = arc::decipher_arc(&pbk, out_key_arc, &*self.crypto.aes_gcm)
357             .map_err(|e| {
358                 ag_err!(InvalidSharedKeyArcs, "failed to decrypt inbound shared key: {e:?}")
359             })?;
360         let (out_session_id, out_source_identity, _) = process_shared_key_arc_headers(
361             &out_key_arc_content.protected_headers,
362             &arc::AuthenticationCompleted(false),
363         )?;
364 
365         if in_session_id != out_session_id {
366             return Err(ag_err!(InvalidSharedKeyArcs, "session id mismatch"));
367         }
368 
369         if in_source_identity != out_source_identity {
370             return Err(ag_err!(InvalidSharedKeyArcs, "peer identity mismatch"));
371         }
372         // Remove the corresponding entry from opened shared sessions which was inserted in `init`
373         let session_digest =
374             compute_session_digest(&in_source_identity, &in_session_id, &*self.crypto.sha256)?;
375         self.opened_shared_sessions.remove(session_digest).map_err(|_| {
376             ag_err!(InvalidSharedKeyArcs, "authentication_complete is called on invalid session")
377         })?;
378 
379         // Validate peer's identity and the peer's signature on the session id
380         let verification_key = self
381             .device
382             .borrow()
383             .validate_peer_identity(&in_source_identity, &*self.crypto.ecdsa)?;
384         self.verify_signature_on_session_id(&verification_key, &in_session_id, peer_sig)?;
385 
386         let updated_shared_key_arcs =
387             self.auth_complete_shared_key_arcs(in_key_arc_content, out_key_arc_content)?;
388 
389         self.device.borrow_mut().record_shared_sessions(
390             &in_source_identity,
391             &in_session_id,
392             &updated_shared_key_arcs,
393             &*self.crypto.sha256,
394         )?;
395         Ok(updated_shared_key_arcs)
396     }
397 
create_shared_key_arcs( &mut self, sink_id: Identity, source_id: Identity, in_encrypt_key: AesKey, out_encrypt_key: AesKey, session_id: &[u8], auth_complete: arc::AuthenticationCompleted, ) -> Result<[Vec<u8>; 2], Error>398     fn create_shared_key_arcs(
399         &mut self,
400         sink_id: Identity,
401         source_id: Identity,
402         in_encrypt_key: AesKey,
403         out_encrypt_key: AesKey,
404         session_id: &[u8],
405         auth_complete: arc::AuthenticationCompleted,
406     ) -> Result<[Vec<u8>; 2], Error> {
407         let pbk = match auth_complete.0 {
408             false => self
409                 .device
410                 .borrow()
411                 .get_or_create_per_boot_key(&*self.crypto.aes_gcm, &mut *self.crypto.rng)?,
412             true => self.per_boot_key()?,
413         };
414 
415         // auth complete protected header
416         let auth_complete_hdr = (arc::AUTHENTICATION_COMPLETE, Value::Bool(auth_complete.0));
417         // session id protected header
418         let session_id_hdr = (arc::SESSION_ID, Value::Bytes(try_to_vec(session_id)?));
419         // direction of encryption
420         let in_direction_hdr =
421             (arc::DIRECTION, Value::Integer((arc::DirectionOfEncryption::In as i32).into()));
422         // permissions header
423         let permissions_encoded = arc::Permissions {
424             source_id: Some(source_id),
425             sink_id: Some(sink_id),
426             ..Default::default()
427         }
428         .to_cbor_value()?;
429         let permission_hdr = (arc::PERMISSIONS, permissions_encoded);
430 
431         let mut in_protected_headers = Vec::<(Label, Value)>::new();
432         in_protected_headers.try_reserve(4)?;
433         in_protected_headers.push(auth_complete_hdr.clone());
434         in_protected_headers.push(session_id_hdr.clone());
435         in_protected_headers.push(permission_hdr.clone());
436         in_protected_headers.push(in_direction_hdr);
437 
438         let in_encrypt_key_arc = arc::create_arc(
439             &pbk,
440             arc::ArcContent {
441                 payload: arc::ArcPayload(in_encrypt_key.0.to_vec()),
442                 protected_headers: in_protected_headers,
443                 ..Default::default()
444             },
445             &*self.crypto.aes_gcm,
446             &mut *self.crypto.rng,
447         )?;
448 
449         // direction of encryption
450         let out_direction_hdr =
451             (arc::DIRECTION, Value::Integer((arc::DirectionOfEncryption::Out as i32).into()));
452         let mut out_protected_headers = Vec::<(Label, Value)>::new();
453         out_protected_headers.try_reserve(4)?;
454         out_protected_headers.push(auth_complete_hdr);
455         out_protected_headers.push(session_id_hdr);
456         out_protected_headers.push(permission_hdr);
457         out_protected_headers.push(out_direction_hdr);
458 
459         let out_encrypt_key_arc = arc::create_arc(
460             &pbk,
461             arc::ArcContent {
462                 payload: arc::ArcPayload(out_encrypt_key.0.to_vec()),
463                 protected_headers: out_protected_headers,
464                 ..Default::default()
465             },
466             &*self.crypto.aes_gcm,
467             &mut *self.crypto.rng,
468         )?;
469         Ok([in_encrypt_key_arc, out_encrypt_key_arc])
470     }
471 
472     /// Update the `authentication_complete` protected header in both arcs to be true
auth_complete_shared_key_arcs( &mut self, mut in_arc_content: arc::ArcContent, mut out_arc_content: arc::ArcContent, ) -> Result<[Vec<u8>; 2], Error>473     pub fn auth_complete_shared_key_arcs(
474         &mut self,
475         mut in_arc_content: arc::ArcContent,
476         mut out_arc_content: arc::ArcContent,
477     ) -> Result<[Vec<u8>; 2], Error> {
478         in_arc_content.protected_headers.retain(|v| v.0 != arc::AUTHENTICATION_COMPLETE);
479         out_arc_content.protected_headers.retain(|v| v.0 != arc::AUTHENTICATION_COMPLETE);
480 
481         let auth_complete_hdr = (arc::AUTHENTICATION_COMPLETE, Value::Bool(true));
482         in_arc_content.protected_headers.try_push(auth_complete_hdr.clone())?;
483         out_arc_content.protected_headers.try_push(auth_complete_hdr)?;
484 
485         let pbk = self.per_boot_key()?;
486         let in_encrypt_key_arc =
487             arc::create_arc(&pbk, in_arc_content, &*self.crypto.aes_gcm, &mut *self.crypto.rng)?;
488         let out_encrypt_key_arc =
489             arc::create_arc(&pbk, out_arc_content, &*self.crypto.aes_gcm, &mut *self.crypto.rng)?;
490         Ok([in_encrypt_key_arc, out_encrypt_key_arc])
491     }
492 
compute_sign_session_id( &self, session_id_input: SessionIdInput, hmac_key: HmacKey, sign_key: Option<EcSignKey>, ) -> Result<(SessionIdentifier, Vec<u8>), Error>493     fn compute_sign_session_id(
494         &self,
495         session_id_input: SessionIdInput,
496         hmac_key: HmacKey,
497         sign_key: Option<EcSignKey>,
498     ) -> Result<(SessionIdentifier, Vec<u8>), Error> {
499         let session_id = self.crypto.hmac.compute_hmac(&hmac_key, &session_id_input.to_vec()?)?;
500 
501         // Construct `CoseSign1`
502         let protected =
503             HeaderBuilder::new().algorithm(self.device.borrow().get_cose_sign_algorithm()?).build();
504         let cose_sign1 = CoseSign1Builder::new()
505             .protected(protected)
506             .try_create_detached_signature(&session_id, &[], |input| match sign_key {
507                 Some(key) => self.crypto.ecdsa.sign(&key, input),
508                 None => self.device.borrow().sign_data(&*self.crypto.ecdsa, input),
509             })?
510             .build();
511 
512         Ok((
513             session_id
514                 .as_slice()
515                 .try_into()
516                 .map_err(|e| ag_err!(InternalError, "invalid session id: {:?}", e))?,
517             cose_sign1.to_vec()?,
518         ))
519     }
520 
per_boot_key(&self) -> Result<AesKey, Error>521     fn per_boot_key(&self) -> Result<AesKey, Error> {
522         self.device.borrow().get_per_boot_key()
523     }
524 
525     /// Returns the latest supported version
get_version(&self) -> i32526     pub fn get_version(&self) -> i32 {
527         self.device.borrow().get_version()
528     }
529 
530     /// Validate and extract signature verification key from the peer's identity
peer_verification_key_from_identity( &self, identity: &[u8], ) -> Result<EcVerifyKey, Error>531     pub fn peer_verification_key_from_identity(
532         &self,
533         identity: &[u8],
534     ) -> Result<EcVerifyKey, Error> {
535         let identity = Identity::from_slice(identity)?;
536         self.device.borrow().validate_peer_identity(&identity, &*self.crypto.ecdsa)
537     }
538 
539     /// Verify the signature in a CBOR-encoded `COSE_Sign1` with detached payload `session_id`.
verify_signature_on_session_id( &self, verify_key: &EcVerifyKey, session_id: &[u8], signature: &[u8], ) -> Result<(), Error>540     pub fn verify_signature_on_session_id(
541         &self,
542         verify_key: &EcVerifyKey,
543         session_id: &[u8],
544         signature: &[u8],
545     ) -> Result<(), Error> {
546         let cose_sign1 = CoseSign1::from_slice(signature)?;
547         verify_key.validate_cose_key_params()?;
548         cose_sign1.verify_detached_signature(session_id, &[], |signature, data| {
549             self.crypto.ecdsa.verify_signature(verify_key, data, signature)
550         })
551     }
552 
553     /// An external entry point for retrieving the decrypted shared keys, given the arcs containing
554     /// the shared keys. The given arcs are validated against the records created at the end of each
555     /// key exchange. The number of arcs can be either one or two, depending on whether a particular
556     /// application protocol involves one-way (i.e. either outgoing or incoming messages) or
557     /// two-way communication (i.e. both outgoing and incoming messages).
decipher_shared_keys_from_arcs(&self, arcs: &[Vec<u8>]) -> Result<Vec<AesKey>, Error>558     pub fn decipher_shared_keys_from_arcs(&self, arcs: &[Vec<u8>]) -> Result<Vec<AesKey>, Error> {
559         if arcs.len() > 2 || arcs.is_empty() {
560             return Err(ag_err!(
561                 InvalidSharedKeyArcs,
562                 "expected one or two arcs, provided {} arcs",
563                 arcs.len()
564             ));
565         }
566         let arc_contents = self.decrypt_and_validate_shared_key_arcs(arcs)?;
567         let mut shared_keys = Vec::<AesKey>::new();
568         for arc_content in arc_contents {
569             let key = AesKey::try_from(arc_content.payload)?;
570             if key.0 == [0; AES_256_KEY_LEN] {
571                 return Err(ag_err!(InvalidSharedKeyArcs, "payload key is all zero",));
572             }
573             shared_keys.try_push(key)?;
574         }
575         Ok(shared_keys)
576     }
577     /// Decrypt the provided arcs, validate and return the arc contents.
decrypt_and_validate_shared_key_arcs( &self, arcs: &[Vec<u8>], ) -> Result<Vec<arc::ArcContent>, Error>578     fn decrypt_and_validate_shared_key_arcs(
579         &self,
580         arcs: &[Vec<u8>],
581     ) -> Result<Vec<arc::ArcContent>, Error> {
582         if arcs.is_empty() {
583             return Err(ag_err!(InvalidSharedKeyArcs, "array of arcs is empty"));
584         }
585         let mut session_identifier: Option<[u8; SESSION_ID_LEN]> = None;
586         let mut source_identity: Option<Identity> = None;
587         let mut sink_identity: Option<Identity> = None;
588         let mut arc_contents = Vec::<arc::ArcContent>::new();
589         for arc in arcs {
590             let pbk = self.per_boot_key()?;
591             let arc_content = arc::decipher_arc(&pbk, arc, &*self.crypto.aes_gcm).map_err(|e| {
592                 ag_err!(InvalidSharedKeyArcs, "failed to decrypt shared key: {e:?}")
593             })?;
594             let (session_id, source_id, sink_id) = process_shared_key_arc_headers(
595                 &arc_content.protected_headers,
596                 &arc::AuthenticationCompleted(true),
597             )?;
598             arc_contents.try_push(arc_content)?;
599             match &session_identifier {
600                 Some(id) if *id == session_id => {}
601                 Some(_) => {
602                     return Err(ag_err!(InvalidSharedKeyArcs, "session id mismatch"));
603                 }
604                 None => {
605                     session_identifier = Some(session_id);
606                 }
607             }
608             match &source_identity {
609                 Some(identity) if *identity == source_id => {}
610                 Some(_) => {
611                     return Err(ag_err!(InvalidSharedKeyArcs, "source identity mismatch"));
612                 }
613                 None => {
614                     source_identity = Some(source_id);
615                 }
616             }
617             match &sink_identity {
618                 Some(identity) if *identity == sink_id => {}
619                 Some(_) => {
620                     return Err(ag_err!(InvalidSharedKeyArcs, "sink identity mismatch"));
621                 }
622                 None => {
623                     sink_identity = Some(sink_id);
624                 }
625             }
626         }
627         // It is safe to unwrap because we ensure that there is at least one arc provided in the
628         // method call
629         let session_identifier = session_identifier.unwrap();
630         let source_identity = source_identity.unwrap();
631         let sink_identity = sink_identity.unwrap();
632         let (_, self_identity) = self.device.borrow().get_identity()?;
633         if self_identity == source_identity {
634             self.device.borrow().validate_shared_sessions(
635                 &sink_identity,
636                 &session_identifier,
637                 arcs,
638                 &*self.crypto.sha256,
639             )?;
640         } else if self_identity == sink_identity {
641             self.device.borrow().validate_shared_sessions(
642                 &source_identity,
643                 &session_identifier,
644                 arcs,
645                 &*self.crypto.sha256,
646             )?;
647         } else {
648             // Note: it is not possible to reach this branch because if the arc is decrypted by the
649             // per-boot key, the correct self identity should have been included in the arc.
650             return Err(ag_err!(InvalidSharedKeyArcs, "self identity is not included in the arc."));
651         }
652         Ok(arc_contents)
653     }
654 }
655 
compute_ke_key_digest(ke_key: &Key, sha256: &dyn Sha256) -> Result<[u8; SHA_256_LEN], Error>656 fn compute_ke_key_digest(ke_key: &Key, sha256: &dyn Sha256) -> Result<[u8; SHA_256_LEN], Error> {
657     let mut key_input = Vec::new();
658     key_input.try_extend_from_slice(
659         ke_key.pub_key.as_ref().ok_or_else(|| ag_err!(InvalidPubKeyInKey, "missing public key"))?,
660     )?;
661     key_input.try_extend_from_slice(
662         ke_key
663             .arc_from_pbk
664             .as_ref()
665             .ok_or_else(|| ag_err!(InvalidPrivKeyArcInKey, "missing private key arc"))?,
666     )?;
667     sha256.compute_sha256(&key_input)
668 }
669 
compute_session_digest( peer_identity: &Identity, session_id: &[u8; SESSION_ID_LEN], sha256: &dyn Sha256, ) -> Result<SessionDigest, Error>670 fn compute_session_digest(
671     peer_identity: &Identity,
672     session_id: &[u8; SESSION_ID_LEN],
673     sha256: &dyn Sha256,
674 ) -> Result<SessionDigest, Error> {
675     let mut session_info = Vec::new();
676     session_info.try_extend_from_slice(&peer_identity.clone().to_vec()?)?;
677     session_info.try_extend_from_slice(session_id)?;
678     sha256.compute_sha256(&session_info)
679 }
680 
681 /// A helper function to process the headers of the shared key arcs, verify the given authentication
682 /// completed status, extract and return the session id, source identity and sink identity.
process_shared_key_arc_headers( protected_headers: &[(Label, Value)], expected_status: &arc::AuthenticationCompleted, ) -> Result<(SessionIdentifier, Identity, Identity), Error>683 pub fn process_shared_key_arc_headers(
684     protected_headers: &[(Label, Value)],
685     expected_status: &arc::AuthenticationCompleted,
686 ) -> Result<(SessionIdentifier, Identity, Identity), Error> {
687     let (_, val) = protected_headers
688         .iter()
689         .find(|(l, _v)| *l == arc::SESSION_ID)
690         .ok_or_else(|| ag_err!(InvalidSharedKeyArcs, "session id is missing"))?;
691     let session_id = match val {
692         Value::Bytes(b) => b.clone(),
693         _ => return Err(ag_err!(InvalidSharedKeyArcs, "invalid encoding of session id")),
694     };
695     let session_id: SessionIdentifier = session_id
696         .try_into()
697         .map_err(|e| ag_err!(InvalidSharedKeyArcs, "invalid session id: {:?}", e))?;
698 
699     let (_, val) = protected_headers
700         .iter()
701         .find(|(l, _v)| *l == arc::PERMISSIONS)
702         .ok_or_else(|| ag_err!(InvalidSharedKeyArcs, "permissions are missing"))?;
703     let permissions = arc::Permissions::from_cbor_value(val.clone())?;
704     let source_identity = permissions.source_id.ok_or_else(|| {
705         ag_err!(InvalidSharedKeyArcs, "source identity is missing in the permissions")
706     })?;
707     let sink_identity = permissions.sink_id.ok_or_else(|| {
708         ag_err!(InvalidSharedKeyArcs, "sink identity is missing in the permissions")
709     })?;
710 
711     let (_, val) = protected_headers
712         .iter()
713         .find(|(l, _v)| *l == arc::AUTHENTICATION_COMPLETE)
714         .ok_or_else(|| ag_err!(InvalidSharedKeyArcs, "authentication complete is missing"))?;
715     let status = match val {
716         Value::Bool(b) => *b,
717         _ => {
718             return Err(ag_err!(
719                 InvalidSharedKeyArcs,
720                 "invalid encoding of authentication complete"
721             ))
722         }
723     };
724     if status != expected_status.0 {
725         return Err(ag_err!(InvalidSharedKeyArcs, "invalid authentication complete status"));
726     }
727     Ok((session_id, source_identity, sink_identity))
728 }
729 
decode_peer_info( pub_key: &[u8], identity: &[u8], nonce: &[u8], ) -> Result<(EcExchangeKeyPub, Identity, Nonce16), Error>730 fn decode_peer_info(
731     pub_key: &[u8],
732     identity: &[u8],
733     nonce: &[u8],
734 ) -> Result<(EcExchangeKeyPub, Identity, Nonce16), Error> {
735     let pub_key =
736         EcExchangeKeyPub(CoseKey::from_slice(pub_key).map_err(|e| {
737             ag_err!(InvalidPeerKeKey, "invalid peer key for key agreement: {:?}", e)
738         })?);
739     let identity = Identity::from_slice(identity)
740         .map_err(|e| ag_err!(InvalidIdentity, "invalid peer identity: {:?}", e))?;
741     let nonce = Nonce16(
742         nonce.try_into().map_err(|e| ag_err!(InvalidPeerNonce, "invalid nonce size: {:?}", e))?,
743     );
744     Ok((pub_key, identity, nonce))
745 }
746 
compute_shared_secret( ecdh: &dyn EcDh, own_key: &EcExchangeKeyPriv, peer_key: &EcExchangeKeyPub, ) -> Result<EcdhSecret, Error>747 fn compute_shared_secret(
748     ecdh: &dyn EcDh,
749     own_key: &EcExchangeKeyPriv,
750     peer_key: &EcExchangeKeyPub,
751 ) -> Result<EcdhSecret, Error> {
752     check_cose_key_params(
753         &peer_key.0,
754         iana::KeyType::EC2,
755         iana::Algorithm::ECDH_ES_HKDF_256, // ECDH
756         iana::EllipticCurve::P_256,
757         ErrorCode::InvalidPeerKeKey,
758     )?;
759     ecdh.compute_shared_secret(own_key, peer_key)
760 }
761 
compute_salt(salt_input: SaltInput, sha_256: &dyn Sha256) -> Result<[u8; SHA_256_LEN], Error>762 fn compute_salt(salt_input: SaltInput, sha_256: &dyn Sha256) -> Result<[u8; SHA_256_LEN], Error> {
763     sha_256.compute_sha256(&salt_input.to_vec()?)
764 }
765 
derive_shared_keys( ecdh_secret: &EcdhSecret, salt: &[u8; SHA_256_LEN], role: Role, hkdf: &dyn Hkdf, ) -> Result<(PseudoRandKey, PseudoRandKey, PseudoRandKey), Error>766 fn derive_shared_keys(
767     ecdh_secret: &EcdhSecret,
768     salt: &[u8; SHA_256_LEN],
769     role: Role,
770     hkdf: &dyn Hkdf,
771 ) -> Result<(PseudoRandKey, PseudoRandKey, PseudoRandKey), Error> {
772     let pseudo_rand_key = hkdf.extract(salt, ecdh_secret)?;
773     let hmac_key = hkdf.expand(&pseudo_rand_key, CONTEXT_KE_HMAC_KEY)?;
774     match role {
775         Role::Sink => {
776             let in_encrypt_key = hkdf.expand(&pseudo_rand_key, CONTEXT_KE_ENCRYPTION_KEY_1)?;
777             let out_encrypt_key = hkdf.expand(&pseudo_rand_key, CONTEXT_KE_ENCRYPTION_KEY_2)?;
778             Ok((in_encrypt_key, out_encrypt_key, hmac_key))
779         }
780         Role::Source => {
781             let in_encrypt_key = hkdf.expand(&pseudo_rand_key, CONTEXT_KE_ENCRYPTION_KEY_2)?;
782             let out_encrypt_key = hkdf.expand(&pseudo_rand_key, CONTEXT_KE_ENCRYPTION_KEY_1)?;
783             Ok((in_encrypt_key, out_encrypt_key, hmac_key))
784         }
785     }
786 }
787 
788 /// Process the given protected headers of an arc and return the nonce used for key agreement
extract_nonce(protected_headers: &[(Label, Value)]) -> Result<Nonce16, Error>789 pub fn extract_nonce(protected_headers: &[(Label, Value)]) -> Result<Nonce16, Error> {
790     for (label, val) in protected_headers {
791         if *label == arc::KE_NONCE {
792             match val {
793                 Value::Bytes(ref b) => {
794                     return Ok(Nonce16(b.clone().try_into().map_err(|e| {
795                         ag_err!(
796                             InvalidPrivKeyArcInKey,
797                             "invalid length of own nonce for key agreement: {:?}",
798                             e
799                         )
800                     })?))
801                 }
802                 _ => {
803                     return Err(ag_err!(
804                         InvalidPrivKeyArcInKey,
805                         "invalid encoding of own nonce for key agreement"
806                     ))
807                 }
808             };
809         }
810     }
811 
812     Err(ag_err!(InvalidPrivKeyArcInKey, "nonce for key agreement is missing in the headers"))
813 }
814