1 //! Test methods to confirm basic functionality of trait implementations.
2 
3 extern crate alloc;
4 use authgraph_core::key::{
5     AesKey, EcSignKey, EcVerifyKey, EcdhSecret, HmacKey, Identity, Key, Nonce12, PseudoRandKey,
6     CURVE25519_PRIV_KEY_LEN, EXPLICIT_KEY_DICE_CERT_CHAIN_VERSION, IDENTITY_VERSION,
7 };
8 use authgraph_core::keyexchange;
9 use authgraph_core::traits::{
10     AesGcm, Device, EcDh, EcDsa, Hkdf, Hmac, MonotonicClock, Rng, Sha256,
11 };
12 use authgraph_core::{ag_err, error::Error};
13 use authgraph_wire::ErrorCode;
14 use coset::{
15     cbor::Value,
16     iana::{self, EnumI64},
17     Algorithm, CborSerializable, CoseKey, CoseKeyBuilder, CoseSign1Builder, HeaderBuilder,
18     KeyOperation, KeyType, Label,
19 };
20 use std::ffi::CString;
21 
22 /// Test basic [`Rng`] functionality.
test_rng<R: Rng>(rng: &mut R)23 pub fn test_rng<R: Rng>(rng: &mut R) {
24     let mut nonce1 = [0; 16];
25     let mut nonce2 = [0; 16];
26     rng.fill_bytes(&mut nonce1);
27     assert_ne!(nonce1, nonce2, "random value is all zeroes!");
28 
29     rng.fill_bytes(&mut nonce2);
30     assert_ne!(nonce1, nonce2, "two random values match!");
31 }
32 
33 /// Test basic [`MonotonicClock`] functionality.
test_clock<C: MonotonicClock>(clock: &C)34 pub fn test_clock<C: MonotonicClock>(clock: &C) {
35     let t1 = clock.now();
36     let t2 = clock.now();
37     assert!(t2.0 >= t1.0);
38     std::thread::sleep(std::time::Duration::from_millis(400));
39     let t3 = clock.now();
40     assert!(t3.0 > (t1.0 + 200));
41 }
42 
43 /// Test basic [`Sha256`] functionality.
test_sha256<S: Sha256>(digest: &S)44 pub fn test_sha256<S: Sha256>(digest: &S) {
45     let tests: &[(&'static [u8], &'static str)] = &[
46         (b"", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"),
47         (b"abc", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"),
48     ];
49     for (i, (data, want)) in tests.iter().enumerate() {
50         let got = digest.compute_sha256(data).unwrap();
51         assert_eq!(hex::encode(got), *want, "incorrect for case {i}")
52     }
53 }
54 
55 /// Test basic [`Hmac`] functionality.
test_hmac<H: Hmac>(hmac: &H)56 pub fn test_hmac<H: Hmac>(hmac: &H) {
57     struct TestCase {
58         key: &'static str, // 32 bytes, hex-encoded
59         data: &'static [u8],
60         want: &'static str, // 32 bytes, hex-encoded
61     }
62     let tests = [
63         TestCase {
64             key: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
65             data: b"Hello",
66             want: "0adc968519e7e86e9fde625df7037baeab85ea5001583b93b9f576258bf7b20c",
67         },
68         TestCase {
69             key: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
70             data: &[],
71             want: "d38b42096d80f45f826b44a9d5607de72496a415d3f4a1a8c88e3bb9da8dc1cb",
72         },
73     ];
74 
75     for (i, test) in tests.iter().enumerate() {
76         let key = hex::decode(test.key).unwrap();
77         let key = HmacKey(key.try_into().unwrap());
78         let got = hmac.compute_hmac(&key, test.data).unwrap();
79         assert_eq!(hex::encode(&got), test.want, "incorrect for case {i}");
80     }
81 }
82 
83 /// Test basic HKDF functionality.
test_hkdf<H: Hkdf>(h: &H)84 pub fn test_hkdf<H: Hkdf>(h: &H) {
85     struct TestCase {
86         ikm: &'static str,
87         salt: &'static str,
88         info: &'static str,
89         want: &'static str,
90     }
91 
92     let tests = [
93         // RFC 5869 section A.1
94         TestCase {
95             ikm: "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
96             salt: "000102030405060708090a0b0c",
97             info: "f0f1f2f3f4f5f6f7f8f9",
98             want: "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf",
99         },
100         // RFC 5869 section A.2
101         TestCase {
102             ikm: concat!(
103                 "000102030405060708090a0b0c0d0e0f",
104                 "101112131415161718191a1b1c1d1e1f",
105                 "202122232425262728292a2b2c2d2e2f",
106                 "303132333435363738393a3b3c3d3e3f",
107                 "404142434445464748494a4b4c4d4e4f",
108             ),
109             salt: concat!(
110                 "606162636465666768696a6b6c6d6e6f",
111                 "707172737475767778797a7b7c7d7e7f",
112                 "808182838485868788898a8b8c8d8e8f",
113                 "909192939495969798999a9b9c9d9e9f",
114                 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
115             ),
116             info: concat!(
117                 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf",
118                 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf",
119                 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf",
120                 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef",
121                 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
122             ),
123             want: "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c",
124         },
125         TestCase {
126             ikm: "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
127             salt: "",
128             info: "",
129             want: "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d",
130         },
131     ];
132 
133     for (i, test) in tests.iter().enumerate() {
134         let ikm = hex::decode(test.ikm).unwrap();
135         let salt = hex::decode(test.salt).unwrap();
136         let info = hex::decode(test.info).unwrap();
137 
138         let got = hkdf(h, &salt, &ikm, &info).unwrap().0;
139         assert_eq!(hex::encode(got), test.want, "incorrect for case {i}");
140     }
141 }
142 
hkdf(hkdf: &dyn Hkdf, salt: &[u8], ikm: &[u8], info: &[u8]) -> Result<PseudoRandKey, Error>143 fn hkdf(hkdf: &dyn Hkdf, salt: &[u8], ikm: &[u8], info: &[u8]) -> Result<PseudoRandKey, Error> {
144     let ikm = EcdhSecret(ikm.to_vec());
145     let prk = hkdf.extract(salt, &ikm)?;
146     hkdf.expand(&prk, info)
147 }
148 
149 /// Simple test that AES key generation is random.
test_aes_gcm_keygen<A: AesGcm, R: Rng>(aes: &A, rng: &mut R)150 pub fn test_aes_gcm_keygen<A: AesGcm, R: Rng>(aes: &A, rng: &mut R) {
151     let key1 = aes.generate_key(rng).unwrap();
152     let key2 = aes.generate_key(rng).unwrap();
153     assert_ne!(key1.0, key2.0, "identical generated AES keys!");
154 }
155 
156 /// Test basic AES-GCM round-trip functionality.
test_aes_gcm_roundtrip<A: AesGcm, R: Rng>(aes: &A, rng: &mut R)157 pub fn test_aes_gcm_roundtrip<A: AesGcm, R: Rng>(aes: &A, rng: &mut R) {
158     let key = aes.generate_key(rng).unwrap();
159     let msg = b"The Magic Words are Squeamish Ossifrage";
160     let aad = b"the aad";
161     let nonce = Nonce12(*b"1243567890ab");
162     let ct = aes.encrypt(&key, msg, aad, &nonce).unwrap();
163     let pt = aes.decrypt(&key, &ct, aad, &nonce).unwrap();
164     assert_eq!(pt, msg);
165 
166     // Modifying any of the inputs should induce failure.
167     let bad_key = aes.generate_key(rng).unwrap();
168     let bad_aad = b"the AAD";
169     let bad_nonce = Nonce12(*b"ab1243567890");
170     let mut bad_ct = ct.clone();
171     bad_ct[0] ^= 0x01;
172 
173     assert!(aes.decrypt(&bad_key, &ct, aad, &nonce).is_err());
174     assert!(aes.decrypt(&key, &bad_ct, aad, &nonce).is_err());
175     assert!(aes.decrypt(&key, &ct, bad_aad, &nonce).is_err());
176     assert!(aes.decrypt(&key, &ct, aad, &bad_nonce).is_err());
177 }
178 
179 /// Test AES-GCM against test vectors.
test_aes_gcm<A: AesGcm>(aes: &A)180 pub fn test_aes_gcm<A: AesGcm>(aes: &A) {
181     struct TestCase {
182         key: &'static str,
183         iv: &'static str,
184         aad: &'static str,
185         msg: &'static str,
186         ct: &'static str,
187         tag: &'static str,
188     }
189 
190     // Test vectors from Wycheproof aes_gcm_test.json.
191     let aes_gcm_tests = [
192         TestCase {
193             // tcId: 73
194             key: "92ace3e348cd821092cd921aa3546374299ab46209691bc28b8752d17f123c20",
195             iv: "00112233445566778899aabb",
196             aad: "00000000ffffffff",
197             msg: "00010203040506070809",
198             ct: "e27abdd2d2a53d2f136b",
199             tag: "9a4a2579529301bcfb71c78d4060f52c",
200         },
201         TestCase {
202             // tcId: 74
203             key: "29d3a44f8723dc640239100c365423a312934ac80239212ac3df3421a2098123",
204             iv: "00112233445566778899aabb",
205             aad: "aabbccddeeff",
206             msg: "",
207             ct: "",
208             tag: "2a7d77fa526b8250cb296078926b5020",
209         },
210         TestCase {
211             // tcId: 75
212             key: "80ba3192c803ce965ea371d5ff073cf0f43b6a2ab576b208426e11409c09b9b0",
213             iv: "4da5bf8dfd5852c1ea12379d",
214             aad: "",
215             msg: "",
216             ct: "",
217             tag: "4771a7c404a472966cea8f73c8bfe17a",
218         },
219         TestCase {
220             // tcId: 76
221             key: "cc56b680552eb75008f5484b4cb803fa5063ebd6eab91f6ab6aef4916a766273",
222             iv: "99e23ec48985bccdeeab60f1",
223             aad: "",
224             msg: "2a",
225             ct: "06",
226             tag: "633c1e9703ef744ffffb40edf9d14355",
227         },
228         TestCase {
229             // tcId: 77
230             key: "51e4bf2bad92b7aff1a4bc05550ba81df4b96fabf41c12c7b00e60e48db7e152",
231             iv: "4f07afedfdc3b6c2361823d3",
232             aad: "",
233             msg: "be3308f72a2c6aed",
234             ct: "cf332a12fdee800b",
235             tag: "602e8d7c4799d62c140c9bb834876b09",
236         },
237         TestCase {
238             // tcId: 78
239             key: "67119627bd988eda906219e08c0d0d779a07d208ce8a4fe0709af755eeec6dcb",
240             iv: "68ab7fdbf61901dad461d23c",
241             aad: "",
242             msg: "51f8c1f731ea14acdb210a6d973e07",
243             ct: "43fc101bff4b32bfadd3daf57a590e",
244             tag: "ec04aacb7148a8b8be44cb7eaf4efa69",
245         },
246     ];
247     for (i, test) in aes_gcm_tests.iter().enumerate() {
248         let key = AesKey(hex::decode(test.key).unwrap().try_into().unwrap());
249         let nonce = Nonce12(hex::decode(test.iv).unwrap().try_into().unwrap());
250         let aad = hex::decode(test.aad).unwrap();
251         let msg = hex::decode(test.msg).unwrap();
252         let want_hex = test.ct.to_owned() + test.tag;
253 
254         let got = aes.encrypt(&key, &msg, &aad, &nonce).unwrap();
255         assert_eq!(hex::encode(&got), want_hex, "incorrect for case {i}");
256 
257         let got_pt = aes.decrypt(&key, &got, &aad, &nonce).unwrap();
258         assert_eq!(hex::encode(got_pt), test.msg, "incorrect decrypt for case {i}");
259     }
260 }
261 
262 /// Test `EcDh` impl for ECDH.
test_ecdh<E: EcDh>(ecdh: &E)263 pub fn test_ecdh<E: EcDh>(ecdh: &E) {
264     let key1 = ecdh.generate_key().unwrap();
265     let key2 = ecdh.generate_key().unwrap();
266     let secret12 = ecdh.compute_shared_secret(&key1.priv_key, &key2.pub_key).unwrap();
267     let secret21 = ecdh.compute_shared_secret(&key2.priv_key, &key1.pub_key).unwrap();
268     assert_eq!(secret12.0, secret21.0);
269 }
270 
271 /// Test `EcDsa` impl for verify.
test_ecdsa<E: EcDsa>(ecdsa: &E)272 pub fn test_ecdsa<E: EcDsa>(ecdsa: &E) {
273     let ed25519_key = coset::CoseKeyBuilder::new_okp_key()
274         .param(iana::OkpKeyParameter::Crv as i64, Value::from(iana::EllipticCurve::Ed25519 as u64))
275         .param(
276             iana::OkpKeyParameter::X as i64,
277             Value::from(
278                 hex::decode("7d4d0e7f6153a69b6242b522abbee685fda4420f8834b108c3bdae369ef549fa")
279                     .unwrap(),
280             ),
281         )
282         .algorithm(coset::iana::Algorithm::EdDSA)
283         .build();
284     let p256_key = CoseKeyBuilder::new_ec2_pub_key(
285         iana::EllipticCurve::P_256,
286         hex::decode("2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838").unwrap(),
287         hex::decode("c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e").unwrap(),
288     )
289     .algorithm(iana::Algorithm::ES256)
290     .build();
291     let p384_key = CoseKeyBuilder::new_ec2_pub_key(
292         iana::EllipticCurve::P_384,
293         hex::decode("2da57dda1089276a543f9ffdac0bff0d976cad71eb7280e7d9bfd9fee4bdb2f20f47ff888274389772d98cc5752138aa").unwrap(),
294         hex::decode("4b6d054d69dcf3e25ec49df870715e34883b1836197d76f8ad962e78f6571bbc7407b0d6091f9e4d88f014274406174f").unwrap(),
295     )
296     .algorithm(iana::Algorithm::ES384)
297     .build();
298 
299     struct TestCase {
300         key: EcVerifyKey,
301         msg: &'static str, // hex
302         sig: &'static str, // hex
303     }
304     let tests = [
305         // Wycheproof: eddsa_test.json tcId=5
306         TestCase {
307             key: EcVerifyKey::Ed25519(ed25519_key),
308             msg: "313233343030",
309             sig: "657c1492402ab5ce03e2c3a7f0384d051b9cf3570f1207fc78c1bcc98c281c2bf0cf5b3a289976458a1be6277a5055545253b45b07dcc1abd96c8b989c00f301",
310         },
311         // Wycheproof: ecdsa_secp256r1_sha256_test.json tcId=3
312         // Signature converted to R | S form
313         TestCase {
314             key: EcVerifyKey::P256(p256_key),
315             msg: "313233343030",
316             sig: "2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db",
317         },
318         // Wycheproof: ecdsa_secp384r1_sha384_test.json tcId=3
319         // Signature converted to R | S form
320         TestCase {
321             key: EcVerifyKey::P384(p384_key),
322             msg: "313233343030",
323             sig: "12b30abef6b5476fe6b612ae557c0425661e26b44b1bfe19daf2ca28e3113083ba8e4ae4cc45a0320abd3394f1c548d7e7bf25603e2d07076ff30b7a2abec473da8b11c572b35fc631991d5de62ddca7525aaba89325dfd04fecc47bff426f82",
324         },
325     ];
326 
327     for (i, test) in tests.iter().enumerate() {
328         let sig = hex::decode(test.sig).unwrap();
329         let msg = hex::decode(test.msg).unwrap();
330 
331         assert!(ecdsa.verify_signature(&test.key, &msg, &sig).is_ok(), "failed for case {i}");
332 
333         // A modified message should not verify.
334         let mut bad_msg = msg.clone();
335         bad_msg[0] ^= 0x01;
336         assert!(
337             ecdsa.verify_signature(&test.key, &bad_msg, &sig).is_err(),
338             "unexpected success for case {i}"
339         );
340 
341         // A modified signature should not verify.
342         let mut bad_sig = sig;
343         bad_sig[0] ^= 0x01;
344         assert!(
345             ecdsa.verify_signature(&test.key, &msg, &bad_sig).is_err(),
346             "unexpected success for case {i}"
347         );
348     }
349 }
350 
351 /// Test EdDSA signing and verification for Ed25519.
test_ed25519_round_trip<E: EcDsa>(ecdsa: &E)352 pub fn test_ed25519_round_trip<E: EcDsa>(ecdsa: &E) {
353     // Wycheproof: eddsa_test.json
354     let ed25519_pub_key = coset::CoseKeyBuilder::new_okp_key()
355         .param(iana::OkpKeyParameter::Crv as i64, Value::from(iana::EllipticCurve::Ed25519 as u64))
356         .param(
357             iana::OkpKeyParameter::X as i64,
358             Value::from(
359                 hex::decode("7d4d0e7f6153a69b6242b522abbee685fda4420f8834b108c3bdae369ef549fa")
360                     .unwrap(),
361             ),
362         )
363         .algorithm(coset::iana::Algorithm::EdDSA)
364         .build();
365     let ed25519_verify_key = EcVerifyKey::Ed25519(ed25519_pub_key);
366     let ed25519_sign_key = EcSignKey::Ed25519(
367         hex::decode("add4bb8103785baf9ac534258e8aaf65f5f1adb5ef5f3df19bb80ab989c4d64b")
368             .unwrap()
369             .try_into()
370             .unwrap(),
371     );
372     test_ecdsa_round_trip(ecdsa, &ed25519_verify_key, &ed25519_sign_key)
373 }
374 
375 // It's not possible to include a generic test for `EcDsa::sign` with NIST curves because the
376 // format of the `EcSignKey` is implementation-dependent.  The following tests are therefore
377 // specific to implementations (such as the reference implementation) which store private key
378 // material for NIST EC curves in the form of DER-encoded `ECPrivateKey` structures.
379 
380 /// Test EdDSA signing and verification for P-256.
test_p256_round_trip<E: EcDsa>(ecdsa: &E)381 pub fn test_p256_round_trip<E: EcDsa>(ecdsa: &E) {
382     // Generated with: openssl ecparam --name prime256v1 -genkey -noout -out p256-privkey.pem
383     //
384     // Contents (der2ascii -pem -i p256-privkey.pem):
385     //
386     // SEQUENCE {
387     //   INTEGER { 1 }
388     //   OCTET_STRING { `0733c93e22240ba783739f9e2bd4b4065bfcecac9268362587dc814da5b84080` }
389     //   [0] {
390     //     # secp256r1
391     //     OBJECT_IDENTIFIER { 1.2.840.10045.3.1.7 }
392     //   }
393     //   [1] {
394     //     BIT_STRING { `00` `04`
395     //                  `2b31afcfab1aba1f8850d7ecfa235e14d60a1ef5b2a75b93ccaa4322de094477`
396     //                  `21ba560a040bab8c922edd32a279e9d3ac991f1507d4b4beded5fd80298b7cee`
397     //     }
398     //   }
399     // }
400     let p256_priv_key = hex::decode("307702010104200733c93e22240ba783739f9e2bd4b4065bfcecac9268362587dc814da5b84080a00a06082a8648ce3d030107a144034200042b31afcfab1aba1f8850d7ecfa235e14d60a1ef5b2a75b93ccaa4322de09447721ba560a040bab8c922edd32a279e9d3ac991f1507d4b4beded5fd80298b7cee").unwrap();
401     let p256_pub_key = CoseKeyBuilder::new_ec2_pub_key(
402         iana::EllipticCurve::P_256,
403         hex::decode("2b31afcfab1aba1f8850d7ecfa235e14d60a1ef5b2a75b93ccaa4322de094477").unwrap(),
404         hex::decode("21ba560a040bab8c922edd32a279e9d3ac991f1507d4b4beded5fd80298b7cee").unwrap(),
405     )
406     .algorithm(iana::Algorithm::ES256)
407     .build();
408 
409     test_ecdsa_round_trip(ecdsa, &EcVerifyKey::P256(p256_pub_key), &EcSignKey::P256(p256_priv_key))
410 }
411 
412 /// Test EdDSA signing and verification for P-384.
test_p384_round_trip<E: EcDsa>(ecdsa: &E)413 pub fn test_p384_round_trip<E: EcDsa>(ecdsa: &E) {
414     // Generated with: openssl ecparam --name secp384r1 -genkey -noout -out p384-privkey.pem
415     //
416     // Contents (der2ascii -pem -i p384-privkey.pem):
417     //
418     // SEQUENCE {
419     //   INTEGER { 1 }
420     //   OCTET_STRING { `81a9d9e43e47dbbf3e7e4e9e06d467b1b126603969bf80f0ade1e1aea9ed534884b81d86ece0bbd41d541bf6d22f6be2` }
421     //   [0] {
422     //     # secp384r1
423     //     OBJECT_IDENTIFIER { 1.3.132.0.34 }
424     //   }
425     //   [1] {
426     //     BIT_STRING { `00` `04`
427     //                  `fdf3f076a6e98047baf68a44d319f0200a03c4807eb0e869db88e1c9758ba96647fecbe0456c475feeb67021e053de93`
428     //                  `478ad58e972d52af0ea5911fe24f82448e9c073263aaa49117c451e787eced645796e50b24ee2c632a6c77e6d430ad01`
429     //     }
430     //   }
431     // }
432     let p384_priv_key = hex::decode("3081a4020101043081a9d9e43e47dbbf3e7e4e9e06d467b1b126603969bf80f0ade1e1aea9ed534884b81d86ece0bbd41d541bf6d22f6be2a00706052b81040022a16403620004fdf3f076a6e98047baf68a44d319f0200a03c4807eb0e869db88e1c9758ba96647fecbe0456c475feeb67021e053de93478ad58e972d52af0ea5911fe24f82448e9c073263aaa49117c451e787eced645796e50b24ee2c632a6c77e6d430ad01").unwrap();
433     let p384_pub_key = CoseKeyBuilder::new_ec2_pub_key(
434         iana::EllipticCurve::P_384,
435         hex::decode("fdf3f076a6e98047baf68a44d319f0200a03c4807eb0e869db88e1c9758ba96647fecbe0456c475feeb67021e053de93").unwrap(),
436         hex::decode("478ad58e972d52af0ea5911fe24f82448e9c073263aaa49117c451e787eced645796e50b24ee2c632a6c77e6d430ad01").unwrap(),
437     )
438     .algorithm(iana::Algorithm::ES384)
439         .build();
440 
441     test_ecdsa_round_trip(ecdsa, &EcVerifyKey::P384(p384_pub_key), &EcSignKey::P384(p384_priv_key))
442 }
443 
test_ecdsa_round_trip<E: EcDsa>(ecdsa: &E, verify_key: &EcVerifyKey, sign_key: &EcSignKey)444 fn test_ecdsa_round_trip<E: EcDsa>(ecdsa: &E, verify_key: &EcVerifyKey, sign_key: &EcSignKey) {
445     let msg = b"This is the message";
446     let sig = ecdsa.sign(sign_key, msg).unwrap();
447 
448     assert!(ecdsa.verify_signature(verify_key, msg, &sig).is_ok());
449 
450     // A modified message should not verify.
451     let mut bad_msg = *msg;
452     bad_msg[0] ^= 0x01;
453     assert!(ecdsa.verify_signature(verify_key, &bad_msg, &sig).is_err());
454 
455     // A modified signature should not verify.
456     let mut bad_sig = sig;
457     bad_sig[0] ^= 0x01;
458     assert!(ecdsa.verify_signature(verify_key, msg, &bad_sig).is_err());
459 }
460 
461 /// Test `create` method of key exchange protocol
test_key_exchange_create(source: &mut keyexchange::AuthGraphParticipant)462 pub fn test_key_exchange_create(source: &mut keyexchange::AuthGraphParticipant) {
463     let create_result = source.create();
464     assert!(create_result.is_ok());
465 
466     // TODO: Add more tests on the values returned from `create` (some of these tests may
467     // need to be done in `libauthgraph_boringssl_test`)
468     // 1. dh_key is not None,
469     // 2. dh_key->pub key is in CoseKey encoding (e..g purpose)
470     // 3. dh_key->priv_key arc can be decrypted from the pbk from the AgDevice, the IV attached
471     //    in the unprotected headers, nonce for key exchange and the payload type = SecretKey
472     //    attached in the protected headers
473     // 5. identity decodes to a CBOR vector and the second element is a bstr of
474     //    CoseKey
475     // 6. nonce is same as the nonce attached in the protected header of the arc in
476     //    #3 above
477     // 7. ECDH can be performed from the dh_key returned from this method
478 }
479 
480 /// Test `init` method of key exchange protocol
test_key_exchange_init( source: &mut keyexchange::AuthGraphParticipant, sink: &mut keyexchange::AuthGraphParticipant, )481 pub fn test_key_exchange_init(
482     source: &mut keyexchange::AuthGraphParticipant,
483     sink: &mut keyexchange::AuthGraphParticipant,
484 ) {
485     let keyexchange::SessionInitiationInfo {
486         ke_key: Key { pub_key: peer_ke_pub_key, .. },
487         identity: peer_identity,
488         nonce: peer_nonce,
489         version: peer_version,
490     } = source.create().unwrap();
491 
492     let init_result =
493         sink.init(&peer_ke_pub_key.unwrap(), &peer_identity, &peer_nonce, peer_version);
494     assert!(init_result.is_ok())
495     // TODO: add more tests on init_result
496 }
497 
498 /// Test `finish` method of key exchange protocol
test_key_exchange_finish( source: &mut keyexchange::AuthGraphParticipant, sink: &mut keyexchange::AuthGraphParticipant, )499 pub fn test_key_exchange_finish(
500     source: &mut keyexchange::AuthGraphParticipant,
501     sink: &mut keyexchange::AuthGraphParticipant,
502 ) {
503     let keyexchange::SessionInitiationInfo {
504         ke_key: Key { pub_key: p1_ke_pub_key, arc_from_pbk: p1_ke_priv_key_arc },
505         identity: p1_identity,
506         nonce: p1_nonce,
507         version: p1_version,
508     } = source.create().unwrap();
509 
510     let keyexchange::KeInitResult {
511         session_init_info:
512             keyexchange::SessionInitiationInfo {
513                 ke_key: Key { pub_key: p2_ke_pub_key, .. },
514                 identity: p2_identity,
515                 nonce: p2_nonce,
516                 version: p2_version,
517             },
518         session_info: keyexchange::SessionInfo { session_id_signature: p2_signature, .. },
519     } = sink.init(p1_ke_pub_key.as_ref().unwrap(), &p1_identity, &p1_nonce, p1_version).unwrap();
520 
521     let finish_result = source.finish(
522         &p2_ke_pub_key.unwrap(),
523         &p2_identity,
524         &p2_signature,
525         &p2_nonce,
526         p2_version,
527         Key { pub_key: p1_ke_pub_key, arc_from_pbk: p1_ke_priv_key_arc },
528     );
529     assert!(finish_result.is_ok())
530     // TODO: add more tests on finish_result
531 }
532 
533 /// Test `authentication_complete` method of key exchange protocol
test_key_exchange_auth_complete( source: &mut keyexchange::AuthGraphParticipant, sink: &mut keyexchange::AuthGraphParticipant, )534 pub fn test_key_exchange_auth_complete(
535     source: &mut keyexchange::AuthGraphParticipant,
536     sink: &mut keyexchange::AuthGraphParticipant,
537 ) {
538     let keyexchange::SessionInitiationInfo {
539         ke_key: Key { pub_key: p1_ke_pub_key, arc_from_pbk: p1_ke_priv_key_arc },
540         identity: p1_identity,
541         nonce: p1_nonce,
542         version: p1_version,
543     } = source.create().unwrap();
544 
545     let keyexchange::KeInitResult {
546         session_init_info:
547             keyexchange::SessionInitiationInfo {
548                 ke_key: Key { pub_key: p2_ke_pub_key, .. },
549                 identity: p2_identity,
550                 nonce: p2_nonce,
551                 version: p2_version,
552             },
553         session_info:
554             keyexchange::SessionInfo {
555                 shared_keys: p2_shared_keys,
556                 session_id: p2_session_id,
557                 session_id_signature: p2_signature,
558             },
559     } = sink.init(p1_ke_pub_key.as_ref().unwrap(), &p1_identity, &p1_nonce, p1_version).unwrap();
560 
561     let keyexchange::SessionInfo {
562         shared_keys: _p1_shared_keys,
563         session_id: p1_session_id,
564         session_id_signature: p1_signature,
565     } = source
566         .finish(
567             &p2_ke_pub_key.unwrap(),
568             &p2_identity,
569             &p2_signature,
570             &p2_nonce,
571             p2_version,
572             Key { pub_key: p1_ke_pub_key, arc_from_pbk: p1_ke_priv_key_arc },
573         )
574         .unwrap();
575 
576     let auth_complete_result = sink.authentication_complete(&p1_signature, p2_shared_keys);
577     assert!(auth_complete_result.is_ok());
578     assert_eq!(p1_session_id, p2_session_id)
579     // TODO: add more tests on finish_result, and encrypt/decrypt using the agreed keys
580 }
581 
582 /// Verify that the key exchange protocol works when source's version is higher than sink's version
583 /// and that the negotiated version is sink's version
test_ke_with_newer_source( source_newer: &mut keyexchange::AuthGraphParticipant, sink: &mut keyexchange::AuthGraphParticipant, )584 pub fn test_ke_with_newer_source(
585     source_newer: &mut keyexchange::AuthGraphParticipant,
586     sink: &mut keyexchange::AuthGraphParticipant,
587 ) {
588     let source_version = source_newer.get_version();
589     let sink_version = sink.get_version();
590     assert!(source_version > sink_version);
591 
592     let keyexchange::SessionInitiationInfo {
593         ke_key: Key { pub_key: p1_ke_pub_key, arc_from_pbk: p1_ke_priv_key_arc },
594         identity: p1_identity,
595         nonce: p1_nonce,
596         version: p1_version,
597     } = source_newer.create().unwrap();
598 
599     let keyexchange::KeInitResult {
600         session_init_info:
601             keyexchange::SessionInitiationInfo {
602                 ke_key: Key { pub_key: p2_ke_pub_key, .. },
603                 identity: p2_identity,
604                 nonce: p2_nonce,
605                 version: p2_version,
606             },
607         session_info:
608             keyexchange::SessionInfo {
609                 shared_keys: p2_shared_keys,
610                 session_id: p2_session_id,
611                 session_id_signature: p2_signature,
612             },
613     } = sink.init(p1_ke_pub_key.as_ref().unwrap(), &p1_identity, &p1_nonce, p1_version).unwrap();
614     assert_eq!(p2_version, sink_version);
615 
616     let keyexchange::SessionInfo {
617         shared_keys: _p1_shared_keys,
618         session_id: p1_session_id,
619         session_id_signature: p1_signature,
620     } = source_newer
621         .finish(
622             &p2_ke_pub_key.unwrap(),
623             &p2_identity,
624             &p2_signature,
625             &p2_nonce,
626             p2_version,
627             Key { pub_key: p1_ke_pub_key, arc_from_pbk: p1_ke_priv_key_arc },
628         )
629         .unwrap();
630 
631     let auth_complete_result = sink.authentication_complete(&p1_signature, p2_shared_keys);
632     assert!(auth_complete_result.is_ok());
633     assert_eq!(p1_session_id, p2_session_id)
634 }
635 
636 /// Verify that the key exchange protocol works when sink's version is higher than sources's version
637 /// and that the negotiated version is source's version
test_ke_with_newer_sink( source: &mut keyexchange::AuthGraphParticipant, sink_newer: &mut keyexchange::AuthGraphParticipant, )638 pub fn test_ke_with_newer_sink(
639     source: &mut keyexchange::AuthGraphParticipant,
640     sink_newer: &mut keyexchange::AuthGraphParticipant,
641 ) {
642     let source_version = source.get_version();
643     let sink_version = sink_newer.get_version();
644     assert!(sink_version > source_version);
645 
646     let keyexchange::SessionInitiationInfo {
647         ke_key: Key { pub_key: p1_ke_pub_key, arc_from_pbk: p1_ke_priv_key_arc },
648         identity: p1_identity,
649         nonce: p1_nonce,
650         version: p1_version,
651     } = source.create().unwrap();
652 
653     let keyexchange::KeInitResult {
654         session_init_info:
655             keyexchange::SessionInitiationInfo {
656                 ke_key: Key { pub_key: p2_ke_pub_key, .. },
657                 identity: p2_identity,
658                 nonce: p2_nonce,
659                 version: p2_version,
660             },
661         session_info:
662             keyexchange::SessionInfo {
663                 shared_keys: p2_shared_keys,
664                 session_id: p2_session_id,
665                 session_id_signature: p2_signature,
666             },
667     } = sink_newer
668         .init(p1_ke_pub_key.as_ref().unwrap(), &p1_identity, &p1_nonce, p1_version)
669         .unwrap();
670     assert_eq!(p2_version, source_version);
671 
672     let keyexchange::SessionInfo {
673         shared_keys: _p1_shared_keys,
674         session_id: p1_session_id,
675         session_id_signature: p1_signature,
676     } = source
677         .finish(
678             &p2_ke_pub_key.unwrap(),
679             &p2_identity,
680             &p2_signature,
681             &p2_nonce,
682             p2_version,
683             Key { pub_key: p1_ke_pub_key, arc_from_pbk: p1_ke_priv_key_arc },
684         )
685         .unwrap();
686 
687     let auth_complete_result = sink_newer.authentication_complete(&p1_signature, p2_shared_keys);
688     assert!(auth_complete_result.is_ok());
689     assert_eq!(p1_session_id, p2_session_id)
690 }
691 
692 /// Verify that the key exchange protocol prevents version downgrade attacks when both source and
693 /// sink have versions newer than version 1
test_ke_for_version_downgrade( source: &mut keyexchange::AuthGraphParticipant, sink: &mut keyexchange::AuthGraphParticipant, )694 pub fn test_ke_for_version_downgrade(
695     source: &mut keyexchange::AuthGraphParticipant,
696     sink: &mut keyexchange::AuthGraphParticipant,
697 ) {
698     let source_version = source.get_version();
699     let sink_version = sink.get_version();
700     assert!(source_version > 1);
701     assert!(sink_version > 1);
702 
703     let keyexchange::SessionInitiationInfo {
704         ke_key: Key { pub_key: p1_ke_pub_key, arc_from_pbk: p1_ke_priv_key_arc },
705         identity: p1_identity,
706         nonce: p1_nonce,
707         version: _p1_version,
708     } = source.create().unwrap();
709 
710     let downgraded_version = 1;
711 
712     let keyexchange::KeInitResult {
713         session_init_info:
714             keyexchange::SessionInitiationInfo {
715                 ke_key: Key { pub_key: p2_ke_pub_key, .. },
716                 identity: p2_identity,
717                 nonce: p2_nonce,
718                 version: p2_version,
719             },
720         session_info:
721             keyexchange::SessionInfo {
722                 shared_keys: _p2_shared_keys,
723                 session_id: _p2_session_id,
724                 session_id_signature: p2_signature,
725             },
726     } = sink
727         .init(p1_ke_pub_key.as_ref().unwrap(), &p1_identity, &p1_nonce, downgraded_version)
728         .unwrap();
729     assert_eq!(p2_version, downgraded_version);
730 
731     let finish_result = source.finish(
732         &p2_ke_pub_key.unwrap(),
733         &p2_identity,
734         &p2_signature,
735         &p2_nonce,
736         p2_version,
737         Key { pub_key: p1_ke_pub_key, arc_from_pbk: p1_ke_priv_key_arc },
738     );
739     // `finish` should fail with signature verification error
740     match finish_result {
741         Ok(_) => panic!("protocol downgrade prevention is broken"),
742         Err(e) => match e {
743             Error(ErrorCode::InvalidSignature, _) => {}
744             _ => panic!("wrong error on protocol downgrade"),
745         },
746     }
747 }
748 
749 /// Verify that the key exchange protocol prevents replay attacks
test_ke_for_replay( source: &mut keyexchange::AuthGraphParticipant, sink: &mut keyexchange::AuthGraphParticipant, )750 pub fn test_ke_for_replay(
751     source: &mut keyexchange::AuthGraphParticipant,
752     sink: &mut keyexchange::AuthGraphParticipant,
753 ) {
754     // Round 1 of the protocol
755     let keyexchange::SessionInitiationInfo {
756         ke_key: Key { pub_key: p1_ke_pub_key, arc_from_pbk: p1_ke_priv_key_arc },
757         identity: p1_identity,
758         nonce: p1_nonce,
759         version: p1_version,
760     } = source.create().unwrap();
761 
762     let keyexchange::KeInitResult {
763         session_init_info:
764             keyexchange::SessionInitiationInfo {
765                 ke_key: Key { pub_key: p2_ke_pub_key, .. },
766                 identity: p2_identity,
767                 nonce: p2_nonce,
768                 version: p2_version,
769             },
770         session_info:
771             keyexchange::SessionInfo {
772                 shared_keys: p2_shared_keys,
773                 session_id: p2_session_id,
774                 session_id_signature: p2_signature,
775             },
776     } = sink.init(p1_ke_pub_key.as_ref().unwrap(), &p1_identity, &p1_nonce, p1_version).unwrap();
777 
778     let keyexchange::SessionInfo {
779         shared_keys: _p1_shared_keys,
780         session_id: p1_session_id,
781         session_id_signature: p1_signature,
782     } = source
783         .finish(
784             &p2_ke_pub_key.clone().unwrap(),
785             &p2_identity,
786             &p2_signature,
787             &p2_nonce,
788             p2_version,
789             Key { pub_key: p1_ke_pub_key.clone(), arc_from_pbk: p1_ke_priv_key_arc.clone() },
790         )
791         .unwrap();
792 
793     let auth_complete_result = sink.authentication_complete(&p1_signature, p2_shared_keys.clone());
794     assert!(auth_complete_result.is_ok());
795     assert_eq!(p1_session_id, p2_session_id);
796 
797     // An attacker may try to run the key exchange protocol again, but this time, they try to
798     // replay the inputs of the previous protocol run, ignoring the outputs of `create` and `init`
799     // of the existing protocol run. In such cases, `finish` and `authentication_complete` should
800     // fail as per the measures against replay attacks.
801     source.create().unwrap();
802 
803     sink.init(p1_ke_pub_key.as_ref().unwrap(), &p1_identity, &p1_nonce, p1_version).unwrap();
804 
805     let finish_result = source.finish(
806         &p2_ke_pub_key.unwrap(),
807         &p2_identity,
808         &p2_signature,
809         &p2_nonce,
810         p2_version,
811         Key { pub_key: p1_ke_pub_key, arc_from_pbk: p1_ke_priv_key_arc },
812     );
813     match finish_result {
814         Ok(_) => panic!("replay prevention is broken in finish"),
815         Err(e) if e.0 == ErrorCode::InvalidKeKey => {}
816         Err(e) => panic!("got error {e:?}, wanted ErrorCode::InvalidKeKey"),
817     }
818 
819     let auth_complete_result = sink.authentication_complete(&p1_signature, p2_shared_keys);
820     match auth_complete_result {
821         Ok(_) => panic!("replay prevention is broken in authentication_complete"),
822         Err(e) if e.0 == ErrorCode::InvalidSharedKeyArcs => {}
823         Err(e) => panic!("got error {e:?}, wanted ErrorCode::InvalidSharedKeyArcs"),
824     }
825 }
826 
827 /// Test the logic of decoding and validating `Identity` using the test data created with open-dice.
validate_identity<E: EcDsa>(ecdsa: &E)828 pub fn validate_identity<E: EcDsa>(ecdsa: &E) {
829     for cert_chain_len in 0..6 {
830         let (pvt_sign_key, identity) =
831             create_identity(cert_chain_len).expect("error in creating identity");
832         // decode identity
833         let decoded_identity =
834             Identity::from_slice(&identity).expect("error in decoding the identity");
835         // validate identity
836         let verify_key =
837             decoded_identity.validate(ecdsa).expect("error in validating the identity");
838         // re-encode the decoded identity
839         decoded_identity.to_vec().expect("failed to serialize Identity");
840 
841         // sign using the private signing key derived from the leaf CDI attest
842         let data = b"test string to sign";
843 
844         let protected =
845             HeaderBuilder::new().algorithm(verify_key.get_cose_sign_algorithm()).build();
846         let cose_sign1 = CoseSign1Builder::new()
847             .protected(protected)
848             .payload(data.to_vec())
849             .try_create_signature(&[], |input| ecdsa.sign(&pvt_sign_key, input))
850             .expect("error creating the signature")
851             .build();
852         // verify the signature with the public signing key extracted from the leaf certificate in
853         // the DICE chain
854         cose_sign1
855             .verify_signature(&[], |signature, data| {
856                 ecdsa.verify_signature(&verify_key, data, signature)
857             })
858             .expect("error in verifying the signature");
859     }
860 }
861 
862 /// Construct a CBOR serialized `Identity` with a `CertChain` containing the given number of
863 /// certificate entries, using open-dice. The maximum length supported by this method is 5.
864 /// Return the private signing key corresponding to the public signing key.
create_identity(dice_chain_len: usize) -> Result<(EcSignKey, Vec<u8>), Error>865 pub fn create_identity(dice_chain_len: usize) -> Result<(EcSignKey, Vec<u8>), Error> {
866     const UDS: [u8; diced_open_dice::CDI_SIZE] = [
867         0x1d, 0xa5, 0xea, 0x90, 0x47, 0xfc, 0xb5, 0xf6, 0x47, 0x12, 0xd3, 0x65, 0x9c, 0xf2, 0x00,
868         0xe0, 0x06, 0xf7, 0xe8, 0x9e, 0x2f, 0xd0, 0x94, 0x7f, 0xc9, 0x9a, 0x9d, 0x40, 0xf7, 0xce,
869         0x13, 0x21,
870     ];
871     let pvt_key_seed = diced_open_dice::derive_cdi_private_key_seed(&UDS).unwrap();
872     let (root_pub_key, pvt_key) = diced_open_dice::keypair_from_seed(pvt_key_seed.as_array())
873         .expect("failed to create key pair from seed.");
874     let root_pub_cose_key = CoseKey {
875         kty: KeyType::Assigned(iana::KeyType::OKP),
876         alg: Some(Algorithm::Assigned(iana::Algorithm::EdDSA)),
877         key_ops: vec![KeyOperation::Assigned(iana::KeyOperation::Verify)].into_iter().collect(),
878         params: vec![
879             (
880                 Label::Int(iana::Ec2KeyParameter::Crv.to_i64()),
881                 iana::EllipticCurve::Ed25519.to_i64().into(),
882             ),
883             (Label::Int(iana::Ec2KeyParameter::X.to_i64()), Value::Bytes(root_pub_key.to_vec())),
884         ],
885         ..Default::default()
886     };
887     let root_pub_cose_key_bstr =
888         root_pub_cose_key.to_vec().expect("failed to serialize root pub key");
889 
890     if dice_chain_len == 0 {
891         let cert_chain = Value::Array(vec![
892             Value::Integer(EXPLICIT_KEY_DICE_CERT_CHAIN_VERSION.into()),
893             Value::Bytes(root_pub_cose_key_bstr.clone()),
894         ]);
895         let identity = Value::Array(vec![
896             Value::Integer(IDENTITY_VERSION.into()),
897             Value::Bytes(cert_chain.to_vec()?),
898         ]);
899         let pvt_key: [u8; CURVE25519_PRIV_KEY_LEN] =
900             pvt_key.as_array()[0..CURVE25519_PRIV_KEY_LEN].try_into().map_err(|e| {
901                 ag_err!(InternalError, "error in constructing the private signing key {:?}", e)
902             })?;
903         return Ok((EcSignKey::Ed25519(pvt_key), identity.to_vec()?));
904     }
905 
906     const CODE_HASH_PVMFW: [u8; diced_open_dice::HASH_SIZE] = [
907         0x16, 0x48, 0xf2, 0x55, 0x53, 0x23, 0xdd, 0x15, 0x2e, 0x83, 0x38, 0xc3, 0x64, 0x38, 0x63,
908         0x26, 0x0f, 0xcf, 0x5b, 0xd1, 0x3a, 0xd3, 0x40, 0x3e, 0x23, 0xf8, 0x34, 0x4c, 0x6d, 0xa2,
909         0xbe, 0x25, 0x1c, 0xb0, 0x29, 0xe8, 0xc3, 0xfb, 0xb8, 0x80, 0xdc, 0xb1, 0xd2, 0xb3, 0x91,
910         0x4d, 0xd3, 0xfb, 0x01, 0x0f, 0xe4, 0xe9, 0x46, 0xa2, 0xc0, 0x26, 0x57, 0x5a, 0xba, 0x30,
911         0xf7, 0x15, 0x98, 0x14,
912     ];
913     const AUTHORITY_HASH_PVMFW: [u8; diced_open_dice::HASH_SIZE] = [
914         0xf9, 0x00, 0x9d, 0xc2, 0x59, 0x09, 0xe0, 0xb6, 0x98, 0xbd, 0xe3, 0x97, 0x4a, 0xcb, 0x3c,
915         0xe7, 0x6b, 0x24, 0xc3, 0xe4, 0x98, 0xdd, 0xa9, 0x6a, 0x41, 0x59, 0x15, 0xb1, 0x23, 0xe6,
916         0xc8, 0xdf, 0xfb, 0x52, 0xb4, 0x52, 0xc1, 0xb9, 0x61, 0xdd, 0xbc, 0x5b, 0x37, 0x0e, 0x12,
917         0x12, 0xb2, 0xfd, 0xc1, 0x09, 0xb0, 0xcf, 0x33, 0x81, 0x4c, 0xc6, 0x29, 0x1b, 0x99, 0xea,
918         0xae, 0xfd, 0xaa, 0x0d,
919     ];
920     const HIDDEN_PVMFW: [u8; diced_open_dice::HIDDEN_SIZE] = [
921         0xa2, 0x01, 0xd0, 0xc0, 0xaa, 0x75, 0x3c, 0x06, 0x43, 0x98, 0x6c, 0xc3, 0x5a, 0xb5, 0x5f,
922         0x1f, 0x0f, 0x92, 0x44, 0x3b, 0x0e, 0xd4, 0x29, 0x75, 0xe3, 0xdb, 0x36, 0xda, 0xc8, 0x07,
923         0x97, 0x4d, 0xff, 0xbc, 0x6a, 0xa4, 0x8a, 0xef, 0xc4, 0x7f, 0xf8, 0x61, 0x7d, 0x51, 0x4d,
924         0x2f, 0xdf, 0x7e, 0x8c, 0x3d, 0xa3, 0xfc, 0x63, 0xd4, 0xd4, 0x74, 0x8a, 0xc4, 0x14, 0x45,
925         0x83, 0x6b, 0x12, 0x7e,
926     ];
927     let comp_name_1 = CString::new("Protected VM firmware").expect("CString::new failed");
928     let config_values_1 = diced_open_dice::DiceConfigValues {
929         component_name: Some(&comp_name_1),
930         component_version: Some(1),
931         resettable: true,
932         ..Default::default()
933     };
934     let config_descriptor_1 = diced_open_dice::retry_bcc_format_config_descriptor(&config_values_1)
935         .expect("failed to format config descriptor");
936     let input_values_1 = diced_open_dice::InputValues::new(
937         CODE_HASH_PVMFW,
938         diced_open_dice::Config::Descriptor(config_descriptor_1.as_slice()),
939         AUTHORITY_HASH_PVMFW,
940         diced_open_dice::DiceMode::kDiceModeDebug,
941         HIDDEN_PVMFW,
942     );
943     let (cdi_values_1, cert_1) = diced_open_dice::retry_dice_main_flow(&UDS, &UDS, &input_values_1)
944         .expect("Failed to run first main flow");
945 
946     if dice_chain_len == 1 {
947         let cert_chain = Value::Array(vec![
948             Value::Integer(EXPLICIT_KEY_DICE_CERT_CHAIN_VERSION.into()),
949             Value::Bytes(root_pub_cose_key_bstr.clone()),
950             Value::from_slice(&cert_1).expect("failed to deserialize the certificate into CBOR"),
951         ]);
952         let identity = Value::Array(vec![
953             Value::Integer(IDENTITY_VERSION.into()),
954             Value::Bytes(cert_chain.to_vec()?),
955         ]);
956         let pvt_key_seed =
957             diced_open_dice::derive_cdi_private_key_seed(&cdi_values_1.cdi_attest).unwrap();
958         let (_, pvt_key) = diced_open_dice::keypair_from_seed(pvt_key_seed.as_array())
959             .expect("failed to create key pair from seed.");
960         let pvt_key: [u8; CURVE25519_PRIV_KEY_LEN] =
961             pvt_key.as_array()[0..CURVE25519_PRIV_KEY_LEN].try_into().map_err(|e| {
962                 ag_err!(InternalError, "error in constructing the private signing key {:?}", e)
963             })?;
964         return Ok((EcSignKey::Ed25519(pvt_key), identity.to_vec()?));
965     }
966 
967     const CODE_HASH_SERVICE_VM: [u8; diced_open_dice::HASH_SIZE] = [
968         0xa4, 0x0c, 0xcb, 0xc1, 0xbf, 0xfa, 0xcc, 0xfd, 0xeb, 0xf4, 0xfc, 0x43, 0x83, 0x7f, 0x46,
969         0x8d, 0xd8, 0xd8, 0x14, 0xc1, 0x96, 0x14, 0x1f, 0x6e, 0xb3, 0xa0, 0xd9, 0x56, 0xb3, 0xbf,
970         0x2f, 0xfa, 0x88, 0x70, 0x11, 0x07, 0x39, 0xa4, 0xd2, 0xa9, 0x6b, 0x18, 0x28, 0xe8, 0x29,
971         0x20, 0x49, 0x0f, 0xbb, 0x8d, 0x08, 0x8c, 0xc6, 0x54, 0xe9, 0x71, 0xd2, 0x7e, 0xa4, 0xfe,
972         0x58, 0x7f, 0xd3, 0xc7,
973     ];
974     const AUTHORITY_HASH_SERVICE_VM: [u8; diced_open_dice::HASH_SIZE] = [
975         0xb2, 0x69, 0x05, 0x48, 0x56, 0xb5, 0xfa, 0x55, 0x6f, 0xac, 0x56, 0xd9, 0x02, 0x35, 0x2b,
976         0xaa, 0x4c, 0xba, 0x28, 0xdd, 0x82, 0x3a, 0x86, 0xf5, 0xd4, 0xc2, 0xf1, 0xf9, 0x35, 0x7d,
977         0xe4, 0x43, 0x13, 0xbf, 0xfe, 0xd3, 0x36, 0xd8, 0x1c, 0x12, 0x78, 0x5c, 0x9c, 0x3e, 0xf6,
978         0x66, 0xef, 0xab, 0x3d, 0x0f, 0x89, 0xa4, 0x6f, 0xc9, 0x72, 0xee, 0x73, 0x43, 0x02, 0x8a,
979         0xef, 0xbc, 0x05, 0x98,
980     ];
981     const HIDDEN_SERVICE_VM: [u8; diced_open_dice::HIDDEN_SIZE] = [
982         0x5b, 0x3f, 0xc9, 0x6b, 0xe3, 0x95, 0x59, 0x40, 0x5e, 0x64, 0xe5, 0x64, 0x3f, 0xfd, 0x21,
983         0x09, 0x9d, 0xf3, 0xcd, 0xc7, 0xa4, 0x2a, 0xe2, 0x97, 0xdd, 0xe2, 0x4f, 0xb0, 0x7d, 0x7e,
984         0xf5, 0x8e, 0xd6, 0x4d, 0x84, 0x25, 0x54, 0x41, 0x3f, 0x8f, 0x78, 0x64, 0x1a, 0x51, 0x27,
985         0x9d, 0x55, 0x8a, 0xe9, 0x90, 0x35, 0xab, 0x39, 0x80, 0x4b, 0x94, 0x40, 0x84, 0xa2, 0xfd,
986         0x73, 0xeb, 0x35, 0x7a,
987     ];
988 
989     let comp_name_2 = CString::new("VM entry").expect("CString::new failed");
990     let config_values_2 = diced_open_dice::DiceConfigValues {
991         component_name: Some(&comp_name_2),
992         component_version: Some(12),
993         resettable: true,
994         ..Default::default()
995     };
996     let config_descriptor_2 = diced_open_dice::retry_bcc_format_config_descriptor(&config_values_2)
997         .expect("failed to format config descriptor");
998 
999     let input_values_2 = diced_open_dice::InputValues::new(
1000         CODE_HASH_SERVICE_VM,
1001         diced_open_dice::Config::Descriptor(config_descriptor_2.as_slice()),
1002         AUTHORITY_HASH_SERVICE_VM,
1003         diced_open_dice::DiceMode::kDiceModeDebug,
1004         HIDDEN_SERVICE_VM,
1005     );
1006 
1007     let (cdi_values_2, cert_2) = diced_open_dice::retry_dice_main_flow(
1008         &cdi_values_1.cdi_attest,
1009         &cdi_values_1.cdi_seal,
1010         &input_values_2,
1011     )
1012     .expect("Failed to run first main flow");
1013 
1014     if dice_chain_len == 2 {
1015         let cert_chain = Value::Array(vec![
1016             Value::Integer(EXPLICIT_KEY_DICE_CERT_CHAIN_VERSION.into()),
1017             Value::Bytes(root_pub_cose_key_bstr.clone()),
1018             Value::from_slice(&cert_1).expect("failed to deserialize the certificate into CBOR"),
1019             Value::from_slice(&cert_2).expect("failed to deserialize the certificate into CBOR"),
1020         ]);
1021         let identity = Value::Array(vec![
1022             Value::Integer(IDENTITY_VERSION.into()),
1023             Value::Bytes(cert_chain.to_vec()?),
1024         ]);
1025         let pvt_key_seed =
1026             diced_open_dice::derive_cdi_private_key_seed(&cdi_values_2.cdi_attest).unwrap();
1027         let (_, pvt_key) = diced_open_dice::keypair_from_seed(pvt_key_seed.as_array())
1028             .expect("failed to create key pair from seed.");
1029         let pvt_key: [u8; CURVE25519_PRIV_KEY_LEN] =
1030             pvt_key.as_array()[0..CURVE25519_PRIV_KEY_LEN].try_into().map_err(|e| {
1031                 ag_err!(InternalError, "error in constructing the private signing key {:?}", e)
1032             })?;
1033         return Ok((EcSignKey::Ed25519(pvt_key), identity.to_vec()?));
1034     }
1035 
1036     const CODE_HASH_PAYLOAD: [u8; diced_open_dice::HASH_SIZE] = [
1037         0x08, 0x78, 0xc2, 0x5b, 0xe7, 0xea, 0x3d, 0x62, 0x70, 0x22, 0xd9, 0x1c, 0x4f, 0x3c, 0x2e,
1038         0x2f, 0x0f, 0x97, 0xa4, 0x6f, 0x6d, 0xd5, 0xe6, 0x4a, 0x6d, 0xbe, 0x34, 0x2e, 0x56, 0x04,
1039         0xaf, 0xef, 0x74, 0x3f, 0xec, 0xb8, 0x44, 0x11, 0xf4, 0x2f, 0x05, 0xb2, 0x06, 0xa3, 0x0e,
1040         0x75, 0xb7, 0x40, 0x9a, 0x4c, 0x58, 0xab, 0x96, 0xe7, 0x07, 0x97, 0x07, 0x86, 0x5c, 0xa1,
1041         0x42, 0x12, 0xf0, 0x34,
1042     ];
1043     const AUTHORITY_HASH_PAYLOAD: [u8; diced_open_dice::HASH_SIZE] = [
1044         0xc7, 0x97, 0x5b, 0xa9, 0x9e, 0xbf, 0x0b, 0xeb, 0xe7, 0x7f, 0x69, 0x8f, 0x8e, 0xcf, 0x04,
1045         0x7d, 0x2c, 0x0f, 0x4d, 0xbe, 0xcb, 0xf5, 0xf1, 0x4c, 0x1d, 0x1c, 0xb7, 0x44, 0xdf, 0xf8,
1046         0x40, 0x90, 0x09, 0x65, 0xab, 0x01, 0x34, 0x3e, 0xc2, 0xc4, 0xf7, 0xa2, 0x3a, 0x5c, 0x4e,
1047         0x76, 0x4f, 0x42, 0xa8, 0x6c, 0xc9, 0xf1, 0x7b, 0x12, 0x80, 0xa4, 0xef, 0xa2, 0x4d, 0x72,
1048         0xa1, 0x21, 0xe2, 0x47,
1049     ];
1050 
1051     let comp_name_3 = CString::new("Payload").expect("CString::new failed");
1052     let config_values_3 = diced_open_dice::DiceConfigValues {
1053         component_name: Some(&comp_name_3),
1054         component_version: Some(12),
1055         resettable: true,
1056         ..Default::default()
1057     };
1058     let config_descriptor_3 = diced_open_dice::retry_bcc_format_config_descriptor(&config_values_3)
1059         .expect("failed to format config descriptor");
1060 
1061     let input_values_3 = diced_open_dice::InputValues::new(
1062         CODE_HASH_PAYLOAD,
1063         diced_open_dice::Config::Descriptor(config_descriptor_3.as_slice()),
1064         AUTHORITY_HASH_PAYLOAD,
1065         diced_open_dice::DiceMode::kDiceModeDebug,
1066         [0u8; diced_open_dice::HIDDEN_SIZE],
1067     );
1068 
1069     let (cdi_values_3, cert_3) = diced_open_dice::retry_dice_main_flow(
1070         &cdi_values_2.cdi_attest,
1071         &cdi_values_2.cdi_seal,
1072         &input_values_3,
1073     )
1074     .expect("Failed to run first main flow");
1075 
1076     if dice_chain_len == 3 {
1077         let cert_chain = Value::Array(vec![
1078             Value::Integer(EXPLICIT_KEY_DICE_CERT_CHAIN_VERSION.into()),
1079             Value::Bytes(root_pub_cose_key_bstr.clone()),
1080             Value::from_slice(&cert_1).expect("failed to deserialize the certificate into CBOR"),
1081             Value::from_slice(&cert_2).expect("failed to deserialize the certificate into CBOR"),
1082             Value::from_slice(&cert_3).expect("failed to deserialize the certificate into CBOR"),
1083         ]);
1084         let identity = Value::Array(vec![
1085             Value::Integer(IDENTITY_VERSION.into()),
1086             Value::Bytes(cert_chain.to_vec()?),
1087         ]);
1088         let pvt_key_seed =
1089             diced_open_dice::derive_cdi_private_key_seed(&cdi_values_3.cdi_attest).unwrap();
1090         let (_, pvt_key) = diced_open_dice::keypair_from_seed(pvt_key_seed.as_array())
1091             .expect("failed to create key pair from seed.");
1092         let pvt_key: [u8; CURVE25519_PRIV_KEY_LEN] =
1093             pvt_key.as_array()[0..CURVE25519_PRIV_KEY_LEN].try_into().map_err(|e| {
1094                 ag_err!(InternalError, "error in constructing the private signing key {:?}", e)
1095             })?;
1096         return Ok((EcSignKey::Ed25519(pvt_key), identity.to_vec()?));
1097     }
1098 
1099     const CODE_HASH_APK1: [u8; diced_open_dice::HASH_SIZE] = [
1100         0x41, 0x92, 0x0d, 0xd0, 0xf5, 0x60, 0xe3, 0x69, 0x26, 0x7f, 0xb8, 0xbc, 0x12, 0x3a, 0xd1,
1101         0x95, 0x1d, 0xb8, 0x9a, 0x9c, 0x3a, 0x3f, 0x01, 0xbf, 0xa8, 0xd9, 0x6d, 0xe9, 0x90, 0x30,
1102         0x1d, 0x0b, 0xaf, 0xef, 0x74, 0x3f, 0xec, 0xb8, 0x44, 0x11, 0xf4, 0x2f, 0x05, 0xb2, 0x06,
1103         0xa3, 0x0e, 0x75, 0xb7, 0x40, 0x9a, 0x4c, 0x58, 0xab, 0x96, 0xe7, 0x07, 0x97, 0x07, 0x86,
1104         0x5c, 0xa1, 0x42, 0x12,
1105     ];
1106     const AUTHORITY_HASH_APK1: [u8; diced_open_dice::HASH_SIZE] = [
1107         0xe3, 0xd9, 0x1c, 0xf5, 0x6f, 0xee, 0x73, 0x40, 0x3d, 0x95, 0x59, 0x67, 0xea, 0x5d, 0x01,
1108         0xfd, 0x25, 0x9d, 0x5c, 0x88, 0x94, 0x3a, 0xc6, 0xd7, 0xa9, 0xdc, 0x4c, 0x60, 0x81, 0xbe,
1109         0x2b, 0x74, 0x40, 0x90, 0x09, 0x65, 0xab, 0x01, 0x34, 0x3e, 0xc2, 0xc4, 0xf7, 0xa2, 0x3a,
1110         0x5c, 0x4e, 0x76, 0x4f, 0x42, 0xa8, 0x6c, 0xc9, 0xf1, 0x7b, 0x12, 0x80, 0xa4, 0xef, 0xa2,
1111         0x4d, 0x72, 0xa1, 0x21,
1112     ];
1113 
1114     let comp_name_4 = CString::new("APK1").expect("CString::new failed");
1115     let config_values_4 = diced_open_dice::DiceConfigValues {
1116         component_name: Some(&comp_name_4),
1117         component_version: Some(12),
1118         resettable: true,
1119         ..Default::default()
1120     };
1121     let config_descriptor_4 = diced_open_dice::retry_bcc_format_config_descriptor(&config_values_4)
1122         .expect("failed to format config descriptor");
1123 
1124     let input_values_4 = diced_open_dice::InputValues::new(
1125         CODE_HASH_APK1,
1126         diced_open_dice::Config::Descriptor(config_descriptor_4.as_slice()),
1127         AUTHORITY_HASH_APK1,
1128         diced_open_dice::DiceMode::kDiceModeDebug,
1129         [0u8; diced_open_dice::HIDDEN_SIZE],
1130     );
1131 
1132     let (cdi_values_4, cert_4) = diced_open_dice::retry_dice_main_flow(
1133         &cdi_values_3.cdi_attest,
1134         &cdi_values_3.cdi_seal,
1135         &input_values_4,
1136     )
1137     .expect("Failed to run first main flow");
1138 
1139     if dice_chain_len == 4 {
1140         let cert_chain = Value::Array(vec![
1141             Value::Integer(EXPLICIT_KEY_DICE_CERT_CHAIN_VERSION.into()),
1142             Value::Bytes(root_pub_cose_key_bstr.clone()),
1143             Value::from_slice(&cert_1).expect("failed to deserialize the certificate into CBOR"),
1144             Value::from_slice(&cert_2).expect("failed to deserialize the certificate into CBOR"),
1145             Value::from_slice(&cert_3).expect("failed to deserialize the certificate into CBOR"),
1146             Value::from_slice(&cert_4).expect("failed to deserialize the certificate into CBOR"),
1147         ]);
1148         let identity = Value::Array(vec![
1149             Value::Integer(IDENTITY_VERSION.into()),
1150             Value::Bytes(cert_chain.to_vec()?),
1151         ]);
1152         let pvt_key_seed =
1153             diced_open_dice::derive_cdi_private_key_seed(&cdi_values_4.cdi_attest).unwrap();
1154         let (_, pvt_key) = diced_open_dice::keypair_from_seed(pvt_key_seed.as_array())
1155             .expect("failed to create key pair from seed.");
1156         let pvt_key: [u8; CURVE25519_PRIV_KEY_LEN] =
1157             pvt_key.as_array()[0..CURVE25519_PRIV_KEY_LEN].try_into().map_err(|e| {
1158                 ag_err!(InternalError, "error in constructing the private signing key {:?}", e)
1159             })?;
1160         return Ok((EcSignKey::Ed25519(pvt_key), identity.to_vec()?));
1161     }
1162 
1163     const CODE_HASH_APEX1: [u8; diced_open_dice::HASH_SIZE] = [
1164         0x52, 0x93, 0x2b, 0xb0, 0x8d, 0xec, 0xdf, 0x54, 0x1f, 0x5c, 0x10, 0x9d, 0x17, 0xce, 0x7f,
1165         0xac, 0xb0, 0x2b, 0xe2, 0x99, 0x05, 0x7d, 0xa3, 0x9b, 0xa6, 0x3e, 0xf9, 0x99, 0xa2, 0xea,
1166         0xd4, 0xd9, 0x1d, 0x0b, 0xaf, 0xef, 0x74, 0x3f, 0xec, 0xb8, 0x44, 0x11, 0xf4, 0x2f, 0x05,
1167         0xb2, 0x06, 0xa3, 0x0e, 0x75, 0xb7, 0x40, 0x9a, 0x4c, 0x58, 0xab, 0x96, 0xe7, 0x07, 0x97,
1168         0x07, 0x86, 0x5c, 0xa1,
1169     ];
1170     const AUTHORITY_HASH_APEX1: [u8; diced_open_dice::HASH_SIZE] = [
1171         0xd1, 0xfc, 0x3d, 0x5f, 0xa0, 0x5f, 0x02, 0xd0, 0x83, 0x9b, 0x0e, 0x32, 0xc2, 0x27, 0x09,
1172         0x12, 0xcc, 0xfc, 0x42, 0xf6, 0x0d, 0xf4, 0x7d, 0xc8, 0x80, 0x1a, 0x64, 0x25, 0xa7, 0xfa,
1173         0x4a, 0x37, 0x2b, 0x74, 0x40, 0x90, 0x09, 0x65, 0xab, 0x01, 0x34, 0x3e, 0xc2, 0xc4, 0xf7,
1174         0xa2, 0x3a, 0x5c, 0x4e, 0x76, 0x4f, 0x42, 0xa8, 0x6c, 0xc9, 0xf1, 0x7b, 0x12, 0x80, 0xa4,
1175         0xef, 0xa2, 0x4d, 0x72,
1176     ];
1177 
1178     let comp_name_5 = CString::new("APEX1").expect("CString::new failed");
1179     let config_values_5 = diced_open_dice::DiceConfigValues {
1180         component_name: Some(&comp_name_5),
1181         component_version: Some(12),
1182         resettable: true,
1183         ..Default::default()
1184     };
1185     let config_descriptor_5 = diced_open_dice::retry_bcc_format_config_descriptor(&config_values_5)
1186         .expect("failed to format config descriptor");
1187 
1188     let input_values_5 = diced_open_dice::InputValues::new(
1189         CODE_HASH_APEX1,
1190         diced_open_dice::Config::Descriptor(config_descriptor_5.as_slice()),
1191         AUTHORITY_HASH_APEX1,
1192         diced_open_dice::DiceMode::kDiceModeDebug,
1193         [0u8; diced_open_dice::HIDDEN_SIZE],
1194     );
1195 
1196     let (cdi_values_5, cert_5) = diced_open_dice::retry_dice_main_flow(
1197         &cdi_values_4.cdi_attest,
1198         &cdi_values_4.cdi_seal,
1199         &input_values_5,
1200     )
1201     .expect("Failed to run first main flow");
1202 
1203     if dice_chain_len == 5 {
1204         let cert_chain = Value::Array(vec![
1205             Value::Integer(EXPLICIT_KEY_DICE_CERT_CHAIN_VERSION.into()),
1206             Value::Bytes(root_pub_cose_key_bstr.clone()),
1207             Value::from_slice(&cert_1).expect("failed to deserialize the certificate into CBOR"),
1208             Value::from_slice(&cert_2).expect("failed to deserialize the certificate into CBOR"),
1209             Value::from_slice(&cert_3).expect("failed to deserialize the certificate into CBOR"),
1210             Value::from_slice(&cert_4).expect("failed to deserialize the certificate into CBOR"),
1211             Value::from_slice(&cert_5).expect("failed to deserialize the certificate into CBOR"),
1212         ]);
1213         let identity = Value::Array(vec![
1214             Value::Integer(IDENTITY_VERSION.into()),
1215             Value::Bytes(cert_chain.to_vec()?),
1216         ]);
1217         let pvt_key_seed =
1218             diced_open_dice::derive_cdi_private_key_seed(&cdi_values_5.cdi_attest).unwrap();
1219         let (_, pvt_key) = diced_open_dice::keypair_from_seed(pvt_key_seed.as_array())
1220             .expect("failed to create key pair from seed.");
1221         let pvt_key: [u8; CURVE25519_PRIV_KEY_LEN] =
1222             pvt_key.as_array()[0..CURVE25519_PRIV_KEY_LEN].try_into().map_err(|e| {
1223                 ag_err!(InternalError, "error in constructing the private signing key {:?}", e)
1224             })?;
1225         return Ok((EcSignKey::Ed25519(pvt_key), identity.to_vec()?));
1226     }
1227     Err(ag_err!(InternalError, "this method supports the maximum length of 5 for a DICE chain"))
1228 }
1229 
1230 /// Add a smoke test for `get_identity` in the `Device` trait, to ensure that the returned Identity
1231 /// passes a set of validation.
test_get_identity<D: Device, E: EcDsa>(ag_device: &D, ecdsa: &E)1232 pub fn test_get_identity<D: Device, E: EcDsa>(ag_device: &D, ecdsa: &E) {
1233     let (_, identity) = ag_device.get_identity().unwrap();
1234     identity.validate(ecdsa).unwrap();
1235 }
1236 
1237 /// Test validation of a sample BCC identity.
test_example_identity_validate<E: EcDsa>(ecdsa: &E)1238 pub fn test_example_identity_validate<E: EcDsa>(ecdsa: &E) {
1239     let mut hex_data =
1240         std::str::from_utf8(include_bytes!("../testdata/sample_identity.hex")).unwrap().to_string();
1241     hex_data.retain(|c| !c.is_whitespace());
1242     let data = hex::decode(hex_data).unwrap();
1243     let identity = Identity::from_slice(&data).expect("identity data did not decode");
1244     identity.validate(ecdsa).expect("identity did not validate");
1245 }
1246