Skip to content

Commit

Permalink
[fix] Return fake random numbers if RNG h/w block unavailable (#935)
Browse files Browse the repository at this point in the history
  • Loading branch information
mhatrevi authored Oct 27, 2023
1 parent 4f9f8d3 commit 9b34966
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 30 deletions.
4 changes: 2 additions & 2 deletions FROZEN_IMAGES.sha384sum
Original file line number Diff line number Diff line change
@@ -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
15 changes: 15 additions & 0 deletions drivers/src/soc_ifc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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
Expand Down Expand Up @@ -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;
}
}

Expand Down
33 changes: 26 additions & 7 deletions drivers/src/trng.rs
Original file line number Diff line number Diff line change
@@ -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 `_`
Expand All @@ -26,7 +29,13 @@ impl Trng {
soc_ifc_trng: SocIfcTrngReg,
soc_ifc: &SocIfcReg,
) -> CaliptraResult<Self> {
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)))
Expand All @@ -52,17 +61,27 @@ impl Trng {
}

pub fn generate(&mut self) -> CaliptraResult<Array4x12> {
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())
},
}
}
}
2 changes: 2 additions & 0 deletions error/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion rom/dev/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <br> **Word 0**: X509 Key Id Algorithm (2 bits) 1: SHA1, 2: SHA256, 2: SHA384, 3: Fuse <br> **Word 1,2,3,4,5**: Subject Key Id <br> **Words 7,8**: Unique Endpoint ID |
| CPTRA_DBG_MANUF_SERVICE_REG | 16 | Manufacturing Services: <br> **Bit 0**: IDEVID CSR upload <br> **Bit 31**: Fake ROM image verify enable |
| CPTRA_DBG_MANUF_SERVICE_REG | 16 | Manufacturing Services: <br> **Bit 0**: IDEVID CSR upload <br> **Bit 1**: Random Number Generator Unavailable <br> **Bit 31**: Fake ROM image verify enable |

## 7. Vaults

Expand Down
53 changes: 37 additions & 16 deletions rom/dev/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());

Expand Down Expand Up @@ -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()),
);
}
56 changes: 56 additions & 0 deletions rom/dev/tests/rom_integration_tests/test_dice_derivations.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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();
}
9 changes: 5 additions & 4 deletions test/tests/caliptra_integration_tests/test_code_coverage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
// );
}

0 comments on commit 9b34966

Please sign in to comment.