1*d289c2baSAndroid Build Coastguard Worker // Copyright 2024, The Android Open Source Project
2*d289c2baSAndroid Build Coastguard Worker //
3*d289c2baSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*d289c2baSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*d289c2baSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*d289c2baSAndroid Build Coastguard Worker //
7*d289c2baSAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*d289c2baSAndroid Build Coastguard Worker //
9*d289c2baSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*d289c2baSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*d289c2baSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*d289c2baSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*d289c2baSAndroid Build Coastguard Worker // limitations under the License.
14*d289c2baSAndroid Build Coastguard Worker
15*d289c2baSAndroid Build Coastguard Worker //! libavb_rs certificate tests.
16*d289c2baSAndroid Build Coastguard Worker
17*d289c2baSAndroid Build Coastguard Worker use crate::{
18*d289c2baSAndroid Build Coastguard Worker build_test_ops_one_image_one_vbmeta,
19*d289c2baSAndroid Build Coastguard Worker test_data::*,
20*d289c2baSAndroid Build Coastguard Worker test_ops::{FakeVbmetaKey, TestOps},
21*d289c2baSAndroid Build Coastguard Worker verify_one_image_one_vbmeta,
22*d289c2baSAndroid Build Coastguard Worker };
23*d289c2baSAndroid Build Coastguard Worker use avb::{
24*d289c2baSAndroid Build Coastguard Worker cert_generate_unlock_challenge, cert_validate_unlock_credential, CertPermanentAttributes,
25*d289c2baSAndroid Build Coastguard Worker CertUnlockChallenge, CertUnlockCredential, IoError, SlotVerifyError, CERT_PIK_VERSION_LOCATION,
26*d289c2baSAndroid Build Coastguard Worker CERT_PSK_VERSION_LOCATION,
27*d289c2baSAndroid Build Coastguard Worker };
28*d289c2baSAndroid Build Coastguard Worker use hex::decode;
29*d289c2baSAndroid Build Coastguard Worker use std::{collections::HashMap, fs, mem::size_of};
30*d289c2baSAndroid Build Coastguard Worker use zerocopy::{AsBytes, FromBytes};
31*d289c2baSAndroid Build Coastguard Worker
32*d289c2baSAndroid Build Coastguard Worker /// Initializes a `TestOps` object such that cert verification will succeed on
33*d289c2baSAndroid Build Coastguard Worker /// `TEST_PARTITION_NAME`.
34*d289c2baSAndroid Build Coastguard Worker ///
35*d289c2baSAndroid Build Coastguard Worker /// The returned `TestOps` also contains RNG configured to return the contents of
36*d289c2baSAndroid Build Coastguard Worker /// `TEST_CERT_UNLOCK_CHALLENGE_RNG_PATH`, so that the pre-signed contents of
37*d289c2baSAndroid Build Coastguard Worker /// `TEST_CERT_UNLOCK_CREDENTIAL_PATH` will successfully validate by default.
build_test_cert_ops_one_image_one_vbmeta<'a>() -> TestOps<'a>38*d289c2baSAndroid Build Coastguard Worker fn build_test_cert_ops_one_image_one_vbmeta<'a>() -> TestOps<'a> {
39*d289c2baSAndroid Build Coastguard Worker let mut ops = build_test_ops_one_image_one_vbmeta();
40*d289c2baSAndroid Build Coastguard Worker
41*d289c2baSAndroid Build Coastguard Worker // Replace vbmeta with the cert-signed version.
42*d289c2baSAndroid Build Coastguard Worker ops.add_partition("vbmeta", fs::read(TEST_CERT_VBMETA_PATH).unwrap());
43*d289c2baSAndroid Build Coastguard Worker
44*d289c2baSAndroid Build Coastguard Worker // Tell `ops` to use cert APIs and to route the default key through cert validation.
45*d289c2baSAndroid Build Coastguard Worker ops.use_cert = true;
46*d289c2baSAndroid Build Coastguard Worker ops.default_vbmeta_key = Some(FakeVbmetaKey::Cert);
47*d289c2baSAndroid Build Coastguard Worker
48*d289c2baSAndroid Build Coastguard Worker // Add the libavb_cert permanent attributes.
49*d289c2baSAndroid Build Coastguard Worker let perm_attr_bytes = fs::read(TEST_CERT_PERMANENT_ATTRIBUTES_PATH).unwrap();
50*d289c2baSAndroid Build Coastguard Worker ops.cert_permanent_attributes =
51*d289c2baSAndroid Build Coastguard Worker Some(CertPermanentAttributes::read_from(&perm_attr_bytes[..]).unwrap());
52*d289c2baSAndroid Build Coastguard Worker ops.cert_permanent_attributes_hash = Some(
53*d289c2baSAndroid Build Coastguard Worker decode(TEST_CERT_PERMANENT_ATTRIBUTES_HASH_HEX)
54*d289c2baSAndroid Build Coastguard Worker .unwrap()
55*d289c2baSAndroid Build Coastguard Worker .try_into()
56*d289c2baSAndroid Build Coastguard Worker .unwrap(),
57*d289c2baSAndroid Build Coastguard Worker );
58*d289c2baSAndroid Build Coastguard Worker
59*d289c2baSAndroid Build Coastguard Worker // Add the rollbacks for the cert keys.
60*d289c2baSAndroid Build Coastguard Worker ops.rollbacks
61*d289c2baSAndroid Build Coastguard Worker .insert(CERT_PIK_VERSION_LOCATION, Ok(TEST_CERT_PIK_VERSION));
62*d289c2baSAndroid Build Coastguard Worker ops.rollbacks
63*d289c2baSAndroid Build Coastguard Worker .insert(CERT_PSK_VERSION_LOCATION, Ok(TEST_CERT_PSK_VERSION));
64*d289c2baSAndroid Build Coastguard Worker
65*d289c2baSAndroid Build Coastguard Worker // It's non-trivial to sign a challenge without `avbtool.py`, so instead we inject the exact RNG
66*d289c2baSAndroid Build Coastguard Worker // used by the pre-generated challenge so that we can use the pre-signed credential.
67*d289c2baSAndroid Build Coastguard Worker ops.cert_fake_rng = fs::read(TEST_CERT_UNLOCK_CHALLENGE_RNG_PATH).unwrap();
68*d289c2baSAndroid Build Coastguard Worker
69*d289c2baSAndroid Build Coastguard Worker ops
70*d289c2baSAndroid Build Coastguard Worker }
71*d289c2baSAndroid Build Coastguard Worker
72*d289c2baSAndroid Build Coastguard Worker /// Returns the contents of `TEST_CERT_UNLOCK_CREDENTIAL_PATH` as a `CertUnlockCredential`.
test_unlock_credential() -> CertUnlockCredential73*d289c2baSAndroid Build Coastguard Worker fn test_unlock_credential() -> CertUnlockCredential {
74*d289c2baSAndroid Build Coastguard Worker let credential_bytes = fs::read(TEST_CERT_UNLOCK_CREDENTIAL_PATH).unwrap();
75*d289c2baSAndroid Build Coastguard Worker CertUnlockCredential::read_from(&credential_bytes[..]).unwrap()
76*d289c2baSAndroid Build Coastguard Worker }
77*d289c2baSAndroid Build Coastguard Worker
78*d289c2baSAndroid Build Coastguard Worker /// Enough fake RNG data to generate a single unlock challenge.
79*d289c2baSAndroid Build Coastguard Worker const UNLOCK_CHALLENGE_FAKE_RNG: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
80*d289c2baSAndroid Build Coastguard Worker
81*d289c2baSAndroid Build Coastguard Worker /// Returns a `TestOps` with only enough configuration to generate a single unlock challenge.
82*d289c2baSAndroid Build Coastguard Worker ///
83*d289c2baSAndroid Build Coastguard Worker /// The generated unlock challenge will have:
84*d289c2baSAndroid Build Coastguard Worker /// * permanent attributes sourced from the contents of `TEST_CERT_PERMANENT_ATTRIBUTES_PATH`.
85*d289c2baSAndroid Build Coastguard Worker /// * RNG sourced from `UNLOCK_CHALLENGE_FAKE_RNG`.
build_test_cert_ops_unlock_challenge_only<'a>() -> TestOps<'a>86*d289c2baSAndroid Build Coastguard Worker fn build_test_cert_ops_unlock_challenge_only<'a>() -> TestOps<'a> {
87*d289c2baSAndroid Build Coastguard Worker let mut ops = TestOps::default();
88*d289c2baSAndroid Build Coastguard Worker
89*d289c2baSAndroid Build Coastguard Worker // Permanent attributes are needed for the embedded product ID.
90*d289c2baSAndroid Build Coastguard Worker let perm_attr_bytes = fs::read(TEST_CERT_PERMANENT_ATTRIBUTES_PATH).unwrap();
91*d289c2baSAndroid Build Coastguard Worker ops.cert_permanent_attributes =
92*d289c2baSAndroid Build Coastguard Worker Some(CertPermanentAttributes::read_from(&perm_attr_bytes[..]).unwrap());
93*d289c2baSAndroid Build Coastguard Worker
94*d289c2baSAndroid Build Coastguard Worker // Fake RNG for unlock challenge generation.
95*d289c2baSAndroid Build Coastguard Worker ops.cert_fake_rng = UNLOCK_CHALLENGE_FAKE_RNG.into();
96*d289c2baSAndroid Build Coastguard Worker
97*d289c2baSAndroid Build Coastguard Worker ops
98*d289c2baSAndroid Build Coastguard Worker }
99*d289c2baSAndroid Build Coastguard Worker
100*d289c2baSAndroid Build Coastguard Worker #[test]
cert_verify_succeeds()101*d289c2baSAndroid Build Coastguard Worker fn cert_verify_succeeds() {
102*d289c2baSAndroid Build Coastguard Worker let mut ops = build_test_cert_ops_one_image_one_vbmeta();
103*d289c2baSAndroid Build Coastguard Worker
104*d289c2baSAndroid Build Coastguard Worker let result = verify_one_image_one_vbmeta(&mut ops);
105*d289c2baSAndroid Build Coastguard Worker
106*d289c2baSAndroid Build Coastguard Worker assert!(result.is_ok());
107*d289c2baSAndroid Build Coastguard Worker }
108*d289c2baSAndroid Build Coastguard Worker
109*d289c2baSAndroid Build Coastguard Worker #[test]
cert_verify_sets_key_rollbacks()110*d289c2baSAndroid Build Coastguard Worker fn cert_verify_sets_key_rollbacks() {
111*d289c2baSAndroid Build Coastguard Worker let mut ops = build_test_cert_ops_one_image_one_vbmeta();
112*d289c2baSAndroid Build Coastguard Worker
113*d289c2baSAndroid Build Coastguard Worker // `cert_key_versions` should start empty and be filled by the `set_key_version()` callback
114*d289c2baSAndroid Build Coastguard Worker // during cert key validation.
115*d289c2baSAndroid Build Coastguard Worker assert!(ops.cert_key_versions.is_empty());
116*d289c2baSAndroid Build Coastguard Worker
117*d289c2baSAndroid Build Coastguard Worker let result = verify_one_image_one_vbmeta(&mut ops);
118*d289c2baSAndroid Build Coastguard Worker assert!(result.is_ok());
119*d289c2baSAndroid Build Coastguard Worker
120*d289c2baSAndroid Build Coastguard Worker assert_eq!(
121*d289c2baSAndroid Build Coastguard Worker ops.cert_key_versions,
122*d289c2baSAndroid Build Coastguard Worker HashMap::from([
123*d289c2baSAndroid Build Coastguard Worker (CERT_PIK_VERSION_LOCATION, TEST_CERT_PIK_VERSION),
124*d289c2baSAndroid Build Coastguard Worker (CERT_PSK_VERSION_LOCATION, TEST_CERT_PSK_VERSION)
125*d289c2baSAndroid Build Coastguard Worker ])
126*d289c2baSAndroid Build Coastguard Worker );
127*d289c2baSAndroid Build Coastguard Worker }
128*d289c2baSAndroid Build Coastguard Worker
129*d289c2baSAndroid Build Coastguard Worker #[test]
cert_verify_fails_with_pik_rollback_violation()130*d289c2baSAndroid Build Coastguard Worker fn cert_verify_fails_with_pik_rollback_violation() {
131*d289c2baSAndroid Build Coastguard Worker let mut ops = build_test_cert_ops_one_image_one_vbmeta();
132*d289c2baSAndroid Build Coastguard Worker // If the image is signed with a lower key version than our rollback, it should fail to verify.
133*d289c2baSAndroid Build Coastguard Worker *ops.rollbacks
134*d289c2baSAndroid Build Coastguard Worker .get_mut(&CERT_PIK_VERSION_LOCATION)
135*d289c2baSAndroid Build Coastguard Worker .unwrap()
136*d289c2baSAndroid Build Coastguard Worker .as_mut()
137*d289c2baSAndroid Build Coastguard Worker .unwrap() += 1;
138*d289c2baSAndroid Build Coastguard Worker
139*d289c2baSAndroid Build Coastguard Worker let result = verify_one_image_one_vbmeta(&mut ops);
140*d289c2baSAndroid Build Coastguard Worker
141*d289c2baSAndroid Build Coastguard Worker assert_eq!(result.unwrap_err(), SlotVerifyError::PublicKeyRejected);
142*d289c2baSAndroid Build Coastguard Worker }
143*d289c2baSAndroid Build Coastguard Worker
144*d289c2baSAndroid Build Coastguard Worker #[test]
cert_verify_fails_with_psk_rollback_violation()145*d289c2baSAndroid Build Coastguard Worker fn cert_verify_fails_with_psk_rollback_violation() {
146*d289c2baSAndroid Build Coastguard Worker let mut ops = build_test_cert_ops_one_image_one_vbmeta();
147*d289c2baSAndroid Build Coastguard Worker // If the image is signed with a lower key version than our rollback, it should fail to verify.
148*d289c2baSAndroid Build Coastguard Worker *ops.rollbacks
149*d289c2baSAndroid Build Coastguard Worker .get_mut(&CERT_PSK_VERSION_LOCATION)
150*d289c2baSAndroid Build Coastguard Worker .unwrap()
151*d289c2baSAndroid Build Coastguard Worker .as_mut()
152*d289c2baSAndroid Build Coastguard Worker .unwrap() += 1;
153*d289c2baSAndroid Build Coastguard Worker
154*d289c2baSAndroid Build Coastguard Worker let result = verify_one_image_one_vbmeta(&mut ops);
155*d289c2baSAndroid Build Coastguard Worker
156*d289c2baSAndroid Build Coastguard Worker assert_eq!(result.unwrap_err(), SlotVerifyError::PublicKeyRejected);
157*d289c2baSAndroid Build Coastguard Worker }
158*d289c2baSAndroid Build Coastguard Worker
159*d289c2baSAndroid Build Coastguard Worker #[test]
cert_verify_fails_with_wrong_vbmeta_key()160*d289c2baSAndroid Build Coastguard Worker fn cert_verify_fails_with_wrong_vbmeta_key() {
161*d289c2baSAndroid Build Coastguard Worker let mut ops = build_test_cert_ops_one_image_one_vbmeta();
162*d289c2baSAndroid Build Coastguard Worker // The default non-cert vbmeta image should fail to verify.
163*d289c2baSAndroid Build Coastguard Worker ops.add_partition("vbmeta", fs::read(TEST_VBMETA_PATH).unwrap());
164*d289c2baSAndroid Build Coastguard Worker
165*d289c2baSAndroid Build Coastguard Worker let result = verify_one_image_one_vbmeta(&mut ops);
166*d289c2baSAndroid Build Coastguard Worker
167*d289c2baSAndroid Build Coastguard Worker assert_eq!(result.unwrap_err(), SlotVerifyError::PublicKeyRejected);
168*d289c2baSAndroid Build Coastguard Worker }
169*d289c2baSAndroid Build Coastguard Worker
170*d289c2baSAndroid Build Coastguard Worker #[test]
cert_verify_fails_with_bad_permanent_attributes_hash()171*d289c2baSAndroid Build Coastguard Worker fn cert_verify_fails_with_bad_permanent_attributes_hash() {
172*d289c2baSAndroid Build Coastguard Worker let mut ops = build_test_cert_ops_one_image_one_vbmeta();
173*d289c2baSAndroid Build Coastguard Worker // The permanent attributes must match their hash.
174*d289c2baSAndroid Build Coastguard Worker ops.cert_permanent_attributes_hash.as_mut().unwrap()[0] ^= 0x01;
175*d289c2baSAndroid Build Coastguard Worker
176*d289c2baSAndroid Build Coastguard Worker let result = verify_one_image_one_vbmeta(&mut ops);
177*d289c2baSAndroid Build Coastguard Worker
178*d289c2baSAndroid Build Coastguard Worker assert_eq!(result.unwrap_err(), SlotVerifyError::PublicKeyRejected);
179*d289c2baSAndroid Build Coastguard Worker }
180*d289c2baSAndroid Build Coastguard Worker
181*d289c2baSAndroid Build Coastguard Worker #[test]
cert_generate_unlock_challenge_succeeds()182*d289c2baSAndroid Build Coastguard Worker fn cert_generate_unlock_challenge_succeeds() {
183*d289c2baSAndroid Build Coastguard Worker let mut ops = build_test_cert_ops_unlock_challenge_only();
184*d289c2baSAndroid Build Coastguard Worker
185*d289c2baSAndroid Build Coastguard Worker let challenge = cert_generate_unlock_challenge(&mut ops).unwrap();
186*d289c2baSAndroid Build Coastguard Worker
187*d289c2baSAndroid Build Coastguard Worker // Make sure the challenge token used our cert callback data correctly.
188*d289c2baSAndroid Build Coastguard Worker assert_eq!(
189*d289c2baSAndroid Build Coastguard Worker challenge.product_id_hash,
190*d289c2baSAndroid Build Coastguard Worker &decode(TEST_CERT_PRODUCT_ID_HASH_HEX).unwrap()[..]
191*d289c2baSAndroid Build Coastguard Worker );
192*d289c2baSAndroid Build Coastguard Worker assert_eq!(challenge.challenge, UNLOCK_CHALLENGE_FAKE_RNG);
193*d289c2baSAndroid Build Coastguard Worker }
194*d289c2baSAndroid Build Coastguard Worker
195*d289c2baSAndroid Build Coastguard Worker #[test]
cert_generate_unlock_challenge_fails_without_permanent_attributes()196*d289c2baSAndroid Build Coastguard Worker fn cert_generate_unlock_challenge_fails_without_permanent_attributes() {
197*d289c2baSAndroid Build Coastguard Worker let mut ops = build_test_cert_ops_unlock_challenge_only();
198*d289c2baSAndroid Build Coastguard Worker
199*d289c2baSAndroid Build Coastguard Worker // Challenge generation should fail without the product ID provided by the permanent attributes.
200*d289c2baSAndroid Build Coastguard Worker ops.cert_permanent_attributes = None;
201*d289c2baSAndroid Build Coastguard Worker
202*d289c2baSAndroid Build Coastguard Worker assert_eq!(
203*d289c2baSAndroid Build Coastguard Worker cert_generate_unlock_challenge(&mut ops).unwrap_err(),
204*d289c2baSAndroid Build Coastguard Worker IoError::Io
205*d289c2baSAndroid Build Coastguard Worker );
206*d289c2baSAndroid Build Coastguard Worker }
207*d289c2baSAndroid Build Coastguard Worker
208*d289c2baSAndroid Build Coastguard Worker #[test]
cert_generate_unlock_challenge_fails_insufficient_rng()209*d289c2baSAndroid Build Coastguard Worker fn cert_generate_unlock_challenge_fails_insufficient_rng() {
210*d289c2baSAndroid Build Coastguard Worker let mut ops = build_test_cert_ops_unlock_challenge_only();
211*d289c2baSAndroid Build Coastguard Worker
212*d289c2baSAndroid Build Coastguard Worker // Remove a byte of RNG so there isn't enough.
213*d289c2baSAndroid Build Coastguard Worker ops.cert_fake_rng.pop();
214*d289c2baSAndroid Build Coastguard Worker
215*d289c2baSAndroid Build Coastguard Worker assert_eq!(
216*d289c2baSAndroid Build Coastguard Worker cert_generate_unlock_challenge(&mut ops).unwrap_err(),
217*d289c2baSAndroid Build Coastguard Worker IoError::Io
218*d289c2baSAndroid Build Coastguard Worker );
219*d289c2baSAndroid Build Coastguard Worker }
220*d289c2baSAndroid Build Coastguard Worker
221*d289c2baSAndroid Build Coastguard Worker #[test]
cert_validate_unlock_credential_success()222*d289c2baSAndroid Build Coastguard Worker fn cert_validate_unlock_credential_success() {
223*d289c2baSAndroid Build Coastguard Worker let mut ops = build_test_cert_ops_one_image_one_vbmeta();
224*d289c2baSAndroid Build Coastguard Worker
225*d289c2baSAndroid Build Coastguard Worker // We don't actually need the challenge here since we've pre-signed it, but we still need to
226*d289c2baSAndroid Build Coastguard Worker // call this function so the libavb_cert internal state is ready for the unlock cred.
227*d289c2baSAndroid Build Coastguard Worker let _ = cert_generate_unlock_challenge(&mut ops).unwrap();
228*d289c2baSAndroid Build Coastguard Worker
229*d289c2baSAndroid Build Coastguard Worker assert_eq!(
230*d289c2baSAndroid Build Coastguard Worker cert_validate_unlock_credential(&mut ops, &test_unlock_credential()),
231*d289c2baSAndroid Build Coastguard Worker Ok(true)
232*d289c2baSAndroid Build Coastguard Worker );
233*d289c2baSAndroid Build Coastguard Worker }
234*d289c2baSAndroid Build Coastguard Worker
235*d289c2baSAndroid Build Coastguard Worker #[test]
cert_validate_unlock_credential_fails_wrong_rng()236*d289c2baSAndroid Build Coastguard Worker fn cert_validate_unlock_credential_fails_wrong_rng() {
237*d289c2baSAndroid Build Coastguard Worker let mut ops = build_test_cert_ops_one_image_one_vbmeta();
238*d289c2baSAndroid Build Coastguard Worker // Modify the RNG slightly, the cerificate should now fail to validate.
239*d289c2baSAndroid Build Coastguard Worker ops.cert_fake_rng[0] ^= 0x01;
240*d289c2baSAndroid Build Coastguard Worker
241*d289c2baSAndroid Build Coastguard Worker let _ = cert_generate_unlock_challenge(&mut ops).unwrap();
242*d289c2baSAndroid Build Coastguard Worker
243*d289c2baSAndroid Build Coastguard Worker assert_eq!(
244*d289c2baSAndroid Build Coastguard Worker cert_validate_unlock_credential(&mut ops, &test_unlock_credential()),
245*d289c2baSAndroid Build Coastguard Worker Ok(false)
246*d289c2baSAndroid Build Coastguard Worker );
247*d289c2baSAndroid Build Coastguard Worker }
248*d289c2baSAndroid Build Coastguard Worker
249*d289c2baSAndroid Build Coastguard Worker #[test]
cert_validate_unlock_credential_fails_with_pik_rollback_violation()250*d289c2baSAndroid Build Coastguard Worker fn cert_validate_unlock_credential_fails_with_pik_rollback_violation() {
251*d289c2baSAndroid Build Coastguard Worker let mut ops = build_test_cert_ops_one_image_one_vbmeta();
252*d289c2baSAndroid Build Coastguard Worker // Rotating the PIK should invalidate all existing unlock keys, which includes our pre-signed
253*d289c2baSAndroid Build Coastguard Worker // certificate.
254*d289c2baSAndroid Build Coastguard Worker *ops.rollbacks
255*d289c2baSAndroid Build Coastguard Worker .get_mut(&CERT_PIK_VERSION_LOCATION)
256*d289c2baSAndroid Build Coastguard Worker .unwrap()
257*d289c2baSAndroid Build Coastguard Worker .as_mut()
258*d289c2baSAndroid Build Coastguard Worker .unwrap() += 1;
259*d289c2baSAndroid Build Coastguard Worker
260*d289c2baSAndroid Build Coastguard Worker let _ = cert_generate_unlock_challenge(&mut ops).unwrap();
261*d289c2baSAndroid Build Coastguard Worker
262*d289c2baSAndroid Build Coastguard Worker assert_eq!(
263*d289c2baSAndroid Build Coastguard Worker cert_validate_unlock_credential(&mut ops, &test_unlock_credential()),
264*d289c2baSAndroid Build Coastguard Worker Ok(false)
265*d289c2baSAndroid Build Coastguard Worker );
266*d289c2baSAndroid Build Coastguard Worker }
267*d289c2baSAndroid Build Coastguard Worker
268*d289c2baSAndroid Build Coastguard Worker #[test]
cert_validate_unlock_credential_fails_no_challenge()269*d289c2baSAndroid Build Coastguard Worker fn cert_validate_unlock_credential_fails_no_challenge() {
270*d289c2baSAndroid Build Coastguard Worker let mut ops = build_test_cert_ops_one_image_one_vbmeta();
271*d289c2baSAndroid Build Coastguard Worker
272*d289c2baSAndroid Build Coastguard Worker // We never called `cert_generate_unlock_challenge()`, so no credentials should validate.
273*d289c2baSAndroid Build Coastguard Worker assert_eq!(
274*d289c2baSAndroid Build Coastguard Worker cert_validate_unlock_credential(&mut ops, &test_unlock_credential()),
275*d289c2baSAndroid Build Coastguard Worker Ok(false)
276*d289c2baSAndroid Build Coastguard Worker );
277*d289c2baSAndroid Build Coastguard Worker }
278*d289c2baSAndroid Build Coastguard Worker
279*d289c2baSAndroid Build Coastguard Worker // In practice, devices will usually be passing unlock challenges and credentials over fastboot as
280*d289c2baSAndroid Build Coastguard Worker // raw bytes. This test ensures that there are some reasonable APIs available to convert between
281*d289c2baSAndroid Build Coastguard Worker // `CertUnlockChallenge`/`CertUnlockCredential` and byte slices.
282*d289c2baSAndroid Build Coastguard Worker #[test]
cert_validate_unlock_credential_bytes_api()283*d289c2baSAndroid Build Coastguard Worker fn cert_validate_unlock_credential_bytes_api() {
284*d289c2baSAndroid Build Coastguard Worker let mut ops = build_test_cert_ops_one_image_one_vbmeta();
285*d289c2baSAndroid Build Coastguard Worker
286*d289c2baSAndroid Build Coastguard Worker // Write an unlock challenge to a byte buffer for TX over fastboot.
287*d289c2baSAndroid Build Coastguard Worker let challenge = cert_generate_unlock_challenge(&mut ops).unwrap();
288*d289c2baSAndroid Build Coastguard Worker let mut buffer = vec![0u8; size_of::<CertUnlockChallenge>()];
289*d289c2baSAndroid Build Coastguard Worker assert_eq!(challenge.write_to(&mut buffer[..]), Some(())); // zerocopy::AsBytes.
290*d289c2baSAndroid Build Coastguard Worker
291*d289c2baSAndroid Build Coastguard Worker // Read an unlock credential from a byte buffer for RX from fastboot.
292*d289c2baSAndroid Build Coastguard Worker let buffer = vec![0u8; size_of::<CertUnlockCredential>()];
293*d289c2baSAndroid Build Coastguard Worker let credential = CertUnlockCredential::ref_from(&buffer[..]).unwrap(); // zerocopy::FromBytes.
294*d289c2baSAndroid Build Coastguard Worker
295*d289c2baSAndroid Build Coastguard Worker // It shouldn't actually validate since the credential is just zeroes, the important thing
296*d289c2baSAndroid Build Coastguard Worker // is that it compiles.
297*d289c2baSAndroid Build Coastguard Worker assert_eq!(
298*d289c2baSAndroid Build Coastguard Worker cert_validate_unlock_credential(&mut ops, credential),
299*d289c2baSAndroid Build Coastguard Worker Ok(false)
300*d289c2baSAndroid Build Coastguard Worker );
301*d289c2baSAndroid Build Coastguard Worker }
302