xref: /aosp_15_r20/external/gsc-utils/rust/ap_ro_errs/src/lib.rs (revision 4f2df630800bdcf1d4f0decf95d8a1cb87344f5f)
1 // Copyright 2023 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 #![no_std]
5 
6 use core::fmt;
7 use enum_utils::enum_as;
8 use zerocopy::{transmute, AsBytes, FromBytes, FromZeroes};
9 
10 /// The result type used throughout AP RO verification.
11 pub type Result<T> = core::result::Result<T, VerifyError>;
12 
13 /// Represents success or failure of AP RO verification
14 #[derive(Copy, Clone)]
15 pub struct ApRoVerificationResult(Result<()>);
16 
17 impl ApRoVerificationResult {
18     /// Value that represents success value both in long life scratch and detailed UMA
19     /// value. We do not want to use `0`, `!0`, or any value that aliases to a detailed
20     /// error, which is verified by unit test.
21     const SERIALIZED_SUCCESS: u32 = 0xFFFF_F000;
22 
23     /// Returns true if the AP RO verification successfully passed
is_success(self) -> bool24     pub fn is_success(self) -> bool {
25         self.0.is_ok()
26     }
27 }
28 
29 impl From<u32> for ApRoVerificationResult {
from(value: u32) -> Self30     fn from(value: u32) -> Self {
31         Self(if value == Self::SERIALIZED_SUCCESS {
32             Ok(())
33         } else {
34             Err(
35                 VerifyError::try_from(value).unwrap_or(VerifyError::Internal(
36                     InternalErrorSource::CouldNotDeserialize,
37                     0,
38                 )),
39             )
40         })
41     }
42 }
43 
44 impl From<Result<()>> for ApRoVerificationResult {
from(value: Result<()>) -> Self45     fn from(value: Result<()>) -> Self {
46         Self(value)
47     }
48 }
49 
50 impl From<ApRoVerificationResult> for Result<()> {
from(value: ApRoVerificationResult) -> Self51     fn from(value: ApRoVerificationResult) -> Self {
52         value.0
53     }
54 }
55 
56 impl From<ApRoVerificationResult> for u32 {
from(value: ApRoVerificationResult) -> Self57     fn from(value: ApRoVerificationResult) -> Self {
58         value
59             .0
60             .map_or_else(u32::from, |()| ApRoVerificationResult::SERIALIZED_SUCCESS)
61     }
62 }
63 
64 /// An error that occurred verifying the AP RO contents.
65 ///
66 /// One byte contains a top-level error code of [`VerifyErrorCode`].
67 /// Three bytes contain a detailed status.
68 ///
69 /// This value has a niche at 0, so `Result<(), VerifyError>`
70 /// can represent `Ok` as a 0, saving space.
71 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
72 #[repr(C, align(4))]
73 pub struct VerifyError {
74     code: VerifyErrorCode,
75     /// Details data that is stored big endian byte order, where the most significant
76     /// value should be first in the array.
77     detail: [u8; 3],
78 }
79 
80 impl VerifyError {
new(code: VerifyErrorCode) -> Self81     const fn new(code: VerifyErrorCode) -> Self {
82         Self {
83             code,
84             detail: [0; 3],
85         }
86     }
87 
88     #[inline(always)]
with_detail(mut self, detail: [u8; 3]) -> Self89     pub const fn with_detail(mut self, detail: [u8; 3]) -> Self {
90         self.detail = detail;
91         self
92     }
93 
94     #[inline(always)]
code(self) -> VerifyErrorCode95     pub fn code(self) -> VerifyErrorCode {
96         self.code
97     }
98 
detail(self) -> [u8; 3]99     pub fn detail(self) -> [u8; 3] {
100         self.detail
101     }
102 
103     /// Failures in validating the write protect status registers.
104     #[inline(always)]
105     #[allow(non_snake_case)]
FailedStatusRegister( register: StatusRegister, got: u8, expected: WriteProtectDescriptor, ) -> Self106     pub const fn FailedStatusRegister(
107         register: StatusRegister,
108         got: u8,
109         expected: WriteProtectDescriptor,
110     ) -> Self {
111         let code = match register {
112             StatusRegister::Register1 => VerifyErrorCode::FailedStatusRegister1,
113             StatusRegister::Register2 => VerifyErrorCode::FailedStatusRegister2,
114             StatusRegister::Register3 => VerifyErrorCode::FailedStatusRegister3,
115         };
116         // Invalid descriptors are represented with masks of 0, as this would normally pass.
117         let (value, mask) = match expected.get() {
118             Ok((value, mask)) => (value, mask),
119             Err(e) => (e as u8, 0),
120         };
121         Self::new(code).with_detail([got, value, mask])
122     }
123 
with_failed_signature_location(mut self, location: SignatureLocation) -> Self124     pub fn with_failed_signature_location(mut self, location: SignatureLocation) -> Self {
125         self.detail[1] = location as u8;
126         self
127     }
128 }
129 
130 impl From<VerifyError> for u32 {
from(value: VerifyError) -> Self131     fn from(value: VerifyError) -> Self {
132         // The error code should be the most significant byte, so the detailed code
133         // can be bound a range of values that belong to a top-level VerifyErrorCode.
134         // Details are stored as BE bytes.
135         u32::from_be_bytes([
136             value.code as u8,
137             value.detail[0],
138             value.detail[1],
139             value.detail[2],
140         ])
141     }
142 }
143 
144 /// Indicates that input data could be not converted to a valid [`VerifyError`].
145 pub struct InvalidVerifyError;
146 
147 impl TryFrom<u32> for VerifyError {
148     type Error = InvalidVerifyError;
149 
try_from(value: u32) -> core::result::Result<Self, Self::Error>150     fn try_from(value: u32) -> core::result::Result<Self, Self::Error> {
151         let [code, d0, d1, d2] = value.to_be_bytes();
152         VerifyErrorCode::from_u8(code)
153             .map(|e| VerifyError::new(e).with_detail([d0, d1, d2]))
154             .ok_or(InvalidVerifyError)
155     }
156 }
157 
158 /// Generates [`VerifyError`] constants that use a given [`VerifyErrorCode`] name
159 /// and contain no details.
160 ///
161 /// The capitalization is intended to mirror enum variants with no value.
162 macro_rules! no_detail_codes {
163     ($($code:ident),* $(,)?) => {
164         #[allow(non_upper_case_globals)]
165         impl VerifyError {
166             $(
167                 #[doc=concat!(
168                     "Error with the [`VerifyErrorCode::", stringify!($code),
169                     "`] code and empty details")
170                 ]
171                 pub const $code: Self = Self::new(VerifyErrorCode:: $code);
172             )*
173         }
174     }
175 }
176 
177 /// Generates [`VerifyError`] functions that use a given [`VerifyErrorCode`] name
178 /// and describe the arguments and transformation to a `[u8; 3]` of details.
179 ///
180 /// The capitalization is intended to mirror enum tuple variants.
181 macro_rules! detailed_codes {
182     ($($code:ident( $($arg:ident: $t:ty),* $(,)?) => $e:expr),* $(,)?) => {
183         #[allow(non_snake_case)]
184         impl VerifyError {
185             $(
186                 #[doc=concat!(
187                     "Error with the [`VerifyErrorCode::", stringify!($code),
188                     "`] code and specified details")
189                 ]
190                 #[inline(always)]
191                 pub const fn $code ( $($arg: $t),* ) -> Self {
192                     Self::new(VerifyErrorCode:: $code).with_detail($e)
193                 }
194             )*
195         }
196     };
197 }
198 
199 no_detail_codes!(
200     // TODO(b/263298180): detail: lots of choices, what was wrong?
201     InconsistentGscvd,
202     // This is currently only used for if the keyblock is too big.
203     InconsistentKeyblock,
204     // TODO(b/263298180): detail: which key was bad, platform/root
205     InconsistentKey,
206     // TODO(b/263298180): detail: Command that failed? offset/len?
207     SpiRead,
208     // Possible detail: `SyncCell` static that increments for every alloc.
209     OutOfMemory,
210     // TODO(b/263298180): detail: How too big was it, and what was too big?
211     // Also, consider subsuming `InconsistentKeyblock`
212     TooBig,
213     // TODO(b/263298180): detail: where did we look?
214     MissingGscvd,
215     // This will only trigger if the either none or just SPI settings are not provisioned.
216     SettingNotProvisioned,
217     // TODO(b/263298180): detail: contents of GBB flags from `GbbHeader`
218     NonZeroGbbFlags,
219     WrongRootKey,
220 );
221 
222 detailed_codes!(
223     FailedVerification(details: FailedVerificationDetail) => details.to_details(),
224     VersionMismatch(source: VersionMismatchSource) => [source as u8, 0, 0],
225     UnsupportedCryptoAlgorithm(source: CryptoAlgorithmSource, alg: u16) => {
226         let [hi, lo] = alg.to_be_bytes();
227         [source as u8, hi, lo]
228     },
229     Internal(source: InternalErrorSource, code: u16) => {
230         let [hi, lo] = code.to_be_bytes();
231         [source as u8, hi, lo]
232     },
233     // `got` and `expected` both get 3 nibbles of data
234     BoardIdMismatch(got: u32, expected: u32) => {
235         let [_, a, b, c] = (got >> 20 << 12 | expected >> 20).to_be_bytes();
236         [a, b, c]
237     },
238 );
239 
240 /// Details for the [`VerifyErrorCode::Internal`] error.
241 ///
242 /// Values cannot change, they can only be appended.
243 #[enum_as(u8)]
244 pub enum InternalErrorSource {
245     /// The lower bytes are a [`kernel::ErrorCode`].
246     Kernel = 1,
247 
248     /// The lower bytes are a [`hil::crypto::CryptoError`].
249     /// Note the values are all negative.hi, lo
250     Crypto = 2,
251 
252     /// Should never happen.
253     VerifyFlashRanges = 3,
254 
255     /// The cached AP RO verification result value was not parsable into a valid result again
256     CouldNotDeserialize = 4,
257 }
258 
259 /// Details for the [`VerifyErrorCode::VersionMismatch`] error. Values cannot change, they can only
260 /// be appended.
261 #[derive(Debug)]
262 #[enum_as(u8)]
263 pub enum VersionMismatchSource {
264     Gscvd = 1,
265     Keyblock = 2,
266 }
267 
268 /// Details for the [`VerifyErrorCode::UnsupportedCryptoAlgorithm`] error.
269 ///
270 /// Values cannot change, they can only be appended.
271 #[derive(Debug)]
272 #[enum_as(u8)]
273 pub enum CryptoAlgorithmSource {
274     Gscvd = 1,
275 
276     /// A `Vb2PackedKey`, either the root key or platform key
277     ///
278     /// TODO(b/263298180): disambiguate; requires setting after-the-fact
279     Vb2PackedKey = 4,
280 }
281 
282 /// Details for the [`VerifyErrorCode::FailedVerification`] error.
283 ///
284 /// Values cannot change, they can only be appended.
285 #[derive(Debug)]
286 pub enum FailedVerificationDetail {
287     DigestMismatch {
288         location: DigestLocation,
289         got: u8,
290         expected: u8,
291     },
292     SignatureVerifyFail,
293 }
294 
295 /// Part of the top byte of the detail for [`VerifyErrorCode::FailedVerification`].
296 ///
297 /// Values cannot change, they can only be appended.
298 #[derive(Debug)]
299 #[enum_as(u8)]
300 pub enum SignatureLocation {
301     Gscvd = 1,
302     Keyblock = 2,
303 }
304 
305 /// Part of the top byte of the detail for [`VerifyErrorCode::FailedVerification`].
306 ///
307 /// Max value is 15.
308 /// Values cannot change, they can only be appended.
309 #[derive(Debug)]
310 #[enum_as(u8)]
311 pub enum DigestLocation {
312     /// The protected regions of AP flash covered by the GSCVD.
313     ProtectedRegions = 1,
314 
315     /// The cache for the GSCVD header.
316     GvdCache = 2,
317 
318     /// The root key
319     RootKey = 3,
320 }
321 
322 impl FailedVerificationDetail {
323     const DIGEST_MISMATCH: u8 = 0x10;
324     const SIGNATURE_VERIFY: u8 = 0;
325 
326     #[inline(always)]
to_details(self) -> [u8; 3]327     const fn to_details(self) -> [u8; 3] {
328         match self {
329             FailedVerificationDetail::DigestMismatch {
330                 location,
331                 got,
332                 expected,
333             } => {
334                 const _CHECK_MAX_DIGEST_LOCATION: () = assert!(DigestLocation::END <= 0x0f);
335 
336                 // Also record the (hardcoded) number of valid root key hashes.
337                 // The top byte carries three pieces of info:
338                 // - The top nibble being non-zero indicates this is a `DIGEST_MISMATCH`.
339                 // - The top nibble is 1 + NUM_VALID_ROOT_KEY_HASHES.
340                 // - The bottom nibble is the `DigestLocation`.
341                 let top_byte =
342                     FailedVerificationDetail::DIGEST_MISMATCH + ((2_u8) << 4) + location as u8;
343                 [top_byte, got, expected]
344             }
345             FailedVerificationDetail::SignatureVerifyFail => {
346                 // Code structure requires the location be set after-the-fact.
347                 // See [`VerifyError::with_failed_signature_location`].
348                 [FailedVerificationDetail::SIGNATURE_VERIFY, 0, 0]
349             }
350         }
351     }
352 }
353 
354 /// All of the verification errors that can occur while validating AP RO. Values cannot change,
355 /// they can only be appended.
356 #[enum_as(u8)]
357 #[derive(Debug)]
358 pub enum VerifyErrorCode {
359     /// Consistent verification data was found, but it failed cryptographic verification.
360     FailedVerification = 1,
361 
362     /// Failed WP status register verification on [`StatusRegister::Register1`].
363     FailedStatusRegister1 = 2,
364 
365     /// Failed WP status register verification on [`StatusRegister::Register2`].
366     FailedStatusRegister2 = 3,
367 
368     /// Failed WP status register verification on [`StatusRegister::Register3`].
369     FailedStatusRegister3 = 4,
370 
371     /// The [`gscvd::GscVerificationData`] wasn't correctly laid out.
372     InconsistentGscvd = 5,
373 
374     /// The [`keyblock::Vb2Keyblock`] wasn't correctly laid out.
375     InconsistentKeyblock = 6,
376 
377     /// The key stored wasn't in a valid format.
378     InconsistentKey = 7,
379 
380     /// A SPI read operation failed while communicating with AP flash.
381     SpiRead = 8,
382 
383     /// The data uses a crypto algorithm that is unsupported.
384     UnsupportedCryptoAlgorithm = 9,
385 
386     /// A structure version is unsupported.
387     VersionMismatch = 10,
388 
389     /// There was not enough reserved memory to perform the operation as requested.
390     OutOfMemory = 11,
391 
392     /// A miscellaneous internal error occurred.
393     Internal = 12,
394 
395     /// A data structure was too large.
396     TooBig = 13,
397 
398     /// There was no GSCVD present in flash.
399     MissingGscvd = 14,
400 
401     /// The Board ID for this GSCVD is not correct for this board.
402     BoardIdMismatch = 15,
403 
404     /// A necessary setting was not provisioned or was invalid.
405     SettingNotProvisioned = 16,
406 
407     /// Verification failed solely because the GBB flags are non-zero.
408     NonZeroGbbFlags = 17,
409 
410     /// The AP RO verification root key hash matched, but the key use is not
411     /// authorized any more because only MP prod key is allowed at this point.
412     WrongRootKey = 18,
413 }
414 
415 pub enum StatusRegister {
416     /// Read Status Register-1 (05h)
417     Register1,
418 
419     /// Read Status Register-2 (35h)
420     Register2,
421 
422     /// Read Status Register-3 (15h)
423     Register3,
424 }
425 
426 #[repr(C, align(4))]
427 #[derive(AsBytes, FromBytes, FromZeroes, Clone, Copy)]
428 pub struct WriteProtectDescriptor {
429     expected_value: ByteWithInverse,
430     mask: ByteWithInverse,
431 }
432 
433 /// A byte value stored along with its bit-inverted value.
434 ///
435 /// This protects against a spurious write causing a reduction in security without first erasing,
436 /// since writes can only clear bits.
437 /// It also allows for more flexible filling in of individual values than a checksum.
438 #[repr(C)]
439 #[derive(AsBytes, FromBytes, FromZeroes, Clone, Copy)]
440 struct ByteWithInverse {
441     value: u8,
442 
443     /// `value`, but with the bits inverted
444     ///
445     /// If it does not equal `!value`, this value is unset (all 1's) or corrupted.
446     inv_value: u8,
447 }
448 
449 impl ByteWithInverse {
new(value: u8) -> Self450     pub const fn new(value: u8) -> Self {
451         Self {
452             value,
453             inv_value: !value,
454         }
455     }
456 
is_blank(self) -> bool457     pub const fn is_blank(self) -> bool {
458         self.value == !0 && self.inv_value == !0
459     }
460 
get(self) -> core::result::Result<u8, BadValue>461     pub const fn get(self) -> core::result::Result<u8, BadValue> {
462         if self.value == !self.inv_value {
463             Ok(self.value)
464         } else {
465             Err(if self.is_blank() {
466                 BadValue::Blank
467             } else {
468                 BadValue::Corrupted
469             })
470         }
471     }
472 }
473 
474 impl fmt::Display for ByteWithInverse {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result475     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
476         match self.get() {
477             Ok(value) => write!(f, "{value:02x}"),
478             Err(e) => write!(f, "{}", e.to_string()),
479         }
480     }
481 }
482 
483 // TODO(kupiakos): Resolve naming consistency of `is_blank` and `get` with
484 // similar `ValueAndMaskWriteProtectDescriptor` methods.
485 impl WriteProtectDescriptor {
new(expected_value: u8, mask: u8) -> Self486     pub fn new(expected_value: u8, mask: u8) -> Self {
487         Self {
488             expected_value: ByteWithInverse::new(expected_value),
489             mask: ByteWithInverse::new(mask),
490         }
491     }
492 
493     /// Returns a blank/unset `WriteProtectDescriptor`
blank() -> Self494     pub fn blank() -> Self {
495         transmute!(!0u32)
496     }
497 
498     /// Returns the (expected value, mask), so long as the value is valid.
get(self) -> core::result::Result<(u8, u8), BadValue>499     pub const fn get(self) -> core::result::Result<(u8, u8), BadValue> {
500         match (self.expected_value.get(), self.mask.get()) {
501             (Ok(expected_value), Ok(mask)) => Ok((expected_value, mask)),
502             (Err(BadValue::Corrupted), _) | (_, Err(BadValue::Corrupted)) => {
503                 Err(BadValue::Corrupted)
504             }
505             // ByteWithInverse never returns `Invalid`
506             _ => Err(BadValue::Blank),
507         }
508     }
509 
510     /// Has this never been written to?
is_blank(self) -> bool511     pub fn is_blank(self) -> bool {
512         let as_u32: u32 = transmute!(self);
513         as_u32 == !0
514     }
515 
516     /// Does this descriptor have an mask of all 0's, making it always match?
is_empty_mask(self) -> bool517     pub fn is_empty_mask(self) -> bool {
518         matches!(self.mask.get(), Ok(0))
519     }
520 
521     /// Is the given value from the protection register considered
522     /// "matching" this descriptor, meaning it's verified.
matches(self, value: u8) -> bool523     pub fn matches(self, value: u8) -> bool {
524         match self.get() {
525             Ok((expected_value, mask)) => expected_value & mask == value & mask,
526             _ => false,
527         }
528     }
529 }
530 
531 impl fmt::Display for WriteProtectDescriptor {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result532     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
533         write!(f, "{} & {}", self.expected_value, self.mask)
534     }
535 }
536 
537 /// The value stored here couldn't be used.
538 #[enum_as(u8)]
539 pub enum BadValue {
540     /// The value was unset/blank. This is an expected state.
541     Blank = 1,
542 
543     /// The value was corrupted - its inverted value did not match its value and it was not blank.
544     /// This is an unexpected state.
545     Corrupted,
546 
547     /// The value was outside of the range of valid values for the type.
548     Invalid,
549 }
550 
551 impl BadValue {
to_string(self) -> &'static str552     pub fn to_string(self) -> &'static str {
553         match self {
554             BadValue::Blank => "Blank",
555             BadValue::Corrupted => "Corrupted",
556             BadValue::Invalid => "Invalid",
557         }
558     }
559 }
560 
561 #[derive(Debug)]
562 #[enum_as(u8)]
563 pub enum ApRoVerificationTpmvStatus {
564     /// Success
565     Success = 20,
566 
567     /// Consistent verification data was found, but it failed cryptographic verification.
568     FailedVerification = 21,
569 
570     /// The `GscVerificationData` wasn't correctly laid out.
571     InconsistentGscvd = 22,
572 
573     /// The `Vb2Keyblock` wasn't correctly laid out.
574     InconsistentKeyblock = 23,
575 
576     /// The key stored wasn't in a valid format.
577     InconsistentKey = 24,
578 
579     /// A SPI read operation failed while communicating with AP flash.
580     SpiRead = 25,
581 
582     /// The data uses a crypto algorithm that is unsupported.
583     UnsupportedCryptoAlgorithm = 26,
584 
585     /// A structure version is unsupported.
586     VersionMismatch = 27,
587 
588     /// There was not enough reserved memory to perform the operation as requested.
589     OutOfMemory = 28,
590 
591     /// A miscellaneous internal error occurred.
592     Internal = 29,
593 
594     /// A data structure was too large.
595     TooBig = 30,
596 
597     /// There was no GSCVD present in flash.
598     MissingGscvd = 31,
599 
600     /// The Board ID for this GSCVD is not correct for this board.
601     BoardIdMismatch = 32,
602 
603     /// A necessary setting was not provisioned or was invalid.
604     SettingNotProvisioned = 33,
605     /* Do not use values 34 and 35. They are ambiguous since Unknown used both as its value. */
606     /// Verification failed solely because the GBB flags are non-zero.
607     NonZeroGbbFlags = 36,
608 
609     /// The root key was recognized, but is disabled by security policy.
610     WrongRootkey = 37,
611 
612     /// Unknown error
613     Unknown = 255,
614 }
615 
616 impl ApRoVerificationTpmvStatus {
to_str(self) -> &'static str617     pub fn to_str(self) -> &'static str {
618         use ApRoVerificationTpmvStatus::*;
619         match self {
620             Success => "OK",
621             FailedVerification => "FAIL",
622             InconsistentGscvd => "bad gvd",
623             InconsistentKeyblock => "bad keyblock",
624             InconsistentKey => "bad key",
625             SpiRead => "spi err",
626             UnsupportedCryptoAlgorithm => "bad crypto",
627             VersionMismatch => "bad version",
628             OutOfMemory => "oom",
629             Internal => "internal",
630             TooBig => "too big",
631             MissingGscvd => "no gvd",
632             BoardIdMismatch => "wrong board id",
633             SettingNotProvisioned => "setting unprovisioned",
634             NonZeroGbbFlags => "Would pass with zeroed GBB flags",
635             WrongRootkey => "Only MP prod root key is accepted",
636             Unknown => "unknown",
637         }
638     }
639 }
640 
641 #[cfg(test)]
642 mod tests {
643     use super::*;
644 
645     #[test]
test_serialized_success_is_invalid_verification_failure()646     fn test_serialized_success_is_invalid_verification_failure() {
647         assert!(
648             VerifyError::try_from(ApRoVerificationResult::SERIALIZED_SUCCESS).is_err(),
649             "Serialized success value cannot overlap with any valid verify error"
650         );
651     }
652 
653     #[test]
test_zero_is_invalid_verification_failure()654     fn test_zero_is_invalid_verification_failure() {
655         // Block 0 from being the successful value since we serialize this to long life scratch, and
656         // the power on reset value for it is 0
657         assert!(
658             !ApRoVerificationResult::from(0).is_success(),
659             "0 must be a failure since 0 is PoR default for LLV scratch"
660         );
661     }
662 
663     #[test]
test_setting_not_provisioned()664     fn test_setting_not_provisioned() {
665         let error = VerifyError::SettingNotProvisioned;
666         let error = u32::from(error);
667         // 0x10 is the SettingNotProvisioned code,
668         // 0x000000 is unused
669         assert_eq!(error, 0x10_000000);
670     }
671 
672     #[test]
test_failed_verification()673     fn test_failed_verification() {
674         let error = VerifyError::FailedVerification(FailedVerificationDetail::SignatureVerifyFail);
675         let error = u32::from(error);
676         // 0x01 is the FailedVerification code,
677         // 0x00 is SignatureVerifyFail,
678         // 0x0000 is unused
679         assert_eq!(error, 0x01_00_0000);
680 
681         let error = VerifyError::FailedVerification(FailedVerificationDetail::DigestMismatch {
682             location: DigestLocation::GvdCache,
683             got: 0x11,
684             expected: 0x22,
685         });
686         let error = u32::from(error);
687         // 0x01 is the FailedVerification code,
688         // 0x10 DigestMismatch + 0x20 is for num valid root keys + 0x02 for GvdCache
689         // 0x11 is for got
690         // 0x22 is for expected
691         assert_eq!(error, 0x01_32_11_22);
692 
693         let error = VerifyError::FailedVerification(FailedVerificationDetail::DigestMismatch {
694             location: DigestLocation::ProtectedRegions,
695             got: 0x09,
696             expected: 0x80,
697         });
698         let error = u32::from(error);
699         // 0x01 is the FailedVerification code,
700         // 0x10 DigestMismatch + 0x20 is for num valid root keys + 0x01 for ProtectedRegions
701         // 0x09 is for got
702         // 0x80 is for expected
703         assert_eq!(error, 0x01_31_09_80);
704 
705         let error = VerifyError::FailedVerification(FailedVerificationDetail::DigestMismatch {
706             location: DigestLocation::RootKey,
707             got: 0x10,
708             expected: 0x02,
709         });
710         let error = u32::from(error);
711         // 0x01 is the FailedVerification code,
712         // 0x10 DigestMismatch + 0x20 is for num valid root keys + 0x03 for Rootkey
713         // 0x10 is for got
714         // 0x02 is for expected
715         assert_eq!(error, 0x01_33_10_02);
716 
717         let error = VerifyError::FailedVerification(FailedVerificationDetail::SignatureVerifyFail)
718             .with_failed_signature_location(SignatureLocation::Gscvd);
719         let error = u32::from(error);
720         // 0x01 is the FailedVerification code,
721         // 0x00 is SignatureVerifyFail,
722         // 0x01 is Gscvd signature location
723         // 0x00 is unused
724         assert_eq!(error, 0x01_00_01_00);
725 
726         let error = VerifyError::FailedVerification(FailedVerificationDetail::SignatureVerifyFail)
727             .with_failed_signature_location(SignatureLocation::Keyblock);
728         let error = u32::from(error);
729         // 0x01 is the FailedVerification code,
730         // 0x00 is SignatureVerifyFail,
731         // 0x02 is Keyblock signature location
732         // 0x00 is unused
733         assert_eq!(error, 0x01_00_02_00);
734     }
735 
736     #[test]
test_version_mismatch()737     fn test_version_mismatch() {
738         let error = VerifyError::VersionMismatch(VersionMismatchSource::Gscvd);
739         let error = u32::from(error);
740         // 0x0A is the VersionMismatch code,
741         // 0x01 is VersionMismatchSource::Gscvd,
742         // 0x0000 is unused
743         assert_eq!(error, 0x0A_01_0000);
744 
745         let error = VerifyError::VersionMismatch(VersionMismatchSource::Keyblock);
746         let error = u32::from(error);
747         // 0x0A is the VersionMismatch code,
748         // 0x02 is VersionMismatchSource::Keyblock,
749         // 0x0000 is unused
750         assert_eq!(error, 0x0A_02_0000);
751     }
752 
753     #[test]
test_unsupported_crypto_algorithm()754     fn test_unsupported_crypto_algorithm() {
755         let error = VerifyError::UnsupportedCryptoAlgorithm(CryptoAlgorithmSource::Gscvd, 0x123);
756         let error = u32::from(error);
757         // 0x09 is the UnsupportedCryptoAlgorithm code,
758         // 0x01 is CryptoAlgorithmSource::Gscvd,
759         // 0x0123 is detailed code
760         assert_eq!(error, 0x09_01_0123);
761 
762         let error =
763             VerifyError::UnsupportedCryptoAlgorithm(CryptoAlgorithmSource::Vb2PackedKey, 0x3);
764         let error = u32::from(error);
765         // 0x09 is the UnsupportedCryptoAlgorithm code,
766         // 0x04 is CryptoAlgorithmSource::Vb2PackedKey,
767         // 0x003 is detailed code
768         assert_eq!(error, 0x09_04_0003);
769     }
770 
771     #[test]
test_internal()772     fn test_internal() {
773         let error = VerifyError::Internal(InternalErrorSource::Crypto, 0x9876);
774         let error = u32::from(error);
775         // 0x0C is the Internal code,
776         // 0x02 is InternalErrorSource::Crypto,
777         // 0x9876 is detailed code
778         assert_eq!(error, 0x0C_02_9876);
779 
780         let error = VerifyError::Internal(InternalErrorSource::Kernel, 0x0011);
781         let error = u32::from(error);
782         // 0x0C is the Internal code,
783         // 0x01 is InternalErrorSource::Kernel,
784         // 0x0011 is detailed code
785         assert_eq!(error, 0x0C_01_0011);
786 
787         let error = VerifyError::Internal(InternalErrorSource::VerifyFlashRanges, 0x9900);
788         let error = u32::from(error);
789         // 0x0C is the Internal code,
790         // 0x03 is InternalErrorSource::VerifyFlashRanges,
791         // 0x9900 is detailed code
792         assert_eq!(error, 0x0C_03_9900);
793     }
794 
795     #[test]
test_board_id_mismatch()796     fn test_board_id_mismatch() {
797         let error = VerifyError::BoardIdMismatch(0x01234567, 0x89abcdef);
798         let error = u32::from(error);
799         // 0x0F is the BoardIdMismatch code,
800         // 0x012 is most significant 3 nibbles of got,
801         // 0x89a is most significant 3 nibbles of expected
802         assert_eq!(error, 0x0F_012_89a);
803     }
804 }
805