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