1 // Copyright 2022, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Test methods to confirm basic functionality of trait implementations.
16 
17 use core::convert::TryInto;
18 use kmr_common::crypto::{
19     aes, des, hmac, Aes, AesCmac, Ckdf, ConstTimeEq, Des, Hkdf, Hmac, MonotonicClock, Rng, Sha256,
20     SymmetricOperation,
21 };
22 use kmr_common::{keyblob, keyblob::SlotPurpose};
23 use kmr_ta::device::{SigningAlgorithm, SigningKey, SigningKeyType};
24 use kmr_wire::{keymint::Digest, rpc};
25 use std::collections::HashMap;
26 use x509_cert::der::{Decode, Encode};
27 
28 /// Test basic [`Rng`] functionality.
test_rng<R: Rng>(rng: &mut R)29 pub fn test_rng<R: Rng>(rng: &mut R) {
30     let u1 = rng.next_u64();
31     let u2 = rng.next_u64();
32     assert_ne!(u1, u2);
33 
34     let mut b1 = [0u8; 16];
35     let mut b2 = [0u8; 16];
36     rng.fill_bytes(&mut b1);
37     rng.fill_bytes(&mut b2);
38     assert_ne!(b1, b2);
39 
40     rng.add_entropy(&b1);
41     rng.add_entropy(&[]);
42     rng.fill_bytes(&mut b1);
43     assert_ne!(b1, b2);
44 }
45 
46 /// Test basic [`ConstTimeEq`] functionality. Does not test the key constant-time property though.
test_eq<E: ConstTimeEq>(comparator: E)47 pub fn test_eq<E: ConstTimeEq>(comparator: E) {
48     let b0 = [];
49     let b1 = [0u8, 1u8, 2u8];
50     let b2 = [1u8, 1u8, 2u8];
51     let b3 = [0u8, 1u8, 3u8];
52     let b4 = [0u8, 1u8, 2u8, 3u8];
53     let b5 = [42; 4096];
54     let mut b6 = [42; 4096];
55     b6[4095] = 43;
56     assert!(comparator.eq(&b0, &b0));
57     assert!(comparator.eq(&b5, &b5));
58 
59     assert!(comparator.ne(&b0, &b1));
60     assert!(comparator.ne(&b0, &b2));
61     assert!(comparator.ne(&b0, &b3));
62     assert!(comparator.ne(&b0, &b4));
63     assert!(comparator.ne(&b0, &b5));
64     assert!(comparator.eq(&b1, &b1));
65     assert!(comparator.ne(&b1, &b2));
66     assert!(comparator.ne(&b1, &b3));
67     assert!(comparator.ne(&b1, &b4));
68     assert!(comparator.ne(&b5, &b6));
69 }
70 
71 /// Test basic [`MonotonicClock`] functionality.
test_clock<C: MonotonicClock>(clock: C)72 pub fn test_clock<C: MonotonicClock>(clock: C) {
73     let t1 = clock.now();
74     let t2 = clock.now();
75     assert!(t2.0 >= t1.0);
76     std::thread::sleep(std::time::Duration::from_millis(400));
77     let t3 = clock.now();
78     assert!(t3.0 > (t1.0 + 200));
79 }
80 
81 /// Test basic HKDF functionality.
test_hkdf<H: Hmac>(hmac: H)82 pub fn test_hkdf<H: Hmac>(hmac: H) {
83     struct TestCase {
84         ikm: &'static str,
85         salt: &'static str,
86         info: &'static str,
87         out_len: usize,
88         want: &'static str,
89     }
90 
91     const HKDF_TESTS: &[TestCase] = &[
92         // RFC 5869 section A.1
93         TestCase {
94             ikm: "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
95             salt: "000102030405060708090a0b0c",
96             info: "f0f1f2f3f4f5f6f7f8f9",
97             out_len: 42,
98             want: concat!(
99                 "3cb25f25faacd57a90434f64d0362f2a",
100                 "2d2d0a90cf1a5a4c5db02d56ecc4c5bf",
101                 "34007208d5b887185865",
102             ),
103         },
104         // RFC 5869 section A.2
105         TestCase {
106             ikm: concat!(
107                 "000102030405060708090a0b0c0d0e0f",
108                 "101112131415161718191a1b1c1d1e1f",
109                 "202122232425262728292a2b2c2d2e2f",
110                 "303132333435363738393a3b3c3d3e3f",
111                 "404142434445464748494a4b4c4d4e4f",
112             ),
113             salt: concat!(
114                 "606162636465666768696a6b6c6d6e6f",
115                 "707172737475767778797a7b7c7d7e7f",
116                 "808182838485868788898a8b8c8d8e8f",
117                 "909192939495969798999a9b9c9d9e9f",
118                 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
119             ),
120             info: concat!(
121                 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf",
122                 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf",
123                 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf",
124                 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef",
125                 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
126             ),
127             out_len: 82,
128             want: concat!(
129                 "b11e398dc80327a1c8e7f78c596a4934",
130                 "4f012eda2d4efad8a050cc4c19afa97c",
131                 "59045a99cac7827271cb41c65e590e09",
132                 "da3275600c2f09b8367793a9aca3db71",
133                 "cc30c58179ec3e87c14c01d5c1f3434f",
134                 "1d87",
135             ),
136         },
137         // RFC 5869 section A.3
138         TestCase {
139             ikm: "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
140             salt: "",
141             info: "",
142             out_len: 42,
143             want: concat!(
144                 "8da4e775a563c18f715f802a063c5a31",
145                 "b8a11f5c5ee1879ec3454e5f3c738d2d",
146                 "9d201395faa4b61a96c8",
147             ),
148         },
149     ];
150 
151     for (i, test) in HKDF_TESTS.iter().enumerate() {
152         let ikm = hex::decode(test.ikm).unwrap();
153         let salt = hex::decode(test.salt).unwrap();
154         let info = hex::decode(test.info).unwrap();
155 
156         let got = hmac.hkdf(&salt, &ikm, &info, test.out_len).unwrap();
157         assert_eq!(hex::encode(got), test.want, "incorrect HKDF result for case {}", i);
158     }
159 }
160 
161 /// Test basic [`Hmac`] functionality.
test_hmac<H: Hmac>(hmac: H)162 pub fn test_hmac<H: Hmac>(hmac: H) {
163     struct TestCase {
164         digest: Digest,
165         tag_size: usize,
166         key: &'static [u8],
167         data: &'static [u8],
168         expected_mac: &'static str,
169     }
170 
171     const HMAC_TESTS : &[TestCase] = &[
172         TestCase {
173             digest: Digest::Sha256,
174             tag_size:     32,
175             data:         b"Hello",
176             key:          b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
177             expected_mac: "e0ff02553d9a619661026c7aa1ddf59b7b44eac06a9908ff9e19961d481935d4",
178         },
179         TestCase {
180             digest: Digest::Sha512,
181             tag_size:     64,
182             data:         b"Hello",
183             key:          b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
184             expected_mac: "481e10d823ba64c15b94537a3de3f253c16642451ac45124dd4dde120bf1e5c15e55487d55ba72b43039f235226e7954cd5854b30abc4b5b53171a4177047c9b",
185         },
186         // empty data
187         TestCase {
188             digest: Digest::Sha256,
189             tag_size:     32,
190             data:         &[],
191             key:          b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
192             expected_mac: "07eff8b326b7798c9ccfcbdbe579489ac785a7995a04618b1a2813c26744777d",
193         },
194 
195         // Test cases from RFC 4231 Section 4.2
196         TestCase {
197             digest: Digest::Sha224,
198             tag_size: 224/8,
199             key: &[0x0b; 20],
200             data: b"Hi There",
201             expected_mac: concat!(
202                 "896fb1128abbdf196832107cd49df33f",
203                 "47b4b1169912ba4f53684b22",
204             ),
205         },
206         TestCase {
207             digest: Digest::Sha256,
208             tag_size: 256/8,
209             key: &[0x0b; 20],
210             data: b"Hi There",
211             expected_mac: concat!(
212                 "b0344c61d8db38535ca8afceaf0bf12b",
213                 "881dc200c9833da726e9376c2e32cff7",
214             ),
215         },
216         TestCase {
217             digest: Digest::Sha384,
218             tag_size: 384/8,
219             key: &[0x0b; 20],
220             data: b"Hi There",
221             expected_mac: concat!(
222                 "afd03944d84895626b0825f4ab46907f",
223                 "15f9dadbe4101ec682aa034c7cebc59c",
224                 "faea9ea9076ede7f4af152e8b2fa9cb6",
225             ),
226         },
227         TestCase {
228             digest: Digest::Sha512,
229             tag_size: 512/8,
230             key: &[0x0b; 20],
231             data: b"Hi There",
232             expected_mac: concat!(
233                 "87aa7cdea5ef619d4ff0b4241a1d6cb0",
234                 "2379f4e2ce4ec2787ad0b30545e17cde",
235                 "daa833b7d6b8a702038b274eaea3f4e4",
236                 "be9d914eeb61f1702e696c203a126854"
237             ),
238         },
239         // Test cases from RFC 4231 Section 4.3
240         TestCase {
241             digest: Digest::Sha224,
242             tag_size: 224/8,
243             key: b"Jefe",
244             data: b"what do ya want for nothing?",
245             expected_mac: concat!(
246                 "a30e01098bc6dbbf45690f3a7e9e6d0f",
247                 "8bbea2a39e6148008fd05e44"
248             ),
249         },
250         TestCase {
251             digest: Digest::Sha256,
252             tag_size: 256/8,
253             key: b"Jefe",
254             data: b"what do ya want for nothing?",
255             expected_mac: concat!(
256                 "5bdcc146bf60754e6a042426089575c7",
257                 "5a003f089d2739839dec58b964ec3843"
258             ),
259         },
260         TestCase {
261             digest: Digest::Sha384,
262             tag_size: 384/8,
263             key: b"Jefe",
264             data: b"what do ya want for nothing?",
265             expected_mac: concat!(
266                 "af45d2e376484031617f78d2b58a6b1b",
267                 "9c7ef464f5a01b47e42ec3736322445e",
268                 "8e2240ca5e69e2c78b3239ecfab21649"
269             ),
270         },
271         TestCase {
272             digest: Digest::Sha512,
273             tag_size: 512/8,
274             key: b"Jefe",
275             data: b"what do ya want for nothing?",
276             expected_mac: concat!(
277                 "164b7a7bfcf819e2e395fbe73b56e0a3",
278                 "87bd64222e831fd610270cd7ea250554",
279                 "9758bf75c05a994a6d034f65f8f0e6fd",
280                 "caeab1a34d4a6b4b636e070a38bce737"
281             ),
282         },
283         // Test cases from RFC 4231 Section 4.4
284         TestCase {
285             digest: Digest::Sha224,
286             tag_size: 224/8,
287             key: &[0xaa; 20],
288             data: &[0xdd; 50],
289             expected_mac: concat!(
290                 "7fb3cb3588c6c1f6ffa9694d7d6ad264",
291                 "9365b0c1f65d69d1ec8333ea"
292             ),
293         },
294         TestCase {
295             digest: Digest::Sha256,
296             tag_size: 256/8,
297             key: &[0xaa; 20],
298             data: &[0xdd; 50],
299             expected_mac: concat!(
300                 "773ea91e36800e46854db8ebd09181a7",
301                 "2959098b3ef8c122d9635514ced565fe"
302             ),
303         },
304         TestCase {
305             digest: Digest::Sha384,
306             tag_size: 384/8,
307             key: &[0xaa; 20],
308             data: &[0xdd; 50],
309             expected_mac: concat!(
310                 "88062608d3e6ad8a0aa2ace014c8a86f",
311                 "0aa635d947ac9febe83ef4e55966144b",
312                 "2a5ab39dc13814b94e3ab6e101a34f27"
313             ),
314         },
315         TestCase {
316             digest: Digest::Sha512,
317             tag_size: 512/8,
318             key: &[0xaa; 20],
319             data: &[0xdd; 50],
320             expected_mac: concat!(
321                 "fa73b0089d56a284efb0f0756c890be9",
322                 "b1b5dbdd8ee81a3655f83e33b2279d39",
323                 "bf3e848279a722c806b485a47e67c807",
324                 "b946a337bee8942674278859e13292fb"
325             ),
326         },
327     ];
328 
329     for (i, test) in HMAC_TESTS.iter().enumerate() {
330         let mut op = hmac.begin(hmac::Key(test.key.to_vec()).into(), test.digest).unwrap();
331         op.update(test.data).unwrap();
332         let mut mac = op.finish().unwrap();
333         mac.truncate(test.tag_size);
334 
335         assert_eq!(
336             hex::encode(&mac),
337             test.expected_mac[..(test.tag_size * 2)],
338             "incorrect mac in test case {}",
339             i
340         );
341     }
342 }
343 
344 /// Test basic [`AesCmac`] functionality.
test_aes_cmac<M: AesCmac>(cmac: M)345 pub fn test_aes_cmac<M: AesCmac>(cmac: M) {
346     // Test vectors from RFC 4493.
347     let key = hex::decode("2b7e151628aed2a6abf7158809cf4f3c").expect("Could not decode key");
348     let key = aes::Key::new(key).unwrap();
349     let data = hex::decode("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710").expect("Could not decode data");
350     let expected = vec![
351         (0usize, "bb1d6929e95937287fa37d129b756746"),
352         (16usize, "070a16b46b4d4144f79bdd9dd04a287c"),
353         (40usize, "dfa66747de9ae63030ca32611497c827"),
354         (64usize, "51f0bebf7e3b9d92fc49741779363cfe"),
355     ]
356     .into_iter()
357     .collect::<HashMap<usize, &'static str>>();
358 
359     for (len, want) in expected {
360         let mut op = cmac.begin(key.clone().into()).unwrap();
361         op.update(&data[..len]).unwrap();
362         let cmac = op.finish().unwrap();
363 
364         assert_eq!(hex::encode(&cmac[..16]), want);
365     }
366 }
367 
368 /// Test `ckdf()` functionality based on an underlying [`AesCmac`] implementation.
test_ckdf<T: Ckdf>(kdf: T)369 pub fn test_ckdf<T: Ckdf>(kdf: T) {
370     // Test data manually generated from Android C++ implementation.
371     let key = aes::Key::new(vec![0; 32]).unwrap();
372     let label = b"KeymasterSharedMac";
373     let v0 = vec![0x00, 0x00, 0x00, 0x00];
374     let v1 = vec![0x01, 0x01, 0x01, 0x01];
375     let v2 = vec![0x02, 0x02, 0x02, 0x02];
376     let v3 = vec![0x03, 0x03, 0x03, 0x03];
377 
378     let result = kdf.ckdf(&key.into(), label, &[&v0, &v1, &v2, &v3], 32).unwrap();
379     assert_eq!(
380         hex::encode(result),
381         concat!("ac9af88a02241f53d43056a4676c42ee", "f06825755e419e7bd20f4e57487717aa")
382     );
383 }
384 
385 /// Test AES-GCM functionality.
test_aes_gcm<A: Aes>(aes: A)386 pub fn test_aes_gcm<A: Aes>(aes: A) {
387     struct TestCase {
388         key: &'static str,
389         iv: &'static str,
390         aad: &'static str,
391         msg: &'static str,
392         ct: &'static str,
393         tag: &'static str,
394     }
395     // Test vectors from https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_test.json
396     let tests = vec![
397         TestCase {
398             key: "5b9604fe14eadba931b0ccf34843dab9",
399             iv: "028318abc1824029138141a2",
400             aad: "",
401             msg: "001d0c231287c1182784554ca3a21908",
402             ct: "26073cc1d851beff176384dc9896d5ff",
403             tag: "0a3ea7a5487cb5f7d70fb6c58d038554",
404         },
405         TestCase {
406             key: "5b9604fe14eadba931b0ccf34843dab9",
407             iv: "921d2507fa8007b7bd067d34",
408             aad: "00112233445566778899aabbccddeeff",
409             msg: "001d0c231287c1182784554ca3a21908",
410             ct: "49d8b9783e911913d87094d1f63cc765",
411             tag: "1e348ba07cca2cf04c618cb4d43a5b92",
412         },
413     ];
414     for test in tests {
415         let key = hex::decode(test.key).unwrap();
416         let iv = hex::decode(test.iv).unwrap();
417         assert_eq!(iv.len(), 12); // Only 96-bit nonces supported.
418         let aad = hex::decode(test.aad).unwrap();
419         let msg = hex::decode(test.msg).unwrap();
420         let tag = hex::decode(test.tag).unwrap();
421         assert_eq!(tag.len(), 16); // Test data includes full 128-bit tag
422 
423         let aes_key = aes::Key::new(key.clone()).unwrap();
424         let mut op = aes
425             .begin_aead(
426                 aes_key.into(),
427                 aes::GcmMode::GcmTag16 { nonce: iv.clone().try_into().unwrap() },
428                 SymmetricOperation::Encrypt,
429             )
430             .unwrap();
431         op.update_aad(&aad).unwrap();
432         let mut got_ct = op.update(&msg).unwrap();
433         got_ct.extend_from_slice(&op.finish().unwrap());
434         assert_eq!(format!("{}{}", test.ct, test.tag), hex::encode(&got_ct));
435 
436         let aes_key = aes::Key::new(key.clone()).unwrap();
437         let mut op = aes
438             .begin_aead(
439                 aes_key.into(),
440                 aes::GcmMode::GcmTag16 { nonce: iv.clone().try_into().unwrap() },
441                 SymmetricOperation::Decrypt,
442             )
443             .unwrap();
444         op.update_aad(&aad).unwrap();
445         let mut got_pt = op.update(&got_ct).unwrap();
446         got_pt.extend_from_slice(&op.finish().unwrap());
447         assert_eq!(test.msg, hex::encode(&got_pt));
448 
449         // Truncated tag should still decrypt.
450         let aes_key = aes::Key::new(key.clone()).unwrap();
451         let mut op = match aes.begin_aead(
452             aes_key.into(),
453             aes::GcmMode::GcmTag12 { nonce: iv.clone().try_into().unwrap() },
454             SymmetricOperation::Decrypt,
455         ) {
456             Ok(c) => c,
457             Err(_) => return,
458         };
459         op.update_aad(&aad).unwrap();
460         let mut got_pt = op.update(&got_ct[..got_ct.len() - 4]).unwrap();
461         got_pt.extend_from_slice(&op.finish().unwrap());
462         assert_eq!(test.msg, hex::encode(&got_pt));
463 
464         // Corrupted ciphertext should not decrypt.
465         let aes_key = aes::Key::new(key).unwrap();
466         let mut op = match aes.begin_aead(
467             aes_key.into(),
468             aes::GcmMode::GcmTag12 { nonce: iv.try_into().unwrap() },
469             SymmetricOperation::Decrypt,
470         ) {
471             Ok(c) => c,
472             Err(_) => return,
473         };
474         op.update_aad(&aad).unwrap();
475         let mut corrupt_ct = got_ct.clone();
476         corrupt_ct[0] ^= 0x01;
477         let _corrupt_pt = op.update(&corrupt_ct).unwrap();
478         let result = op.finish();
479         assert!(result.is_err());
480     }
481 }
482 
483 /// Test basic triple-DES functionality.
test_des<D: Des>(des: D)484 pub fn test_des<D: Des>(des: D) {
485     struct TestCase {
486         key: &'static str,
487         msg: &'static str,
488         ct: &'static str,
489     }
490     let tests = vec![
491         TestCase {
492             key: "800000000000000000000000000000000000000000000000",
493             msg: "0000000000000000",
494             ct: "95a8d72813daa94d",
495         },
496         TestCase {
497             key: "000000000000000000000000000000002000000000000000",
498             msg: "0000000000000000",
499             ct: "7ad16ffb79c45926",
500         },
501     ];
502     for test in tests {
503         let key = hex::decode(test.key).unwrap();
504         let msg = hex::decode(test.msg).unwrap();
505 
506         let des_key = des::Key::new(key.clone()).unwrap();
507         let mut op = des
508             .begin(des_key.clone().into(), des::Mode::EcbNoPadding, SymmetricOperation::Encrypt)
509             .unwrap();
510         let mut got_ct = op.update(&msg).unwrap();
511         got_ct.extend_from_slice(&op.finish().unwrap());
512         assert_eq!(test.ct, hex::encode(&got_ct));
513 
514         let mut op = des
515             .begin(des_key.into(), des::Mode::EcbNoPadding, SymmetricOperation::Decrypt)
516             .unwrap();
517         let mut got_pt = op.update(&got_ct).unwrap();
518         got_pt.extend_from_slice(&op.finish().unwrap());
519         assert_eq!(test.msg, hex::encode(&got_pt));
520     }
521 }
522 
523 /// Test basic SHA-256 functionality.
test_sha256<S: Sha256>(sha256: S)524 pub fn test_sha256<S: Sha256>(sha256: S) {
525     struct TestCase {
526         msg: &'static [u8],
527         want: &'static str,
528     }
529     let tests = vec![
530         TestCase {
531             msg: b"",
532             want: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
533         },
534         TestCase {
535             msg: b"abc",
536             want: "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
537         },
538     ];
539     for test in tests {
540         let got = sha256.hash(test.msg).unwrap();
541         assert_eq!(hex::encode(got), test.want, "for input {}", hex::encode(test.msg));
542     }
543 }
544 
545 /// Test secure deletion secret management.
546 ///
547 /// Warning: this test will use slots in the provided manager, and may leak slots on failure.
test_sdd_mgr<M: keyblob::SecureDeletionSecretManager, R: Rng>(mut sdd_mgr: M, mut rng: R)548 pub fn test_sdd_mgr<M: keyblob::SecureDeletionSecretManager, R: Rng>(mut sdd_mgr: M, mut rng: R) {
549     let (slot1, sdd1) = sdd_mgr.new_secret(&mut rng, SlotPurpose::KeyGeneration).unwrap();
550     assert!(sdd_mgr.get_secret(slot1).unwrap() == sdd1);
551     assert!(sdd_mgr.get_secret(slot1).unwrap() == sdd1);
552 
553     // A second instance should share factory reset secret but not per-key secret.
554     let (slot2, sdd2) = sdd_mgr.new_secret(&mut rng, SlotPurpose::KeyGeneration).unwrap();
555     assert!(sdd_mgr.get_secret(slot2).unwrap() == sdd2);
556     assert_eq!(sdd1.factory_reset_secret, sdd2.factory_reset_secret);
557     assert_ne!(sdd1.secure_deletion_secret, sdd2.secure_deletion_secret);
558 
559     assert!(sdd_mgr.delete_secret(slot1).is_ok());
560     assert!(sdd_mgr.get_secret(slot1).is_err());
561     assert!(sdd_mgr.delete_secret(slot1).is_err());
562 
563     assert!(sdd_mgr.delete_secret(slot2).is_ok());
564 }
565 
566 /// Test that attestation certificates parse as X.509 structures.
test_signing_cert_parse<T: kmr_ta::device::RetrieveCertSigningInfo>( certs: T, is_strongbox: bool, )567 pub fn test_signing_cert_parse<T: kmr_ta::device::RetrieveCertSigningInfo>(
568     certs: T,
569     is_strongbox: bool,
570 ) {
571     let avail = if is_strongbox {
572         vec![SigningKey::Batch, SigningKey::DeviceUnique]
573     } else {
574         vec![SigningKey::Batch]
575     };
576     for which in avail {
577         for algo_hint in [SigningAlgorithm::Ec, SigningAlgorithm::Rsa] {
578             let info = SigningKeyType { which, algo_hint };
579             let chain = certs
580                 .cert_chain(info)
581                 .unwrap_or_else(|_| panic!("failed to retrieve chain for {:?}", info));
582 
583             // Check that the attestation chain looks basically valid (parses as DER,
584             // has subject/issuer match).
585             let mut prev_subject_data = vec![];
586             for (idx, cert) in chain.iter().rev().enumerate() {
587                 let cert = x509_cert::Certificate::from_der(&cert.encoded_certificate)
588                     .expect("failed to parse cert");
589 
590                 let subject_data = cert.tbs_certificate.subject.to_der().unwrap();
591                 let issuer_data = cert.tbs_certificate.issuer.to_der().unwrap();
592                 if idx == 0 {
593                     // First cert should be self-signed, and so have subject==issuer.
594                     assert_eq!(
595                         hex::encode(&subject_data),
596                         hex::encode(&issuer_data),
597                         "root cert has subject != issuer for {:?}",
598                         info
599                     );
600                 } else {
601                     // Issuer of cert should be the subject of the previous cert.
602                     assert_eq!(
603                         hex::encode(&prev_subject_data),
604                         hex::encode(&issuer_data),
605                         "cert {} has issuer != prev_cert.subject for {:?}",
606                         idx,
607                         info
608                     )
609                 }
610                 prev_subject_data.clone_from(&subject_data);
611             }
612         }
613     }
614 }
615 
616 /// Simple smoke test for an `RetrieveRpcArtifacts` trait implementation.
test_retrieve_rpc_artifacts<T: kmr_ta::device::RetrieveRpcArtifacts>( rpc: T, hmac: &dyn Hmac, hkdf: &dyn Hkdf, )617 pub fn test_retrieve_rpc_artifacts<T: kmr_ta::device::RetrieveRpcArtifacts>(
618     rpc: T,
619     hmac: &dyn Hmac,
620     hkdf: &dyn Hkdf,
621 ) {
622     assert!(rpc.get_dice_info(rpc::TestMode(false)).is_ok());
623 
624     let context = b"abcdef";
625     let data1 = rpc.derive_bytes_from_hbk(hkdf, context, 16).expect("failed to derive from HBK");
626     let data2 = rpc.derive_bytes_from_hbk(hkdf, context, 16).expect("failed to derive from HBK");
627     assert_eq!(data1, data2, "derive_bytes_from_hbk() method should be deterministic");
628 
629     let data1 = rpc.compute_hmac_sha256(hmac, hkdf, context).expect("failed to perform HMAC");
630     let data2 = rpc.compute_hmac_sha256(hmac, hkdf, context).expect("failed to perform HMAC");
631     assert_eq!(data1, data2, "compute_hmac_sha256() method should be deterministic");
632 }
633