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