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