From 9b34966344e1d0983342905775a7c6b65b6e4ea0 Mon Sep 17 00:00:00 2001 From: Vishal Mhatre <38512878+mhatrevi@users.noreply.github.com> Date: Fri, 27 Oct 2023 15:37:34 -0700 Subject: [PATCH] [fix] Return fake random numbers if RNG h/w block unavailable (#935) --- FROZEN_IMAGES.sha384sum | 4 +- drivers/src/soc_ifc.rs | 15 +++++ drivers/src/trng.rs | 33 ++++++++--- error/src/lib.rs | 2 + rom/dev/README.md | 2 +- rom/dev/src/main.rs | 53 ++++++++++++------ .../test_dice_derivations.rs | 56 +++++++++++++++++++ .../test_code_coverage.rs | 9 +-- 8 files changed, 144 insertions(+), 30 deletions(-) diff --git a/FROZEN_IMAGES.sha384sum b/FROZEN_IMAGES.sha384sum index 6ec72887b3..d2e57b01e8 100644 --- a/FROZEN_IMAGES.sha384sum +++ b/FROZEN_IMAGES.sha384sum @@ -1,3 +1,3 @@ # WARNING: Do not update this file without the approval of the Caliptra TAC -61fe1910f551e4349960f7470e888c08da73ca198088de0eb2774421383aa7f3c8e427f2d2f604faf07ed57262770f45 caliptra-rom-no-log.bin -6ece85186f5b6d1dc248be35e0957a95ac78609b5f1dc1cee507ccee5b4f88bdfbf39c0524ecbd645b46f1d0d6c2c142 caliptra-rom-with-log.bin +2607e3489598918ce7118dc6e82514416654cdaeb1a5695cf331c913b2311452bd31aab163649ffcc8f5797a797b69e1 caliptra-rom-no-log.bin +8b84b93ca4a10b02e1460a9dd4d056eae4b57f3b9d4f661f00eea193ce9db61027ad00370c9ddb2636bc630143fb26c9 caliptra-rom-with-log.bin diff --git a/drivers/src/soc_ifc.rs b/drivers/src/soc_ifc.rs index 9ce0266db4..c346eb784b 100644 --- a/drivers/src/soc_ifc.rs +++ b/drivers/src/soc_ifc.rs @@ -136,6 +136,14 @@ impl SocIfc { flags.contains(MfgFlags::GENERATE_IDEVID_CSR) } + /// Returns the flag indicating whether random number generation is unavailable. + pub fn mfg_flag_rng_unavailable(&self) -> bool { + let soc_ifc_regs = self.soc_ifc.regs(); + // Lower 16 bits are for mfg flags + let flags: MfgFlags = (soc_ifc_regs.cptra_dbg_manuf_service_reg().read() & 0xffff).into(); + flags.contains(MfgFlags::RNG_SUPPORT_UNAVAILABLE) + } + /// Check if verification is turned on for fake-rom pub fn verify_in_fake_mode(&self) -> bool { let soc_ifc_regs = self.soc_ifc.regs(); @@ -149,6 +157,11 @@ impl SocIfc { self.soc_ifc.regs().cptra_hw_config().read().i_trng_en() } + #[inline(always)] + pub fn cptra_dbg_manuf_service_flags(&mut self) -> MfgFlags { + (self.soc_ifc.regs().cptra_dbg_manuf_service_reg().read() & 0xffff).into() + } + /// Enable or disable WDT1 /// /// # Arguments @@ -288,6 +301,8 @@ bitflags::bitflags! { pub struct MfgFlags : u32 { /// Generate Initial Device Id Certificate Signing Request const GENERATE_IDEVID_CSR = 0x01; + /// RNG functionality unavailable + const RNG_SUPPORT_UNAVAILABLE = 0x2; } } diff --git a/drivers/src/trng.rs b/drivers/src/trng.rs index de21a86533..64ae6bfa0b 100644 --- a/drivers/src/trng.rs +++ b/drivers/src/trng.rs @@ -1,16 +1,19 @@ // Licensed under the Apache-2.0 license +use core::array; + use caliptra_error::{CaliptraError, CaliptraResult}; use caliptra_registers::{ csrng::CsrngReg, entropy_src::EntropySrcReg, soc_ifc::SocIfcReg, soc_ifc_trng::SocIfcTrngReg, }; -use crate::{trng_ext::TrngExt, Array4x12, Csrng}; +use crate::{trng_ext::TrngExt, Array4x12, Csrng, MfgFlags}; #[repr(u32)] pub enum Trng { Internal(Csrng) = 0xb714a2b1, External(TrngExt) = 0xf3702ce3, + MfgMode() = 0x0c702ce3, // Teach the compiler that "other" values are possible to encourage it not // to get too crazy with optimizations. Match statements should handle `_` @@ -26,7 +29,13 @@ impl Trng { soc_ifc_trng: SocIfcTrngReg, soc_ifc: &SocIfcReg, ) -> CaliptraResult { - if soc_ifc.regs().cptra_hw_config().read().i_trng_en() { + // If device is unlocked for debug and RNG support is unavailable, return a fake RNG. + let flags: MfgFlags = (soc_ifc.regs().cptra_dbg_manuf_service_reg().read() & 0xffff).into(); + if !soc_ifc.regs().cptra_security_state().read().debug_locked() + & flags.contains(MfgFlags::RNG_SUPPORT_UNAVAILABLE) + { + Ok(Self::MfgMode()) + } else if soc_ifc.regs().cptra_hw_config().read().i_trng_en() { Ok(Self::Internal(Csrng::new(csrng, entropy_src, soc_ifc)?)) } else { Ok(Self::External(TrngExt::new(soc_ifc_trng))) @@ -52,17 +61,27 @@ impl Trng { } pub fn generate(&mut self) -> CaliptraResult { + extern "C" { + fn cfi_panic_handler(code: u32) -> !; + } + match self { Self::Internal(csrng) => Ok(csrng.generate12()?.into()), Self::External(trng_ext) => trng_ext.generate(), - _ => { - extern "C" { - fn cfi_panic_handler(code: u32) -> !; - } + Self::MfgMode() => { unsafe { - cfi_panic_handler(CaliptraError::ROM_CFI_PANIC_UNEXPECTED_MATCH_BRANCH.into()) + let soc_ifc = SocIfcReg::new(); + if soc_ifc.regs().cptra_security_state().read().debug_locked() { + cfi_panic_handler( + CaliptraError::ROM_CFI_PANIC_FAKE_TRNG_USED_WITH_DEBUG_LOCK.into(), + ) + } } + Ok(array::from_fn(|_| 0xdeadbeef_u32).into()) } + _ => unsafe { + cfi_panic_handler(CaliptraError::ROM_CFI_PANIC_UNEXPECTED_MATCH_BRANCH.into()) + }, } } } diff --git a/error/src/lib.rs b/error/src/lib.rs index 32dc3ed8ed..1eb8146006 100644 --- a/error/src/lib.rs +++ b/error/src/lib.rs @@ -442,6 +442,8 @@ impl CaliptraError { pub const ROM_CFI_PANIC_TRNG_FAILURE: CaliptraError = CaliptraError::new_const(0x104005B); pub const ROM_CFI_PANIC_UNEXPECTED_MATCH_BRANCH: CaliptraError = CaliptraError::new_const(0x104005C); + pub const ROM_CFI_PANIC_FAKE_TRNG_USED_WITH_DEBUG_LOCK: CaliptraError = + CaliptraError::new_const(0x104005D); /// ROM Global Errors pub const ROM_GLOBAL_NMI: CaliptraError = CaliptraError::new_const(0x01050001); diff --git a/rom/dev/README.md b/rom/dev/README.md index 06ee4e581e..51519b1bcb 100644 --- a/rom/dev/README.md +++ b/rom/dev/README.md @@ -107,7 +107,7 @@ Following are the main FUSE & Architectural Registers used by the Caliptra ROM f | FUSE_RUNTIME_SVN | 128 | Runtime Security Version Number | | FUSE_ANTI_ROLLBACK_DISABLE | 1 | Disable SVN checking for FMC & Runtime when bit is set | | FUSE_IDEVID_CERT_ATTR | 768 | FUSE containing information for generating IDEVID CSR
**Word 0**: X509 Key Id Algorithm (2 bits) 1: SHA1, 2: SHA256, 2: SHA384, 3: Fuse
**Word 1,2,3,4,5**: Subject Key Id
**Words 7,8**: Unique Endpoint ID | -| CPTRA_DBG_MANUF_SERVICE_REG | 16 | Manufacturing Services:
**Bit 0**: IDEVID CSR upload
**Bit 31**: Fake ROM image verify enable | +| CPTRA_DBG_MANUF_SERVICE_REG | 16 | Manufacturing Services:
**Bit 0**: IDEVID CSR upload
**Bit 1**: Random Number Generator Unavailable
**Bit 31**: Fake ROM image verify enable | ## 7. Vaults diff --git a/rom/dev/src/main.rs b/rom/dev/src/main.rs index d69200c948..b3bb38331d 100644 --- a/rom/dev/src/main.rs +++ b/rom/dev/src/main.rs @@ -79,22 +79,7 @@ pub extern "C" fn rom_entry() -> ! { } // Check if TRNG is correctly sourced as per hw config. - cfi_assert_eq( - env.soc_ifc.hw_config_internal_trng(), - matches!(env.trng, Trng::Internal(_)), - ); - cfi_assert_eq( - !env.soc_ifc.hw_config_internal_trng(), - matches!(env.trng, Trng::External(_)), - ); - cfi_assert_eq( - env.soc_ifc.hw_config_internal_trng(), - matches!(env.trng, Trng::Internal(_)), - ); - cfi_assert_eq( - !env.soc_ifc.hw_config_internal_trng(), - matches!(env.trng, Trng::External(_)), - ); + validate_trng_config(&mut env); report_boot_status(RomBootStatus::CfiInitialized.into()); @@ -378,3 +363,39 @@ fn panic_is_possible() { // The existence of this symbol is used to inform test_panic_missing // that panics are possible. Do not remove or rename this symbol. } + +#[inline(always)] +fn validate_trng_config(env: &mut RomEnv) { + // NOTE: The usage of non-short-circuiting boolean operations (| and &) is + // explicit here, and necessary to prevent the compiler from inserting a ton + // of glitch-susceptible jumps into the generated code. + + cfi_assert_eq( + env.soc_ifc.hw_config_internal_trng() + & (!env.soc_ifc.mfg_flag_rng_unavailable() | env.soc_ifc.debug_locked()), + matches!(env.trng, Trng::Internal(_)), + ); + cfi_assert_eq( + !env.soc_ifc.hw_config_internal_trng() + & (!env.soc_ifc.mfg_flag_rng_unavailable() | env.soc_ifc.debug_locked()), + matches!(env.trng, Trng::External(_)), + ); + cfi_assert_eq( + env.soc_ifc.mfg_flag_rng_unavailable() & !env.soc_ifc.debug_locked(), + matches!(env.trng, Trng::MfgMode()), + ); + cfi_assert_eq( + env.soc_ifc.hw_config_internal_trng() + & (!env.soc_ifc.mfg_flag_rng_unavailable() | env.soc_ifc.debug_locked()), + matches!(env.trng, Trng::Internal(_)), + ); + cfi_assert_eq( + !env.soc_ifc.hw_config_internal_trng() + & (!env.soc_ifc.mfg_flag_rng_unavailable() | env.soc_ifc.debug_locked()), + matches!(env.trng, Trng::External(_)), + ); + cfi_assert_eq( + env.soc_ifc.mfg_flag_rng_unavailable() & !env.soc_ifc.debug_locked(), + matches!(env.trng, Trng::MfgMode()), + ); +} diff --git a/rom/dev/tests/rom_integration_tests/test_dice_derivations.rs b/rom/dev/tests/rom_integration_tests/test_dice_derivations.rs index 7df7046b1d..822e177ba0 100644 --- a/rom/dev/tests/rom_integration_tests/test_dice_derivations.rs +++ b/rom/dev/tests/rom_integration_tests/test_dice_derivations.rs @@ -1,10 +1,15 @@ // Licensed under the Apache-2.0 license +use caliptra_builder::firmware::rom_tests::TEST_FMC_WITH_UART; +use caliptra_builder::firmware::APP_WITH_UART; +use caliptra_builder::firmware::ROM_WITH_UART; use caliptra_builder::ImageOptions; use caliptra_common::mailbox_api::CommandId; use caliptra_common::RomBootStatus::*; +use caliptra_hw_model::BootParams; use caliptra_hw_model::Fuses; use caliptra_hw_model::HwModel; +use caliptra_hw_model::InitParams; use crate::helpers; @@ -77,3 +82,54 @@ fn test_cold_reset_status_reporting() { hw.step_until_boot_status(FmcAliasDerivationComplete.into(), false); hw.step_until_boot_status(ColdResetComplete.into(), false); } + +#[test] +fn test_cold_reset_success() { + let rom = caliptra_builder::build_firmware_rom(&ROM_WITH_UART).unwrap(); + let image_bundle = caliptra_builder::build_and_sign_image( + &TEST_FMC_WITH_UART, + &APP_WITH_UART, + ImageOptions::default(), + ) + .unwrap(); + + let mut hw = caliptra_hw_model::new(BootParams { + init_params: InitParams { + rom: &rom, + ..Default::default() + }, + fw_image: Some(&image_bundle.to_bytes().unwrap()), + ..Default::default() + }) + .unwrap(); + + hw.step_until_boot_status(ColdResetComplete.into(), true); + + hw.step_until_exit_success().unwrap(); +} + +#[test] +fn test_cold_reset_no_rng() { + let rom = caliptra_builder::build_firmware_rom(&ROM_WITH_UART).unwrap(); + let image_bundle = caliptra_builder::build_and_sign_image( + &TEST_FMC_WITH_UART, + &APP_WITH_UART, + ImageOptions::default(), + ) + .unwrap(); + + let mut hw = caliptra_hw_model::new(BootParams { + init_params: InitParams { + rom: &rom, + ..Default::default() + }, + fw_image: Some(&image_bundle.to_bytes().unwrap()), + initial_dbg_manuf_service_reg: 0x2, // Disable RNG + ..Default::default() + }) + .unwrap(); + + hw.step_until_boot_status(ColdResetComplete.into(), true); + + hw.step_until_exit_success().unwrap(); +} diff --git a/test/tests/caliptra_integration_tests/test_code_coverage.rs b/test/tests/caliptra_integration_tests/test_code_coverage.rs index 1ca6148864..0651aefe9e 100644 --- a/test/tests/caliptra_integration_tests/test_code_coverage.rs +++ b/test/tests/caliptra_integration_tests/test_code_coverage.rs @@ -32,8 +32,9 @@ fn test_emu_coverage() { coverage_from_bitmap, calculator::coverage_from_instr_trace(TRACE_PATH, &instr_pcs) ); - assert_eq!( - coverage_from_bitmap, - calculator::coverage_from_instr_trace(TRACE_PATH, &instr_pcs) - ); + // [TODO] Temporarily disabling due to flakiness. + // assert_eq!( + // coverage_from_bitmap, + // calculator::coverage_from_instr_trace(TRACE_PATH, &instr_pcs) + // ); }