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 //! Definitions related to different types of keys and other cryptographic artifacts.
18 use crate::arc;
19 use crate::error::Error;
20 use crate::traits::{EcDsa, Rng};
21 use crate::FallibleAllocExt;
22 use crate::{ag_err, ag_verr};
23 use alloc::{
24     string::{String, ToString},
25     vec::Vec,
26 };
27 use authgraph_wire as wire;
28 use coset::{
29     cbor, cbor::value::Value, iana, AsCborValue, CborOrdering, CborSerializable, CoseError,
30     CoseKey, CoseSign1, Label,
31 };
32 use wire::ErrorCode;
33 use zeroize::ZeroizeOnDrop;
34 
35 pub use wire::Key;
36 
37 /// Length of an AES 256-bits key in bytes
38 pub const AES_256_KEY_LEN: usize = 32;
39 
40 /// Size (in bytes) of a curve 25519 private key.
41 pub const CURVE25519_PRIV_KEY_LEN: usize = 32;
42 
43 /// Version of the cert chain as per
44 /// hardware/interfaces/security/authgraph/aidl/android/hardware/security/authgraph/
45 /// ExplicitKeyDiceCertChain.cddl
46 pub const EXPLICIT_KEY_DICE_CERT_CHAIN_VERSION: i32 = 1;
47 
48 /// Version of the identity as per
49 /// hardware/interfaces/security/authgraph/aidl/android/hardware/security/authgraph/Identity.cddl
50 pub const IDENTITY_VERSION: i32 = 1;
51 
52 /// Length of a SHA 256 digest in bytes
53 pub const SHA_256_LEN: usize = 32;
54 
55 // Following constants represent the keys of the (key, value) pairs in a Dice certificate
56 const ISS: i64 = 1;
57 const SUB: i64 = 2;
58 const PROFILE_NAME: i64 = -4670554;
59 const SUBJECT_PUBLIC_KEY: i64 = -4670552;
60 const KEY_USAGE: i64 = -4670553;
61 const CODE_HASH: i64 = -4670545;
62 const CODE_DESC: i64 = -4670546;
63 const CONFIG_HASH: i64 = -4670547;
64 const CONFIG_DESC: i64 = -4670548;
65 const AUTHORITY_HASH: i64 = -4670549;
66 const AUTHORITY_DESC: i64 = -4670550;
67 const MODE: i64 = -4670551;
68 
69 const COMPONENT_NAME: i64 = -70002;
70 const COMPONENT_VERSION: i64 = -70003;
71 const RESETTABLE: i64 = -70004;
72 const SECURITY_VERSION: i64 = -70005;
73 const RKP_VM_MARKER: i64 = -70006;
74 
75 /// AES key of 256 bits
76 #[derive(Clone, ZeroizeOnDrop)]
77 pub struct AesKey(pub [u8; AES_256_KEY_LEN]);
78 
79 impl TryFrom<arc::ArcPayload> for AesKey {
80     type Error = Error;
try_from(payload: arc::ArcPayload) -> Result<AesKey, Self::Error>81     fn try_from(payload: arc::ArcPayload) -> Result<AesKey, Self::Error> {
82         if payload.0.len() != AES_256_KEY_LEN {
83             return Err(ag_err!(
84                 InvalidSharedKeyArcs,
85                 "payload key has invalid length: {}",
86                 payload.0.len()
87             ));
88         }
89         let mut key = AesKey([0; AES_256_KEY_LEN]);
90         key.0.copy_from_slice(&payload.0);
91         Ok(key)
92     }
93 }
94 
95 /// EC key pair on P256 curve, created for ECDH.
96 pub struct EcExchangeKey {
97     /// Public key
98     pub pub_key: EcExchangeKeyPub,
99     /// Private key
100     pub priv_key: EcExchangeKeyPriv,
101 }
102 
103 /// Public key of an EC key pair created for ECDH
104 #[derive(Clone)]
105 pub struct EcExchangeKeyPub(pub CoseKey);
106 
107 /// Private key of an EC key pair created for ECDH.
108 /// It is up to the implementers of the AuthGraph traits to decide how to encode the private key.
109 #[derive(ZeroizeOnDrop)]
110 pub struct EcExchangeKeyPriv(pub Vec<u8>);
111 
112 /// Shared secret agreed via ECDH
113 #[derive(ZeroizeOnDrop)]
114 pub struct EcdhSecret(pub Vec<u8>);
115 
116 /// Pseudo random key of 256 bits that is output by extract/expand functions of key derivation
117 #[derive(ZeroizeOnDrop)]
118 pub struct PseudoRandKey(pub [u8; 32]);
119 
120 /// A nonce of 16 bytes, used for key exchange
121 #[derive(Clone)]
122 pub struct Nonce16(pub [u8; 16]);
123 
124 impl Nonce16 {
125     /// Create a random nonce of 16 bytes
new(rng: &dyn Rng) -> Self126     pub fn new(rng: &dyn Rng) -> Self {
127         let mut nonce = Nonce16([0u8; 16]);
128         rng.fill_bytes(&mut nonce.0);
129         nonce
130     }
131 }
132 
133 /// A nonce of 12 bytes, used for AES-GCM encryption
134 pub struct Nonce12(pub [u8; 12]);
135 
136 impl Nonce12 {
137     /// Create a random nonce of 12 bytes
new(rng: &dyn Rng) -> Self138     pub fn new(rng: &dyn Rng) -> Self {
139         let mut nonce = Nonce12([0u8; 12]);
140         rng.fill_bytes(&mut nonce.0);
141         nonce
142     }
143 }
144 
145 impl TryFrom<&[u8]> for Nonce12 {
146     type Error = Error;
try_from(v: &[u8]) -> Result<Self, Self::Error>147     fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
148         if v.len() != 12 {
149             return Err(ag_err!(InvalidSharedKeyArcs, "nonce has invalid length: {}", v.len()));
150         }
151         let mut nonce = Nonce12([0; 12]);
152         nonce.0.copy_from_slice(v);
153         Ok(nonce)
154     }
155 }
156 
157 /// Milliseconds since an epoch that is common between source and sink
158 pub struct MillisecondsSinceEpoch(pub i64);
159 
160 /// Variants of EC private key used to create signature
161 #[derive(Clone, ZeroizeOnDrop)]
162 pub enum EcSignKey {
163     /// On curve Ed25519
164     Ed25519([u8; CURVE25519_PRIV_KEY_LEN]),
165     /// On NIST curve P-256
166     P256(Vec<u8>),
167     /// On NIST curve P-384
168     P384(Vec<u8>),
169 }
170 
171 /// Variants of EC public key used to verify signature
172 #[derive(Clone, PartialEq)]
173 pub enum EcVerifyKey {
174     /// On curve Ed25519
175     Ed25519(CoseKey),
176     /// On NIST curve P-256
177     P256(CoseKey),
178     /// On NIST curve P-384
179     P384(CoseKey),
180 }
181 
182 impl Default for EcVerifyKey {
default() -> Self183     fn default() -> Self {
184         EcVerifyKey::P256(CoseKey::default())
185     }
186 }
187 
188 impl EcVerifyKey {
189     /// Return the `CoseKey` contained in any variant of this enum.
190     /// Assume that the `CoseKey` is checked for appropriate header parameters before it used for
191     /// signature verifictation.
get_key(self) -> CoseKey192     pub fn get_key(self) -> CoseKey {
193         match self {
194             EcVerifyKey::Ed25519(k) | EcVerifyKey::P256(k) | EcVerifyKey::P384(k) => k,
195         }
196     }
197 
198     /// Similar to `get_key()`, return the `CoseKey` contained in any variant of this enum
199     /// (but by reference).
get_key_ref(&self) -> &CoseKey200     pub fn get_key_ref(&self) -> &CoseKey {
201         match self {
202             EcVerifyKey::Ed25519(k) | EcVerifyKey::P256(k) | EcVerifyKey::P384(k) => k,
203         }
204     }
205 
206     /// Validate whether the CoseKey is in the expected canonical form as per the spec.
is_canonicalized(&self) -> bool207     pub fn is_canonicalized(&self) -> bool {
208         let mut expected = self.clone();
209         expected.canonicalize_cose_key();
210         *self == expected
211     }
212 
213     /// Order the labels of the Cose Key, in order to ensure canonical encoding in accordance with
214     /// Core Deterministic Encoding Requirements [RFC 8949 s4.2.1].
canonicalize_cose_key(&mut self)215     pub fn canonicalize_cose_key(&mut self) {
216         match self {
217             EcVerifyKey::Ed25519(k) | EcVerifyKey::P256(k) | EcVerifyKey::P384(k) => {
218                 k.canonicalize(CborOrdering::Lexicographic);
219             }
220         }
221     }
222 
223     /// Return the Cose signing algorithm corresponds to the given public signing key.
224     /// Assume that the `CoseKey` is checked for appropriate header parameters before it is used for
225     /// signature verification.
get_cose_sign_algorithm(&self) -> iana::Algorithm226     pub fn get_cose_sign_algorithm(&self) -> iana::Algorithm {
227         match *self {
228             EcVerifyKey::Ed25519(_) => iana::Algorithm::EdDSA,
229             EcVerifyKey::P256(_) => iana::Algorithm::ES256,
230             EcVerifyKey::P384(_) => iana::Algorithm::ES384,
231         }
232     }
233 
234     /// Construct `EcVerifyKey` from `CoseKey`.
from_cose_key(cose_key: CoseKey) -> Result<Self, CoseError>235     pub fn from_cose_key(cose_key: CoseKey) -> Result<Self, CoseError> {
236         // Only the algorithm is checked while decoding, other parameters are
237         // checked during validation of the `EcVerifykey`.
238         match cose_key.alg {
239             Some(coset::Algorithm::Assigned(iana::Algorithm::EdDSA)) => {
240                 Ok(EcVerifyKey::Ed25519(cose_key))
241             }
242             Some(coset::Algorithm::Assigned(iana::Algorithm::ES256)) => {
243                 Ok(EcVerifyKey::P256(cose_key))
244             }
245             Some(coset::Algorithm::Assigned(iana::Algorithm::ES384)) => {
246                 Ok(EcVerifyKey::P384(cose_key))
247             }
248             Some(_) => {
249                 Err(CoseError::UnexpectedItem("unsupported algorithm", "Ed25519 or P256 or P384"))
250             }
251             None => Err(CoseError::UnexpectedItem("algorithm is none", "Ed25519 or P256 or P384")),
252         }
253     }
254 
255     /// Validate the key parameters
validate_cose_key_params(&self) -> Result<(), Error>256     pub fn validate_cose_key_params(&self) -> Result<(), Error> {
257         match self {
258             EcVerifyKey::Ed25519(cose_key) => check_cose_key_params(
259                 cose_key,
260                 iana::KeyType::OKP,
261                 iana::Algorithm::EdDSA,
262                 iana::EllipticCurve::Ed25519,
263                 ErrorCode::InvalidCertChain,
264             ),
265             EcVerifyKey::P256(cose_key) => check_cose_key_params(
266                 cose_key,
267                 iana::KeyType::EC2,
268                 iana::Algorithm::ES256,
269                 iana::EllipticCurve::P_256,
270                 ErrorCode::InvalidCertChain,
271             ),
272             EcVerifyKey::P384(cose_key) => check_cose_key_params(
273                 cose_key,
274                 iana::KeyType::EC2,
275                 iana::Algorithm::ES384,
276                 iana::EllipticCurve::P_384,
277                 ErrorCode::InvalidCertChain,
278             ),
279         }
280     }
281 }
282 
283 /// HMAC key of 256 bits
284 #[derive(ZeroizeOnDrop)]
285 pub struct HmacKey(pub [u8; 32]);
286 
287 /// Identity of an AuthGraph participant. The CDDL is listed in hardware/interfaces/security/
288 /// authgraph/aidl/android/hardware/security/Identity.cddl
289 #[derive(Clone, PartialEq)]
290 pub struct Identity {
291     /// Version of the cddl
292     pub version: i32,
293     /// Certificate chain
294     pub cert_chain: CertChain,
295     /// Identity verification policy
296     pub policy: Option<Policy>,
297 }
298 
299 /// Certificate chain containing the public signing key. The CDDL is listed in
300 /// hardware/interfaces/security/authgraph/aidl/android/hardware/security/
301 /// authgraph/ExplicitKeyDiceCertChain.cddl
302 #[derive(Clone, PartialEq)]
303 pub struct CertChain {
304     /// Version of the cddl
305     pub version: i32,
306     /// Root public key used to verify the signature in the first DiceChainEntry. If `cert_chain`
307     /// is none, this is the key used to verify the signature created by the AuthGraph participant.
308     pub root_key: EcVerifyKey,
309     /// Dice certificate chain.
310     pub dice_cert_chain: Option<Vec<DiceChainEntry>>,
311 }
312 
313 /// An entry in the certificate chain (i.e. a certificate).
314 #[derive(Clone, PartialEq)]
315 pub struct DiceChainEntry {
316     /// A certificate is represented as CoseSign1. The `payload` field of CoseSign1 holds the CBOR
317     /// encoded payload that was signed.
318     pub signature: CoseSign1,
319     /// The payload signed in the certificate is partially decoded as
320     /// `DiceChainEntryPayloadPartiallyDecoded` for validation purposes.
321     pub payload: DiceChainEntryPayloadPartiallyDecoded,
322 }
323 
324 /// Partially decoded payload for each entry in the DICE chain
325 #[derive(Default, Clone, PartialEq)]
326 pub struct DiceChainEntryPayloadPartiallyDecoded {
327     /// Issuer of the DiceChainEntry. Required as per the CDDL.
328     pub issuer: Option<String>,
329     /// The party whom the certificate is issued to. Required as per the CDDL.
330     pub subject: Option<String>,
331     /// Public signing key of the party whom the certificate is issued to. Required as per the CDDL.
332     pub subject_pub_key: Option<EcVerifyKey>,
333     /// The complete CBOR map containing all the fields (including the fields above) of the
334     /// DiceChainEntryPayload
335     pub full_map: Option<Value>,
336 }
337 
338 /// Payload for each entry in the DICE chain
339 #[derive(Default, Clone, PartialEq)]
340 pub struct DiceChainEntryPayload {
341     /// Issuer of the DiceChainEntry. Required as per the CDDL.
342     pub issuer: Option<String>,
343     /// The party whom the certificate is issued to. Required as per the CDDL.
344     pub subject: Option<String>,
345     /// Profile name. Required as per the CDDL.
346     pub profile_name: Option<String>,
347     /// Public signing key of the party whom the certificate is issued to. Required as per the CDDL.
348     pub subject_pub_key: Option<EcVerifyKey>,
349     /// Usage of the key pair corresponding to `subject_public_key`. Required as per the CDDL.
350     pub key_usage: Option<Vec<u8>>,
351     /// Code hash. Required as per the CDDL.
352     pub code_hash: Option<Vec<u8>>,
353     /// Code descriptor. Optional as per the CDDL.
354     pub code_descriptor: Option<Vec<u8>>,
355     /// Configuration hash. Required as per the CDDL.
356     pub configuration_hash: Option<Vec<u8>>,
357     /// Configuration descriptor. Required as per the CDDL.
358     pub configuration_descriptor: Option<ConfigurationDescriptorOrLegacy>,
359     /// Authority hash. Required as per the CDDL.
360     pub authority_hash: Option<Vec<u8>>,
361     /// Authority descriptor. Optional as per the CDDL.
362     pub authority_descriptor: Option<Vec<u8>>,
363     /// Mode. Required as per the CDDL.
364     pub mode: Option<Vec<u8>>,
365     /// Any custom fields, if present
366     pub custom_fields: Vec<(i64, Value)>,
367 }
368 
369 /// Configuration descriptor in `DiceChainEntryPayload`. All the fields are optional
370 #[derive(Default, Clone, PartialEq)]
371 pub struct ConfigurationDescriptor {
372     /// Component name
373     pub component_name: Option<String>,
374     /// Component version
375     pub component_version: Option<ComponentVersion>,
376     /// Resettable. If the field is present, the value is true, otherwise, it is false.
377     pub resettable: bool,
378     /// Security version
379     pub security_version: Option<u32>,
380     /// RKP VM Marker. If the field is present, the value is true, otherwise, it is false.
381     pub rkp_vm_marker: bool,
382     /// Any custom fields, if present
383     pub custom_fields: Vec<(i64, Value)>,
384 }
385 
386 /// Configuration descriptor that allows for non-spec compliant legacy values.
387 #[derive(Clone, PartialEq)]
388 pub enum ConfigurationDescriptorOrLegacy {
389     /// Configuration descriptor complying with the CDDL schema.
390     Descriptor(ConfigurationDescriptor),
391     /// Raw legacy configuration descriptor (b/261647022).
392     Legacy(Vec<u8>),
393 }
394 
395 /// Component version can be either an integer or a string, as per the CDDL.
396 #[derive(Clone, PartialEq)]
397 pub enum ComponentVersion {
398     /// Version represented as an integer
399     IntVersion(u32),
400     /// Version represented as a string
401     TextVersion(String),
402 }
403 
404 /// Identity verification policy specifying how to validate the certificate chain. The CDDL is
405 /// listed in hardware/interfaces/security/authgraph/aidl/android/hardware/security/authgraph/
406 /// DicePolicy.cddl
407 #[derive(Clone, Eq, PartialEq)]
408 pub struct Policy(pub Vec<u8>);
409 
410 /// The output of identity verification.
411 pub enum IdentityVerificationDecision {
412     /// The latest certificate chain is allowed by the identity verification policy, the identity
413     /// owner is not updated
414     Match,
415     /// The latest certificate chain is not allowed by the identity verification policy
416     Mismatch,
417     /// The latest certificate chain is allowed by the identity verification policy and the identity
418     /// owner is updated
419     Updated,
420 }
421 
422 /// The structure containing the inputs for the `salt` used in extracting a pseudo random key
423 /// from the Diffie-Hellman secret.
424 /// salt = bstr .cbor [
425 ///     source_version:    int,
426 ///     sink_ke_pub_key:   bstr .cbor PlainPubKey,
427 ///     source_ke_pub_key: bstr .cbor PlainPubKey,
428 ///     sink_ke_nonce:     bstr .size 16,
429 ///     source_ke_nonce:   bstr .size 16,
430 ///     sink_cert_chain:   bstr .cbor ExplicitKeyDiceCertChain,
431 ///     source_cert_chain: bstr .cbor ExplicitKeyDiceCertChain,
432 /// ]
433 pub struct SaltInput {
434     /// Version advertised by the source (P1).
435     pub source_version: i32,
436     /// Public key from sink for key exchange
437     pub sink_ke_pub_key: EcExchangeKeyPub,
438     /// Public key from source for ke exchange
439     pub source_ke_pub_key: EcExchangeKeyPub,
440     /// Nonce from sink for key exchange
441     pub sink_ke_nonce: Nonce16,
442     /// Nonce from source for key exchange
443     pub source_ke_nonce: Nonce16,
444     /// ExplicitKeyDiceCertChain of sink
445     pub sink_cert_chain: CertChain,
446     /// ExplicitKeyDiceCertChain of source
447     pub source_cert_chain: CertChain,
448 }
449 
450 /// The structure containing the inputs for the `session_id` computed during key agreement.
451 /// session_id = bstr .cbor [
452 ///     sink_ke_nonce:     bstr .size 16,
453 ///     source_ke_nonce:   bstr .size 16,
454 /// ]
455 pub struct SessionIdInput {
456     /// Nonce from sink for key exchange
457     pub sink_ke_nonce: Nonce16,
458     /// Nonce from source for key exchange
459     pub source_ke_nonce: Nonce16,
460 }
461 
462 impl Identity {
463     /// A helper function to validate the peer's identity. The validation is mainly about the
464     /// Dice certificate chain (see `validate` method on `CertChain`), which is part of the
465     /// identity. Peer's identity is validated when the peer is authenticated (i.e. during
466     /// verification of the signature of the peer). Return the signature verification key upon
467     /// successful validation.
validate(&self, ecdsa: &dyn EcDsa) -> Result<EcVerifyKey, Error>468     pub fn validate(&self, ecdsa: &dyn EcDsa) -> Result<EcVerifyKey, Error> {
469         if self.version != IDENTITY_VERSION {
470             return Err(ag_err!(InvalidIdentity, "version mismatch"));
471         }
472         self.cert_chain.validate(ecdsa)
473         // TODO: Assume that the policy is None for now.
474     }
475 }
476 
477 impl AsCborValue for Identity {
from_cbor_value(value: Value) -> Result<Self, CoseError>478     fn from_cbor_value(value: Value) -> Result<Self, CoseError> {
479         let mut array = match value {
480             Value::Array(a) if a.len() == 3 || a.len() == 2 => a,
481             _ => {
482                 return Err(CoseError::UnexpectedItem("_", "array with two or three items"));
483             }
484         };
485         // TODO: Assume policy is none for now
486         let cert_chain = match array.remove(1) {
487             Value::Bytes(cert_chain_encoded) => CertChain::from_slice(&cert_chain_encoded)?,
488             _ => {
489                 return Err(CoseError::UnexpectedItem("_", "encoded CertChain"));
490             }
491         };
492         let version: i32 = match array.remove(0) {
493             Value::Integer(i) => i.try_into()?,
494             _ => {
495                 return Err(CoseError::UnexpectedItem("_", "Integer"));
496             }
497         };
498         Ok(Identity { version, cert_chain, policy: None })
499     }
500 
to_cbor_value(self) -> Result<Value, CoseError>501     fn to_cbor_value(self) -> Result<Value, CoseError> {
502         let mut array = Vec::<Value>::new();
503         array.try_push(Value::Integer(self.version.into())).map_err(|_| CoseError::EncodeFailed)?;
504         array
505             .try_push(Value::Bytes(self.cert_chain.to_vec()?))
506             .map_err(|_| CoseError::EncodeFailed)?;
507         // TODO: encode policy if present
508         Ok(Value::Array(array))
509     }
510 }
511 
512 impl CborSerializable for Identity {}
513 
514 impl CertChain {
515     /// Perform the following validations on the decoded DICE cert chain:
516     /// 1. correctness of the `version`
517     /// 2. `root_key` is in accordance with Core Deterministic Encoding Requirements
518     ///    [RFC 8949 s4.2.1]
519     /// 3. correctness of Cose key parameters of the `root_key`
520     /// 4. if dice_cert_chain is present, check for each DiceChainEntry,
521     ///    i.  Cose key parameters of `subject_pub_key`
522     ///    ii. the signature is verified with the parent's `subject_pub_key` or with the `root_key`
523     ///        for the first DiceChainEntry
524     ///    iii.`subject` in the parent's DiceChainEntryPayload matches the `issuer` in the current
525     ///        DiceChainEntryPayload (except for the first DiceChainEntry)
526     ///    iv. no two identical `subject` or `subject_pub_key` in the DiceChainEntryPayloads.
validate(&self, ecdsa: &dyn EcDsa) -> Result<EcVerifyKey, Error>527     pub fn validate(&self, ecdsa: &dyn EcDsa) -> Result<EcVerifyKey, Error> {
528         if self.version != EXPLICIT_KEY_DICE_CERT_CHAIN_VERSION {
529             return Err(ag_err!(InvalidCertChain, "version mismatch"));
530         }
531         if !self.root_key.is_canonicalized() {
532             return Err(ag_err!(
533                 InvalidCertChain,
534                 "root key is not in the required canonical form"
535             ));
536         }
537         self.root_key.validate_cose_key_params()?;
538         match &self.dice_cert_chain {
539             None => Ok(self.root_key.clone()),
540             Some(dice_chain_entries) => {
541                 let mut parent_pub_sign_key = &self.root_key;
542                 let mut parent_subj: Option<&String> = None;
543                 let mut subj_pub_key_list = Vec::<&EcVerifyKey>::new();
544                 subj_pub_key_list.try_reserve(dice_chain_entries.len())?;
545                 for (i, dice_chain_entry) in dice_chain_entries.iter().enumerate() {
546                     let subject_pub_key =
547                         &dice_chain_entry.payload.subject_pub_key.as_ref().ok_or_else(|| {
548                             ag_err!(InternalError, "subject public key is missing")
549                         })?;
550                     subject_pub_key.validate_cose_key_params()?;
551 
552                     let subject = &dice_chain_entry
553                         .payload
554                         .subject
555                         .as_ref()
556                         .ok_or_else(|| ag_err!(InternalError, "subject is missing"))?;
557                     dice_chain_entry.signature.verify_signature(&[], |sig, data| {
558                         ecdsa.verify_signature(parent_pub_sign_key, data, sig)
559                     })?;
560 
561                     if i != 0
562                         && *parent_subj.ok_or_else(|| {
563                             ag_err!(InvalidCertChain, "parent's subject field is not initialized")
564                         })? != *dice_chain_entry
565                             .payload
566                             .issuer
567                             .as_ref()
568                             .ok_or_else(|| ag_err!(InvalidCertChain, "issuer is missing"))?
569                     {
570                         return Err(ag_err!(
571                             InvalidCertChain,
572                             "parent's subject does not match the current issuer"
573                         ));
574                     }
575 
576                     if subj_pub_key_list.contains(subject_pub_key) {
577                         return Err(ag_err!(InvalidCertChain, "subject public key is repeated"));
578                     }
579 
580                     parent_pub_sign_key = subject_pub_key;
581                     subj_pub_key_list.push(subject_pub_key);
582                     parent_subj = Some(subject);
583                 }
584                 Ok(parent_pub_sign_key.clone())
585             }
586         }
587     }
588 }
589 
590 impl AsCborValue for CertChain {
from_cbor_value(value: Value) -> Result<Self, CoseError>591     fn from_cbor_value(value: Value) -> Result<Self, CoseError> {
592         let mut array = match value {
593             Value::Array(a) if a.len() >= 2 => a,
594             _ => {
595                 return Err(CoseError::UnexpectedItem("_", "array with two or more items"));
596             }
597         };
598         let dice_chain_entries_optional = if array.len() > 2 {
599             let mut dice_chain_entries = Vec::<DiceChainEntry>::new();
600             // TODO: find the correct CoseError to return
601             dice_chain_entries.try_reserve(array.len() - 2).map_err(|_| CoseError::EncodeFailed)?;
602             for i in (2..array.len()).rev() {
603                 let dice_chain_entry_encoded = array.remove(i);
604                 let dice_chain_entry = DiceChainEntry::from_cbor_value(dice_chain_entry_encoded)?;
605                 dice_chain_entries.push(dice_chain_entry);
606             }
607             dice_chain_entries.reverse();
608             Some(dice_chain_entries)
609         } else {
610             None
611         };
612         let root_cose_key = match array.remove(1) {
613             Value::Bytes(root_key_encoded) => {
614                 let cose_key = CoseKey::from_slice(&root_key_encoded)?;
615                 EcVerifyKey::from_cose_key(cose_key)?
616             }
617             _ => {
618                 return Err(CoseError::UnexpectedItem("_", "encoded CoseKey"));
619             }
620         };
621         let version: i32 = match array.remove(0) {
622             Value::Integer(i) => i.try_into()?,
623             _ => {
624                 return Err(CoseError::UnexpectedItem("_", "Integer"));
625             }
626         };
627         Ok(CertChain {
628             version,
629             root_key: root_cose_key,
630             dice_cert_chain: dice_chain_entries_optional,
631         })
632     }
633 
to_cbor_value(mut self) -> Result<Value, CoseError>634     fn to_cbor_value(mut self) -> Result<Value, CoseError> {
635         let mut array = Vec::<Value>::new();
636         array.try_reserve(2).map_err(|_| CoseError::EncodeFailed)?;
637         array.push(Value::Integer(self.version.into()));
638         // Prepare the root key to be encoded in accordance with
639         // Core Deterministic Encoding Requirements [RFC 8949 s4.2.1], as specified in
640         // hardware/interfaces/security/authgraph/aidl/android/hardware/security/authgraph/
641         // ExplicitKeyDiceCertChain.cddl
642         self.root_key.canonicalize_cose_key();
643         array.push(Value::Bytes(self.root_key.get_key().to_vec()?));
644         if let Some(dice_chain_entries) = self.dice_cert_chain {
645             let len = dice_chain_entries.len();
646             array.try_reserve(len).map_err(|_| CoseError::EncodeFailed)?;
647             for dice_chain_entry in dice_chain_entries {
648                 array.push(dice_chain_entry.to_cbor_value()?);
649             }
650         }
651         Ok(Value::Array(array))
652     }
653 }
654 
655 impl CborSerializable for CertChain {}
656 
657 impl AsCborValue for DiceChainEntry {
from_cbor_value(value: Value) -> Result<Self, CoseError>658     fn from_cbor_value(value: Value) -> Result<Self, CoseError> {
659         let signature = CoseSign1::from_cbor_value(value)?;
660         let payload = DiceChainEntryPayloadPartiallyDecoded::from_slice(
661             signature.payload.as_ref().ok_or(CoseError::EncodeFailed)?,
662         )?;
663         Ok(DiceChainEntry { signature, payload })
664     }
665 
to_cbor_value(self) -> Result<Value, CoseError>666     fn to_cbor_value(self) -> Result<Value, CoseError> {
667         // We only need to encode the first field (i.e. `signature`) of `DiceChainEntry` because as
668         // per the CDDL, `DiceChainEntry` is just a CoseSign1. The corresponding Rust struct
669         // contains the additional `payload` field only for the purpose of validation, therefore, it
670         // does not need to be included in the CBOR encoding.
671         self.signature.to_cbor_value()
672     }
673 }
674 
675 impl CborSerializable for DiceChainEntryPayloadPartiallyDecoded {}
676 
677 impl AsCborValue for DiceChainEntryPayloadPartiallyDecoded {
from_cbor_value(value: Value) -> Result<Self, CoseError>678     fn from_cbor_value(value: Value) -> Result<Self, CoseError> {
679         let payload_map = match value {
680             Value::Map(ref map) => map,
681             _ => {
682                 return Err(CoseError::UnexpectedItem("non-map", "map of entries"));
683             }
684         };
685         let mut dice_chain_entry_payload = DiceChainEntryPayloadPartiallyDecoded::default();
686         for (key, val) in payload_map {
687             let key_int: i64 = key
688                 .as_integer()
689                 .ok_or(CoseError::UnexpectedItem("None", "an Integer"))?
690                 .try_into()
691                 .map_err(|_| CoseError::UnexpectedItem("error", "an Integer convertible to i64"))?;
692             match (key_int, val) {
693                 (ISS, Value::Text(issuer)) => match dice_chain_entry_payload.issuer {
694                     None => dice_chain_entry_payload.issuer = Some(issuer.to_string()),
695                     Some(_) => {
696                         return Err(CoseError::UnexpectedItem(
697                             "single entry for issuer",
698                             "repeated entries for issuer",
699                         ));
700                     }
701                 },
702                 (SUB, Value::Text(subject)) => match dice_chain_entry_payload.subject {
703                     None => dice_chain_entry_payload.subject = Some(subject.to_string()),
704                     Some(_) => {
705                         return Err(CoseError::UnexpectedItem(
706                             "single entry for subject",
707                             "repeated entries for subject",
708                         ));
709                     }
710                 },
711                 (SUBJECT_PUBLIC_KEY, Value::Bytes(sp_key_bytes)) => {
712                     match dice_chain_entry_payload.subject_pub_key {
713                         None => {
714                             let cose_key = CoseKey::from_slice(sp_key_bytes)?;
715                             let ec_verify_key = EcVerifyKey::from_cose_key(cose_key)?;
716                             dice_chain_entry_payload.subject_pub_key = Some(ec_verify_key);
717                         }
718                         Some(_) => {
719                             return Err(CoseError::UnexpectedItem(
720                                 "single entry for subject public key",
721                                 "repeated entries for subject public key",
722                             ));
723                         }
724                     }
725                 }
726                 (_k, _v) => {}
727             }
728         }
729         dice_chain_entry_payload.full_map = Some(value);
730         Ok(dice_chain_entry_payload)
731     }
732 
to_cbor_value(self) -> Result<Value, CoseError>733     fn to_cbor_value(self) -> Result<Value, CoseError> {
734         // This is not implemented because Authgraph protocol retrieves an already encoded DICE
735         // chain via `Device` trait and the first field of `DiceChainEntry` has the encoded payload
736         // that is signed.
737         unimplemented!()
738     }
739 }
740 
741 impl CborSerializable for DiceChainEntry {}
742 
743 impl AsCborValue for DiceChainEntryPayload {
from_cbor_value(value: Value) -> Result<Self, CoseError>744     fn from_cbor_value(value: Value) -> Result<Self, CoseError> {
745         let payload_map = match value {
746             Value::Map(map) => map,
747             _ => {
748                 return Err(CoseError::UnexpectedItem("non-map", "map of entries"));
749             }
750         };
751         let mut dice_chain_entry_payload = DiceChainEntryPayload::default();
752         for (key, val) in payload_map {
753             let key_int: i64 = key
754                 .as_integer()
755                 .ok_or(CoseError::UnexpectedItem("None", "an Integer"))?
756                 .try_into()
757                 .map_err(|_| CoseError::UnexpectedItem("error", "an Integer convertible to i64"))?;
758             match (key_int, val) {
759                 (ISS, Value::Text(issuer)) => match dice_chain_entry_payload.issuer {
760                     None => dice_chain_entry_payload.issuer = Some(issuer),
761                     Some(_) => {
762                         return Err(CoseError::UnexpectedItem(
763                             "single entry for issuer",
764                             "repeated entries for issuer",
765                         ));
766                     }
767                 },
768                 (SUB, Value::Text(subject)) => match dice_chain_entry_payload.subject {
769                     None => dice_chain_entry_payload.subject = Some(subject),
770                     Some(_) => {
771                         return Err(CoseError::UnexpectedItem(
772                             "single entry for subject",
773                             "repeated entries for subject",
774                         ));
775                     }
776                 },
777                 (PROFILE_NAME, Value::Text(profile_name)) => {
778                     match dice_chain_entry_payload.profile_name {
779                         None => dice_chain_entry_payload.profile_name = Some(profile_name),
780                         Some(_) => {
781                             return Err(CoseError::UnexpectedItem(
782                                 "single entry for profile name",
783                                 "repeated entries for profile name",
784                             ));
785                         }
786                     }
787                 }
788                 (SUBJECT_PUBLIC_KEY, Value::Bytes(sp_key_bytes)) => {
789                     match dice_chain_entry_payload.subject_pub_key {
790                         None => {
791                             let cose_key = CoseKey::from_slice(&sp_key_bytes)?;
792                             let ec_verify_key = EcVerifyKey::from_cose_key(cose_key)?;
793                             dice_chain_entry_payload.subject_pub_key = Some(ec_verify_key);
794                         }
795                         Some(_) => {
796                             return Err(CoseError::UnexpectedItem(
797                                 "single entry for subject public key",
798                                 "repeated entries for subject public key",
799                             ));
800                         }
801                     }
802                 }
803                 (KEY_USAGE, Value::Bytes(key_usage)) => match dice_chain_entry_payload.key_usage {
804                     None => dice_chain_entry_payload.key_usage = Some(key_usage),
805                     Some(_) => {
806                         return Err(CoseError::UnexpectedItem(
807                             "single entry for key usage",
808                             "repeated entries for key usage",
809                         ));
810                     }
811                 },
812                 (CODE_HASH, Value::Bytes(code_hash)) => match dice_chain_entry_payload.code_hash {
813                     None => dice_chain_entry_payload.code_hash = Some(code_hash),
814                     Some(_) => {
815                         return Err(CoseError::UnexpectedItem(
816                             "single entry for code hash",
817                             "repeated entries for code hash",
818                         ));
819                     }
820                 },
821                 (CODE_DESC, Value::Bytes(code_desc)) => {
822                     match dice_chain_entry_payload.code_descriptor {
823                         None => dice_chain_entry_payload.code_descriptor = Some(code_desc),
824                         Some(_) => {
825                             return Err(CoseError::UnexpectedItem(
826                                 "single or no entry for code descriptors",
827                                 "repeated entries for code descriptor",
828                             ));
829                         }
830                     }
831                 }
832                 (CONFIG_HASH, Value::Bytes(config_hash)) => {
833                     match dice_chain_entry_payload.configuration_hash {
834                         None => dice_chain_entry_payload.configuration_hash = Some(config_hash),
835                         Some(_) => {
836                             return Err(CoseError::UnexpectedItem(
837                                 "single entry for configuration hash",
838                                 "repeated entries for configuration hash",
839                             ));
840                         }
841                     }
842                 }
843                 (CONFIG_DESC, Value::Bytes(config_desc)) => {
844                     match dice_chain_entry_payload.configuration_descriptor {
845                         None => {
846                             let desc = match ConfigurationDescriptor::from_slice(&config_desc) {
847                                 Ok(desc) => ConfigurationDescriptorOrLegacy::Descriptor(desc),
848                                 Err(_) => {
849                                     // Allow for legacy devices that use a different format
850                                     // (b/261647022).
851                                     ConfigurationDescriptorOrLegacy::Legacy(config_desc)
852                                 }
853                             };
854                             dice_chain_entry_payload.configuration_descriptor = Some(desc);
855                         }
856                         Some(_) => {
857                             return Err(CoseError::UnexpectedItem(
858                                 "single entry for configuration descriptor",
859                                 "repeated entries for configuration descriptor",
860                             ));
861                         }
862                     }
863                 }
864                 (AUTHORITY_HASH, Value::Bytes(authority_hash)) => {
865                     match dice_chain_entry_payload.authority_hash {
866                         None => dice_chain_entry_payload.authority_hash = Some(authority_hash),
867                         Some(_) => {
868                             return Err(CoseError::UnexpectedItem(
869                                 "single entry for authority hash",
870                                 "repeated entries for authority hash",
871                             ));
872                         }
873                     }
874                 }
875                 (AUTHORITY_DESC, Value::Bytes(authority_desc)) => {
876                     match dice_chain_entry_payload.authority_descriptor {
877                         None => {
878                             dice_chain_entry_payload.authority_descriptor = Some(authority_desc)
879                         }
880                         Some(_) => {
881                             return Err(CoseError::UnexpectedItem(
882                                 "single or no entry for authority descriptors",
883                                 "repeated entries for authority descriptor",
884                             ));
885                         }
886                     }
887                 }
888                 (MODE, Value::Bytes(mode)) => match dice_chain_entry_payload.mode {
889                     None => dice_chain_entry_payload.mode = Some(mode),
890                     Some(_) => {
891                         return Err(CoseError::UnexpectedItem(
892                             "single entry for mode",
893                             "repeated entries for mode",
894                         ));
895                     }
896                 },
897                 (k, v) => {
898                     dice_chain_entry_payload
899                         .custom_fields
900                         .try_push((k, v))
901                         .map_err(|_| CoseError::EncodeFailed)?;
902                 }
903             }
904         }
905         Ok(dice_chain_entry_payload)
906     }
907 
to_cbor_value(self) -> Result<Value, CoseError>908     fn to_cbor_value(self) -> Result<Value, CoseError> {
909         // This is not implemented because Authgraph protocol retrieves an already encoded DICE
910         // chain via `Device` trait and the first field of `DiceChainEntry` has the encoded payload
911         // that is signed.
912         unimplemented!()
913     }
914 }
915 
916 impl CborSerializable for DiceChainEntryPayload {}
917 
918 impl AsCborValue for ConfigurationDescriptor {
from_cbor_value(value: Value) -> Result<Self, CoseError>919     fn from_cbor_value(value: Value) -> Result<Self, CoseError> {
920         let config_desc_map = match value {
921             Value::Map(map) => map,
922             _ => {
923                 return Err(CoseError::UnexpectedItem("non-map", "map of entries"));
924             }
925         };
926         let mut config_descriptor = ConfigurationDescriptor::default();
927         for (key, val) in config_desc_map {
928             let key_int: i64 = key
929                 .as_integer()
930                 .ok_or(CoseError::UnexpectedItem("None", "an Integer"))?
931                 .try_into()
932                 .map_err(|_| CoseError::UnexpectedItem("error", "an Integer convertible to i64"))?;
933             match (key_int, val) {
934                 (COMPONENT_NAME, Value::Text(comp_name)) => {
935                     config_descriptor.component_name = Some(comp_name);
936                 }
937                 (COMPONENT_VERSION, Value::Text(comp_version)) => {
938                     config_descriptor.component_version =
939                         Some(ComponentVersion::TextVersion(comp_version));
940                 }
941                 (COMPONENT_VERSION, Value::Integer(comp_version)) => {
942                     config_descriptor.component_version =
943                         Some(ComponentVersion::IntVersion(comp_version.try_into().map_err(
944                             |_| CoseError::UnexpectedItem("error", "an Integer convertible to u32"),
945                         )?));
946                 }
947                 (RESETTABLE, Value::Null) => {
948                     config_descriptor.resettable = true;
949                 }
950                 (SECURITY_VERSION, Value::Integer(security_version)) => {
951                     config_descriptor.security_version =
952                         Some(security_version.try_into().map_err(|_| {
953                             CoseError::UnexpectedItem("error", "an Integer convertible to u32")
954                         })?);
955                 }
956                 (RKP_VM_MARKER, Value::Null) => {
957                     config_descriptor.rkp_vm_marker = true;
958                 }
959                 (k, v) => {
960                     config_descriptor
961                         .custom_fields
962                         .try_push((k, v))
963                         .map_err(|_| CoseError::EncodeFailed)?;
964                 }
965             }
966         }
967         Ok(config_descriptor)
968     }
969 
to_cbor_value(self) -> Result<Value, CoseError>970     fn to_cbor_value(self) -> Result<Value, CoseError> {
971         // This is not implemented because Authgraph protocol retrieves an already encoded DICE
972         // chain via `Device` trait and the first field of `DiceChainEntry` has the encoded payload
973         // that is signed.
974         unimplemented!()
975     }
976 }
977 
978 impl CborSerializable for ConfigurationDescriptor {}
979 
980 impl AsCborValue for SaltInput {
from_cbor_value(_value: Value) -> Result<Self, CoseError>981     fn from_cbor_value(_value: Value) -> Result<Self, CoseError> {
982         // This method will never be called, except (maybe) in case of unit testing
983         Err(CoseError::EncodeFailed)
984     }
985 
to_cbor_value(self) -> Result<Value, CoseError>986     fn to_cbor_value(self) -> Result<Value, CoseError> {
987         let mut array = Vec::<Value>::new();
988         array.try_reserve(7).map_err(|_| CoseError::EncodeFailed)?;
989         array.push(Value::Integer(self.source_version.into()));
990         array.push(Value::Bytes(self.sink_ke_pub_key.0.to_vec()?));
991         array.push(Value::Bytes(self.source_ke_pub_key.0.to_vec()?));
992         array.push(Value::Bytes(self.sink_ke_nonce.0.to_vec()));
993         array.push(Value::Bytes(self.source_ke_nonce.0.to_vec()));
994         array.push(Value::Bytes(self.sink_cert_chain.to_vec()?));
995         array.push(Value::Bytes(self.source_cert_chain.to_vec()?));
996         Ok(Value::Array(array))
997     }
998 }
999 
1000 impl CborSerializable for SaltInput {}
1001 
1002 impl AsCborValue for SessionIdInput {
from_cbor_value(_value: Value) -> Result<Self, CoseError>1003     fn from_cbor_value(_value: Value) -> Result<Self, CoseError> {
1004         // This method will never be called, except (maybe) in case of unit testing
1005         Err(CoseError::EncodeFailed)
1006     }
1007 
to_cbor_value(self) -> Result<Value, CoseError>1008     fn to_cbor_value(self) -> Result<Value, CoseError> {
1009         let mut array = Vec::<Value>::new();
1010         array.try_reserve(2).map_err(|_| CoseError::EncodeFailed)?;
1011         array.push(Value::Bytes(self.sink_ke_nonce.0.to_vec()));
1012         array.push(Value::Bytes(self.source_ke_nonce.0.to_vec()));
1013         Ok(Value::Array(array))
1014     }
1015 }
1016 
1017 impl CborSerializable for SessionIdInput {}
1018 
1019 /// Given a `CoseKey` and the set of expected parameters, check if the `CoseKey` contains them.
check_cose_key_params( cose_key: &coset::CoseKey, want_kty: iana::KeyType, want_alg: iana::Algorithm, want_curve: iana::EllipticCurve, err_code: ErrorCode, ) -> Result<(), Error>1020 pub fn check_cose_key_params(
1021     cose_key: &coset::CoseKey,
1022     want_kty: iana::KeyType,
1023     want_alg: iana::Algorithm,
1024     want_curve: iana::EllipticCurve,
1025     err_code: ErrorCode,
1026 ) -> Result<(), Error> {
1027     if cose_key.kty != coset::KeyType::Assigned(want_kty) {
1028         return Err(ag_verr!(err_code, "invalid kty {:?}, expect {want_kty:?}", cose_key.kty));
1029     }
1030     if cose_key.alg != Some(coset::Algorithm::Assigned(want_alg)) {
1031         return Err(ag_verr!(err_code, "invalid alg {:?}, expect {want_alg:?}", cose_key.alg));
1032     }
1033     let curve = cose_key
1034         .params
1035         .iter()
1036         .find_map(|(l, v)| match (l, v) {
1037             (Label::Int(l), Value::Integer(v)) if *l == iana::Ec2KeyParameter::Crv as i64 => {
1038                 Some(*v)
1039             }
1040             _ => None,
1041         })
1042         .ok_or_else(|| ag_verr!(err_code, "no curve"))?;
1043     if curve != cbor::value::Integer::from(want_curve as u64) {
1044         return Err(ag_verr!(err_code, "invalid curve {curve:?}, expect {want_curve:?}"));
1045     }
1046     Ok(())
1047 }
1048 
1049 #[cfg(test)]
1050 mod tests {
1051     use super::*;
1052 
1053     #[test]
test_legacy_open_dice_payload()1054     fn test_legacy_open_dice_payload() {
1055         // Some legacy devices have an open-DICE format config descriptor (b/261647022) rather than
1056         // the format used in the Android RKP HAL.  Ensure that they still parse.
1057         let data = hex::decode(concat!(
1058             "a8",   // 8-map
1059             "01",   // Issuer:
1060             "7828", // 40-tstr
1061             "32336462613837333030633932323934663836333566323738316464346633366362313934383835",
1062             "02",   // Subject:
1063             "7828", // 40-tstr
1064             "33376165616366396230333465643064376166383665306634653431656163356335383134343966",
1065             "3a00474450", // Code Hash(-4670545):
1066             "5840",       // 64-bstr
1067             "3c9aa93a6766f16f5fbd3dfc7e5059b39cdc8aa0cf546cc878d588a69cfcd654",
1068             "2fa509bd6cc14b7160a6bf34545ffdd840f0e91e35b274a7a952b5b0efcff1b0",
1069             "3a00474453", // Configuration Descriptor (-4670548):
1070             "5840",       // 64-bstr
1071             // The RKP HAL expects the following data to match schema:
1072             //
1073             //     { ? -70002 : tstr, ? -70003 : int / tstr, ? -70004 : null,
1074             //       ? -70005 : uint, ? -70006 : null, }
1075             //
1076             // However, the open-DICE spec had:
1077             //     If the configuration input is a hash this field contains the original
1078             //     configuration data that was hashed. If it is not a hash, this field contains the
1079             //     exact 64-byte configuration input value used to compute CDI values."
1080             "e2000000000001508609939b5a4f0f0800000000000000000101000000000000",
1081             "0000000000000000000000000000000000000000000000000000000000000000",
1082             "3a00474454", // Authority Hash (-4670549):
1083             "5840",       // 64-bstr
1084             "4d00da66eabbb2b684641a57e96c8e64d76df1e31ea203bbbb9f439372c1a8ec",
1085             "aa550000aa550000aa550000aa550000aa550000aa550000aa550000aa550000",
1086             "3a00474456", // Mode (-4670551):
1087             "4101",       // 1-bstr value 0x01
1088             "3a00474457", // Subject Public Key (-4670552):
1089             "5871",       // 113-bstr
1090             "a601020338220481022002215830694a8fa269c3375b770ef61d06dec5a78595",
1091             "2ee96db3602b57c50d8fa67f97e874fbd3f5b42e66ac8ead3f3eb3b130f42258",
1092             "301b5574256be9f4770c3325422e53981b1a969387068a51aea68fe98f779be5",
1093             "75ecb077a60106852af654377e56d446a6",
1094             "3a00474458", // Key Usage (-4670553):
1095             "4120"        // 1-bstr value 0x20
1096         ))
1097         .unwrap();
1098 
1099         assert!(DiceChainEntryPayloadPartiallyDecoded::from_slice(&data).is_ok());
1100         assert!(DiceChainEntryPayload::from_slice(&data).is_ok());
1101     }
1102 }
1103