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