Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[fix] CFI check for TRNG source #954

Merged
merged 8 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
6c8651061bc86da0ab38a62631282112c30d78980ba9ae37f3148b264e520bc200ccf03a2b76f903a492746745ee0195 caliptra-rom-no-log.bin
6a5ed1989df5f11820534fbdebf71f6090c5a2784140506d31a008a347c7281eaf3db50f80846a122f91af2d42047672 caliptra-rom-with-log.bin
72cfc1b0c55a98797e070a45f4008ea08b7b41ff0e1fdf7d86c76a271c0837f983d556f2172a1758e5a4a8a3750df916 caliptra-rom-no-log.bin
37c4803e98c48e124c54248b4f28f85f61445ecf6094e6ec1d4c7039111657479bb4c6c618d74d6fe59518186f4866bd caliptra-rom-with-log.bin
3 changes: 3 additions & 0 deletions cfi/lib/src/cfi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ pub enum CfiPanicInfo {
/// Random number generator error
TrngError,

/// An enum match statement finds an unexpected value.
UnexpectedMatchBranch,

/// Unknown error
UnknownError,
}
Expand Down
4 changes: 2 additions & 2 deletions cfi/lib/src/cfi_counter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ pub enum CfiCounter {}

impl CfiCounter {
/// Reset counter
#[inline(never)]
#[inline(always)]
pub fn reset(trng: &mut caliptra_drivers::Trng) {
prng().seed_from_trng(trng);
prng().mix_entropy_from_trng(trng);
Self::reset_internal();
}

Expand Down
10 changes: 5 additions & 5 deletions cfi/lib/src/xoshiro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ impl Xoshiro128 {
&*(addr as *const Xoshiro128)
}

pub fn seed_from_trng(&self, trng: &mut caliptra_drivers::Trng) {
pub fn mix_entropy_from_trng(&self, trng: &mut caliptra_drivers::Trng) {
loop {
if let Ok(entropy) = trng.generate() {
self.s0.set(entropy.0[0]);
self.s1.set(entropy.0[1]);
self.s2.set(entropy.0[2]);
self.s3.set(entropy.0[3]);
self.s0.set(self.s0.get() ^ entropy.0[0]);
self.s1.set(self.s1.get() ^ entropy.0[1]);
self.s2.set(self.s2.get() ^ entropy.0[2]);
self.s3.set(self.s3.get() ^ entropy.0[3]);
} else {
cfi_panic(CfiPanicInfo::TrngError)
}
Expand Down
9 changes: 4 additions & 5 deletions drivers/src/memory_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,12 @@ pub const ROM_ORG: u32 = 0x00000000;
pub const MBOX_ORG: u32 = 0x30000000;
pub const ICCM_ORG: u32 = 0x40000000;
pub const DCCM_ORG: u32 = 0x50000000;
// Region of ~ 1k bytes between DCCM_ORG and CFI_VAL_ORG is reserved for ROM's DATA_ORG
pub const CFI_XO_S0_ORG: u32 = 0x50000000;
pub const CFI_XO_S1_ORG: u32 = 0x50000004;
pub const CFI_XO_S2_ORG: u32 = 0x50000008;
pub const CFI_XO_S3_ORG: u32 = 0x5000000C;
pub const CFI_VAL_ORG: u32 = 0x500003E4;
pub const CFI_MASK_ORG: u32 = 0x500003E8;
pub const CFI_XO_S0_ORG: u32 = 0x500003EC;
pub const CFI_XO_S1_ORG: u32 = 0x500003F0;
pub const CFI_XO_S2_ORG: u32 = 0x500003F4;
pub const CFI_XO_S3_ORG: u32 = 0x500003F8;
pub const BOOT_STATUS_ORG: u32 = 0x500003FC;
pub const MAN1_ORG: u32 = 0x50000400;
pub const MAN2_ORG: u32 = 0x50001C00;
Expand Down
5 changes: 5 additions & 0 deletions drivers/src/soc_ifc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ impl SocIfc {
((val >> 31) & 1) != 0
}

#[inline(always)]
pub fn hw_config_internal_trng(&mut self) -> bool {
self.soc_ifc.regs().cptra_hw_config().read().i_trng_en()
}

/// Enable or disable WDT1
///
/// # Arguments
Expand Down
21 changes: 18 additions & 3 deletions drivers/src/trng.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
// Licensed under the Apache-2.0 license

use caliptra_error::CaliptraResult;
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};

#[repr(u32)]
pub enum Trng {
Internal(Csrng),
External(TrngExt),
Internal(Csrng) = 0xb714a2b1,
External(TrngExt) = 0xf3702ce3,

// Teach the compiler that "other" values are possible to encourage it not
// to get too crazy with optimizations. Match statements should handle `_`
// by jumping to the CFI handler.
Invalid0 = 0x0060f20f,
Invalid1 = 0x0a8dfe7a,
}

impl Trng {
Expand Down Expand Up @@ -48,6 +55,14 @@ impl Trng {
match self {
Self::Internal(csrng) => Ok(csrng.generate12()?.into()),
Self::External(trng_ext) => trng_ext.generate(),
_ => {
extern "C" {
fn cfi_panic_handler(code: u32) -> !;
}
unsafe {
cfi_panic_handler(CaliptraError::ROM_CFI_PANIC_UNEXPECTED_MATCH_BRANCH.into())
}
}
}
}
}
6 changes: 6 additions & 0 deletions drivers/test-fw/src/bin/trng_driver_responder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ pub fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}

#[no_mangle]
extern "C" fn cfi_panic_handler(code: u32) -> ! {
println!("CFI Panic code=0x{:08X}", code);
loop {}
}

#[no_mangle]
extern "C" fn main() {
let csrng_reg = unsafe { CsrngReg::new() };
Expand Down
2 changes: 2 additions & 0 deletions error/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,8 @@ impl CaliptraError {
pub const ROM_CFI_PANIC_ASSERT_GE_FAILURE: CaliptraError = CaliptraError::new_const(0x1040059);
pub const ROM_CFI_PANIC_ASSERT_LE_FAILURE: CaliptraError = CaliptraError::new_const(0x104005A);
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);

/// ROM Global Errors
pub const ROM_GLOBAL_NMI: CaliptraError = CaliptraError::new_const(0x01050001);
Expand Down
8 changes: 8 additions & 0 deletions fmc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,14 @@ extern "C" fn nmi_handler(trap_record: &TrapRecord) {

handle_fatal_error(error.into());
}

#[no_mangle]
extern "C" fn cfi_panic_handler(code: u32) -> ! {
cprintln!("CFI Panic code=0x{:08X}", code);

handle_fatal_error(code);
}

#[panic_handler]
#[inline(never)]
#[cfg(not(feature = "std"))]
Expand Down
24 changes: 22 additions & 2 deletions rom/dev/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ Abstract:
#![cfg_attr(feature = "fake-rom", allow(unused_imports))]

use crate::{lock::lock_registers, print::HexBytes};
use caliptra_cfi_lib::CfiCounter;
use caliptra_cfi_lib::{cfi_assert_eq, CfiCounter};
use caliptra_registers::soc_ifc::SocIfcReg;
use core::hint::black_box;

use caliptra_drivers::{
cprintln, report_fw_error_fatal, report_fw_error_non_fatal, CaliptraError, Ecc384, Hmac384,
KeyVault, Mailbox, ResetReason, Sha256, Sha384, Sha384Acc, ShaAccLockState, SocIfc,
KeyVault, Mailbox, ResetReason, Sha256, Sha384, Sha384Acc, ShaAccLockState, SocIfc, Trng,
};
use caliptra_error::CaliptraResult;
use caliptra_image_types::RomInfo;
Expand Down Expand Up @@ -70,10 +70,30 @@ pub extern "C" fn rom_entry() -> ! {
if !cfg!(feature = "no-cfi") {
cprintln!("[state] CFI Enabled");
CfiCounter::reset(&mut env.trng);
CfiCounter::reset(&mut env.trng);
CfiCounter::reset(&mut env.trng);
} else {
cprintln!("[state] CFI Disabled");
}

// 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(_)),
);

let _lifecyle = match env.soc_ifc.lifecycle() {
caliptra_drivers::Lifecycle::Unprovisioned => "Unprovisioned",
caliptra_drivers::Lifecycle::Manufacturing => "Manufacturing",
Expand Down
2 changes: 2 additions & 0 deletions rom/dev/src/rom.ld
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ ROM_ORG = 0x00000000;
ICCM_ORG = 0x40000000;
DCCM_ORG = 0x50000000;
DATA_ORG = 0x50000000;
DCCM_POST_CFI_ENTROPY_ORG = 0x50000010;
STACK_ORG = 0x5001C000;
ESTACK_ORG = 0x5001F800;
NSTACK_ORG = 0x5001FC00;
Expand All @@ -33,6 +34,7 @@ ROM_RELAXATION_PADDING = 4k;
ROM_SIZE = 48K;
ICCM_SIZE = 128K;
DCCM_SIZE = 128K;
DCCM_POST_CFI_ENTROPY_SIZE = 131056; /* DCCM_SIZE - (sizeof(CFI_XO_S0) + sizeof(CFI_XO_S1) + sizeof(CFI_XO_S2) + sizeof(CFI_XO_S3)) */
DATA_SIZE = 996;
STACK_SIZE = 14K;
ESTACK_SIZE = 1K;
Expand Down
29 changes: 26 additions & 3 deletions rom/dev/src/start.S
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,21 @@ _start:
andi t1, t1, 0x3
bne t1, x0, post_ecc_init

//
// Cold Boot
//

// Zero ICCM
la a0, ICCM_ORG // dest
la a1, ICCM_SIZE // len
call _zero_mem256

la a0, DCCM_ORG // dest
la a1, DCCM_SIZE // len
call _zero_mem256
// Zero out post-CFI Entropy region
// CFI region is used as an additional entropy source for CFI RNG,
// hence it is not cleared.
la a0, DCCM_POST_CFI_ENTROPY_ORG // dest
la a1, DCCM_POST_CFI_ENTROPY_SIZE // len
call _zero_mem32
mhatrevi marked this conversation as resolved.
Show resolved Hide resolved

post_ecc_init:

Expand Down Expand Up @@ -151,6 +158,22 @@ _zero_mem256:
ret
.cfi_endproc

.section .init.text, "ax"
.align 2
_zero_mem32:
.cfi_startproc
li t0, 4
1:
beqz a1, 1f
sw x0, 0(a0)
addi a0, a0, 4
sub a1, a1, t0
j 1b
1:
ret
.cfi_endproc


.section .init.text, "ax"
.align 2
_copy_mem32:
Expand Down
31 changes: 29 additions & 2 deletions rom/dev/test-fw/asm_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ core::arch::global_asm!(include_str!("../src/start.S"));
mod exception;

use caliptra_drivers::cprintln;
use caliptra_drivers::memory_layout::*;
use caliptra_drivers::ExitCtrl;

#[no_mangle]
Expand Down Expand Up @@ -67,17 +68,32 @@ unsafe fn is_zeroed(mut ptr: *const u32, mut size: usize) -> bool {
extern "C" {
fn _zero_mem256(dest: *mut u32, len: usize);
fn _copy_mem32(dest: *mut u32, src: *const u32, len: usize);
fn _zero_mem32(dest: *mut u32, len: usize);
static mut DCCM_POST_CFI_ENTROPY_ORG: u8;
static mut DCCM_POST_CFI_ENTROPY_SIZE: u8;
}

#[no_mangle]
pub extern "C" fn rom_entry() -> ! {
const SIZEOF_U32: usize = core::mem::size_of::<u32>();
unsafe {
let dccm_post_cfi_entropy_org = (&mut DCCM_POST_CFI_ENTROPY_ORG as *mut u8) as usize;
let dccm_post_cfi_entropy_size = (&mut DCCM_POST_CFI_ENTROPY_SIZE as *mut u8) as usize;

// Test that memory is cleared at startup
assert!(is_zeroed(0x4000_0000 as *const u32, 1024 * 128));

// Check everything but the last 3k, which might contain non-zero stack bytes
assert!(is_zeroed(0x5000_0000 as *const u32, 1024 * (128 - 3)));
// Test if the DCCM region after the CFI entropy is cleared, except for the last 3k, which might contain non-zero stack bytes
assert!(is_zeroed(
dccm_post_cfi_entropy_org as *const u32,
dccm_post_cfi_entropy_size - (3 * 1024)
));

// Check if CFI entropy source is not cleared.
assert_ne!((CFI_XO_S0_ORG as *const u32).read_volatile(), 0);
assert_ne!((CFI_XO_S1_ORG as *const u32).read_volatile(), 0);
assert_ne!((CFI_XO_S2_ORG as *const u32).read_volatile(), 0);
assert_ne!((CFI_XO_S3_ORG as *const u32).read_volatile(), 0);

// Test _zero_mem256

Expand All @@ -96,6 +112,17 @@ pub extern "C" fn rom_entry() -> ! {
// len rounds up to the nearest 32-byte chunk
assert_eq!(test_mem[32..42], [1, 0, 0, 0, 0, 0, 0, 0, 0, 1]);

// Test _zero_mem32

test_mem[4..12].copy_from_slice(&[0x5555_5555u32; 8]);
_zero_mem32(test_mem.as_mut_ptr().offset(4), 8 * SIZEOF_U32);
assert_eq!(test_mem[3..13], [1, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
_zero_mem32(test_mem.as_mut_ptr().offset(13), 16 * SIZEOF_U32);
assert_eq!(
test_mem[12..30],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
);

// Test _copy_mem32

test_mem[45..48].copy_from_slice(&[0x0011_2233, 0x4455_6677, 0x8899_aabb]);
Expand Down
9 changes: 9 additions & 0 deletions test-harness/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,15 @@ macro_rules! test_suite {
}
}

#[no_mangle]
extern "C" fn cfi_panic_handler(code: u32) -> ! {
println!("CFI Panic code=0x{:08X}", code);

caliptra_drivers::report_fw_error_fatal(0xdead2);

caliptra_drivers::ExitCtrl::exit(u32::MAX)
}

#[no_mangle]
pub extern "C" fn main() {
$(
Expand Down
15 changes: 12 additions & 3 deletions test/tests/smoke_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -588,10 +588,11 @@ fn test_rt_wdt_timeout() {
const RUNTIME_GLOBAL_WDT_EPIRED: u32 = 0x000E001F;
let rom = caliptra_builder::build_firmware_rom(&firmware::ROM_WITH_UART).unwrap();

// TODO: Don't hard-code these; maybe measure from a previous boot?
let rt_wdt_timeout_cycles = if cfg!(any(feature = "verilator", feature = "fpga_realtime")) {
27_000_000
} else {
2_700_000
2_720_000
};

let security_state = *caliptra_hw_model::SecurityState::default().set_debug_locked(true);
Expand All @@ -604,7 +605,11 @@ fn test_rt_wdt_timeout() {

let mut hw = run_test(None, None, Some(init_params));

hw.step_until(|m| m.soc_ifc().cptra_fw_error_fatal().read() == RUNTIME_GLOBAL_WDT_EPIRED);
hw.step_until(|m| m.soc_ifc().cptra_fw_error_fatal().read() != 0);
assert_eq!(
hw.soc_ifc().cptra_fw_error_fatal().read(),
RUNTIME_GLOBAL_WDT_EPIRED
)
}

#[test]
Expand All @@ -629,5 +634,9 @@ fn test_fmc_wdt_timeout() {

let mut hw = caliptra_test::run_test(None, None, Some(init_params));

hw.step_until(|m| m.soc_ifc().cptra_fw_error_fatal().read() == FMC_GLOBAL_WDT_EPIRED);
hw.step_until(|m| m.soc_ifc().cptra_fw_error_fatal().read() != 0);
assert_eq!(
hw.soc_ifc().cptra_fw_error_fatal().read(),
FMC_GLOBAL_WDT_EPIRED
);
}
Loading