diff --git a/Cargo.lock b/Cargo.lock index f120171597..c65eaa597c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -193,6 +193,27 @@ dependencies = [ "once_cell", ] +[[package]] +name = "caliptra-cfi-derive" +version = "0.1.0" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "caliptra-cfi-lib" +version = "0.1.0" +dependencies = [ + "caliptra-cfi-derive", + "caliptra-drivers", + "caliptra-registers", + "caliptra_common", + "ufmt", +] + [[package]] name = "caliptra-cpu" version = "0.1.0" @@ -537,6 +558,8 @@ name = "caliptra-rom" version = "0.1.0" dependencies = [ "caliptra-builder", + "caliptra-cfi-derive", + "caliptra-cfi-lib", "caliptra-drivers", "caliptra-error", "caliptra-hw-model", diff --git a/Cargo.toml b/Cargo.toml index 8ce6990f6b..9d390561b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,8 @@ exclude = [ members = [ "builder", + "cfi/lib", + "cfi/derive", "ci-tools/file-header-fix", "ci-tools/size-history", "common", @@ -74,6 +76,8 @@ arrayref = "0.3.6" asn1 = "0.13.0" bitfield = "0.14.0" bitflags = "2.0.1" +caliptra-cfi-lib = { path = "cfi/lib", default-features = false, features = ["cfi", "cfi-counter" ] } +caliptra-cfi-derive = { path = "cfi/derive" } caliptra_common = { path = "common", default-features = false } caliptra-builder = { path = "builder" } caliptra-cpu = { path = "cpu" } diff --git a/cfi/derive/Cargo.toml b/cfi/derive/Cargo.toml new file mode 100644 index 0000000000..30bd2583ef --- /dev/null +++ b/cfi/derive/Cargo.toml @@ -0,0 +1,16 @@ +# Licensed under the Apache-2.0 license + +[package] +name = "caliptra-cfi-derive" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true +doctest = false + +[dependencies] +syn = { version = "1.0.107", features = ["extra-traits", "full"] } +quote = "1.0.23" +proc-macro2 = "1.0.51" +paste = "1.0.11" diff --git a/cfi/derive/src/lib.rs b/cfi/derive/src/lib.rs new file mode 100644 index 0000000000..0a627b640a --- /dev/null +++ b/cfi/derive/src/lib.rs @@ -0,0 +1,79 @@ +/*++ + +Licensed under the Apache-2.0 license. + +File Name: + + lib.rs + +Abstract: + + File contains CFI procedural macro. + +References: + https://tf-m-user-guide.trustedfirmware.org/design_docs/tfm_physical_attack_mitigation.html + https://github.com/rust-embedded/riscv/blob/master/src/asm.rs + +--*/ + +use proc_macro::TokenStream; +use quote::{format_ident, quote, ToTokens}; +use syn::__private::TokenStream2; +use syn::parse_macro_input; +use syn::parse_quote; +use syn::FnArg; +use syn::ItemFn; + +#[proc_macro_attribute] +pub fn cfi_mod_fn(_args: TokenStream, input: TokenStream) -> TokenStream { + cfi_fn(true, input) +} + +#[proc_macro_attribute] +pub fn cfi_impl_fn(_args: TokenStream, input: TokenStream) -> TokenStream { + cfi_fn(false, input) +} + +fn cfi_fn(mod_fn: bool, input: TokenStream) -> TokenStream { + let mut wrapper_fn: ItemFn = parse_macro_input!(input as ItemFn); + let mut orig_fn = wrapper_fn.clone(); + orig_fn.sig.ident = format_ident!("__cfi_{}", wrapper_fn.sig.ident); + orig_fn.attrs.clear(); + orig_fn.vis = syn::Visibility::Inherited; + + let fn_name = format_ident!("{}", orig_fn.sig.ident); + + let param_names: Vec = orig_fn + .sig + .inputs + .iter() + .map(|input| match input { + FnArg::Receiver(r) => r.self_token.to_token_stream(), + FnArg::Typed(p) => p.pat.to_token_stream(), + }) + .collect(); + + let fn_call = if mod_fn { + quote!(#fn_name( #(#param_names,)* )) + } else { + quote!(Self::#fn_name( #(#param_names,)* )) + }; + + wrapper_fn.block.stmts.clear(); + wrapper_fn.block.stmts = parse_quote!( + let saved_ctr = caliptra_cfi_lib::CfiCounter::increment(); + caliptra_cfi_lib::CfiCounter::delay(); + let ret = #fn_call; + caliptra_cfi_lib::CfiCounter::delay(); + let new_ctr = caliptra_cfi_lib::CfiCounter::decrement(); + caliptra_cfi_lib::CfiCounter::assert_eq(saved_ctr, new_ctr); + ret + ); + + let code = quote! { + #wrapper_fn + #orig_fn + }; + + code.into() +} diff --git a/cfi/lib/Cargo.toml b/cfi/lib/Cargo.toml new file mode 100644 index 0000000000..37c7766ffa --- /dev/null +++ b/cfi/lib/Cargo.toml @@ -0,0 +1,25 @@ +# Licensed under the Apache-2.0 license + +[package] +name = "caliptra-cfi-lib" +version = "0.1.0" +edition = "2021" + +[lib] +doctest = false + +[dependencies] +caliptra_common = { workspace = true, default-features = false } +caliptra-drivers.workspace = true +caliptra-registers.workspace = true +ufmt.workspace = true + +[dev-dependencies] +caliptra-cfi-derive.workspace = true + +[features] +default = ["cfi", "cfi-counter", "cfi-test"] +cfi = [] +cfi-counter = [] +cfi-test = [] + diff --git a/cfi/lib/src/cfi.rs b/cfi/lib/src/cfi.rs new file mode 100644 index 0000000000..9f96614636 --- /dev/null +++ b/cfi/lib/src/cfi.rs @@ -0,0 +1,179 @@ +/*++ + +Licensed under the Apache-2.0 license. + +File Name: + + cfi.rs + +Abstract: + + File contains CFI launder implementation. + +References: + https://github.com/lowRISC/opentitan/blob/7a61300cf7c409fa68fd892942c1d7b58a7cd4c0/sw/device/lib/base/hardened.h#L260 + +--*/ + +use caliptra_drivers::CaliptraError; +use core::cfg; +use core::cmp::{Eq, Ord, PartialEq, PartialOrd}; +use core::marker::Copy; + +/// CFI Panic Information +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub enum CfiPanicInfo { + /// CFI Counter decode error + CounterCorrupt, + + /// CFI Counter overflow + CounterOverflow, + + /// CFI Counter underflow + CounterUnderflow, + + /// CFI Counter mismatch + CounterMismatch, + + /// CFI Assert Equal failed + AssertEqFail, + + /// CFI Assert Not Equal failed + AssertNeFail, + + /// CFI Greater Than failed + AssertGtFail, + + /// CFI Less Than failed + AssertLtFail, + + /// CFI Greater Than Equal failed + AssertGeFail, + + /// CFI Less Than Equal failed + AssertLeFail, + + /// Random number generator error + TrngError, + + /// Unknown error + UnknownError, +} + +impl From for CaliptraError { + /// Converts to this type from the input type. + fn from(info: CfiPanicInfo) -> CaliptraError { + match info { + CfiPanicInfo::CounterCorrupt => CaliptraError::ROM_CFI_PANIC_COUNTER_CORRUPT, + CfiPanicInfo::CounterOverflow => CaliptraError::ROM_CFI_PANIC_COUNTER_OVERFLOW, + CfiPanicInfo::CounterUnderflow => CaliptraError::ROM_CFI_PANIC_COUNTER_UNDERFLOW, + CfiPanicInfo::CounterMismatch => CaliptraError::ROM_CFI_PANIC_COUNTER_MISMATCH, + CfiPanicInfo::AssertEqFail => CaliptraError::ROM_CFI_PANIC_ASSERT_EQ_FAILURE, + CfiPanicInfo::AssertNeFail => CaliptraError::ROM_CFI_PANIC_ASSERT_NE_FAILURE, + CfiPanicInfo::AssertGtFail => CaliptraError::ROM_CFI_PANIC_ASSERT_GT_FAILURE, + CfiPanicInfo::AssertLtFail => CaliptraError::ROM_CFI_PANIC_ASSERT_LT_FAILURE, + CfiPanicInfo::AssertGeFail => CaliptraError::ROM_CFI_PANIC_ASSERT_GE_FAILURE, + CfiPanicInfo::AssertLeFail => CaliptraError::ROM_CFI_PANIC_ASSERT_LE_FAILURE, + CfiPanicInfo::TrngError => CaliptraError::ROM_CFI_PANIC_TRNG_FAILURE, + _ => CaliptraError::ROM_CFI_PANIC_UNKNOWN, + } + } +} + +/// Launder the value to prevent compiler optimization +/// +/// # Arguments +/// +/// * `val` - Value to launder +/// +/// # Returns +/// +/// `T` - Same value +pub fn cfi_launder(val: T) -> T { + if cfg!(feature = "cfi") { + // Note: The black box seems to be disabling more optimization + // than necessary and results in larger binary size + core::hint::black_box(val) + } else { + val + } +} + +/// Control flow integrity panic +/// +/// This panic is raised when the control flow integrity error is detected +/// +/// # Arguments +/// +/// * `info` - Panic information +/// +/// # Returns +/// +/// `!` - Never returns +#[inline(never)] +pub fn cfi_panic(info: CfiPanicInfo) -> ! { + // Prevent the compiler from optimizing the reason + let _ = cfi_launder(info); + + #[cfg(feature = "cfi")] + { + #[cfg(feature = "cfi-test")] + { + panic!("CFI Panic = {:04x?}", info); + } + + #[cfg(not(feature = "cfi-test"))] + { + extern "C" { + fn cfi_panic_handler(code: u32) -> !; + } + unsafe { + cfi_panic_handler(CaliptraError::from(info).into()); + } + } + } + + #[cfg(not(feature = "cfi"))] + { + unimplemented!() + } +} + +macro_rules! cfi_assert_macro { + ($name: ident, $op: tt, $trait1: path, $trait2: path, $panic_info: ident) => { + /// CFI Binary Condition Assertion + /// + /// # Arguments + /// + /// `a` - Left hand side + /// `b` - Right hand side + #[inline(never)] + #[allow(unused)] + pub fn $name(lhs: T, rhs: T) + where + T: $trait1 + $trait2, + { + if cfg!(feature = "cfi") { + if !(lhs $op rhs) { + cfi_panic(CfiPanicInfo::$panic_info); + } + } else { + lhs $op rhs; + } + } + }; +} + +cfi_assert_macro!(cfi_assert_eq, ==, Eq, PartialEq, AssertEqFail); +cfi_assert_macro!(cfi_assert_ne, !=, Eq, PartialEq, AssertNeFail); +cfi_assert_macro!(cfi_assert_gt, >, Ord, PartialOrd, AssertGtFail); +cfi_assert_macro!(cfi_assert_lt, <, Ord, PartialOrd, AssertLtFail); +cfi_assert_macro!(cfi_assert_ge, >=, Ord, PartialOrd, AssertGeFail); +cfi_assert_macro!(cfi_assert_le, <=, Ord, PartialOrd, AssertLeFail); + +#[macro_export] +macro_rules! cfi_assert { + ($cond: expr) => { + cfi_assert_eq($cond, true) + }; +} diff --git a/cfi/lib/src/cfi_ctr.rs b/cfi/lib/src/cfi_ctr.rs new file mode 100644 index 0000000000..0ef505603a --- /dev/null +++ b/cfi/lib/src/cfi_ctr.rs @@ -0,0 +1,223 @@ +/*++ + +Licensed under the Apache-2.0 license. + +File Name: + + cfi_ctr.rs + +Abstract: + + File contains CFI Integer and Counter implementations. The counter is based on ideas from + Trusted Firmware-M firmware. + +References: + https://tf-m-user-guide.trustedfirmware.org/design_docs/tfm_physical_attack_mitigation.html + +--*/ + +use crate::cfi::{cfi_panic, CfiPanicInfo}; +use crate::xoshiro::Xoshiro128; +#[cfg(not(feature = "cfi-test"))] +use caliptra_common::memory_layout::{CFI_MASK_ORG, CFI_VAL_ORG}; +use core::default::Default; + +#[cfg(feature = "cfi-test")] +static mut CFI_VAL: u32 = 0u32; +#[cfg(feature = "cfi-test")] +static mut CFI_MASK: u32 = 0u32; + +/// CFI Integer +#[derive(Debug, Eq, PartialEq, Copy, Clone)] +pub struct CfiInt { + /// Actual Value + val: u32, + + /// Masked Value + masked_val: u32, +} + +impl CfiInt { + /// Integer mask with high hamming distance + const MASK: u32 = 0xA5A5A5A5; + + /// Create integer from raw values + fn from_raw(val: u32, masked_val: u32) -> Self { + Self { val, masked_val } + } + + /// Encode the integer + fn encode(val: u32) -> Self { + Self { + val, + masked_val: val ^ Self::MASK, + } + } + + /// Check if the integer is valid + fn is_valid(&self) -> bool { + self.val == self.masked_val ^ Self::MASK + } +} + +impl Default for CfiInt { + /// Returns the "default value" for a type. + fn default() -> Self { + Self::encode(0) + } +} + +fn prng() -> &'static Xoshiro128 { + use caliptra_drivers::memory_layout::CFI_XO_S0_ORG; + if cfg!(feature = "cfi-test") { + static mut STATE: Xoshiro128 = Xoshiro128::new_unseeded(); + unsafe { &STATE } + } else { + unsafe { Xoshiro128::from_address(CFI_XO_S0_ORG) } + } +} + +/// CFI counter +pub enum CfiCounter {} + +impl CfiCounter { + /// Reset counter + #[inline(never)] + pub fn reset(trng: &mut caliptra_drivers::Trng) { + prng().seed_from_trng(trng); + Self::reset_internal(); + } + + #[cfg(feature = "cfi-test")] + pub fn reset_for_test() { + Self::reset_internal() + } + + fn reset_internal() { + Self::write(CfiInt::default()); + } + + // Zero the counter + pub fn corrupt() { + Self::write(CfiInt { + val: 0, + masked_val: 0, + }); + } + + /// Increment counter + #[inline(never)] + pub fn increment() -> CfiInt { + if cfg!(all(feature = "cfi", feature = "cfi-counter")) { + let int = Self::read(); + if !int.is_valid() { + cfi_panic(CfiPanicInfo::CounterCorrupt); + } + + let (new, overflow) = int.val.overflowing_add(1); + if overflow { + cfi_panic(CfiPanicInfo::CounterOverflow); + } + + let new_int = CfiInt::encode(new); + Self::write(new_int); + + int + } else { + CfiInt::default() + } + } + + /// Decrement Counter + #[inline(never)] + pub fn decrement() -> CfiInt { + if cfg!(all(feature = "cfi", feature = "cfi-counter")) { + let val = Self::read(); + if !val.is_valid() { + cfi_panic(CfiPanicInfo::CounterCorrupt); + } + + let (new, underflow) = val.val.overflowing_sub(1); + if underflow { + cfi_panic(CfiPanicInfo::CounterUnderflow); + } + + let new_val = CfiInt::encode(new); + Self::write(new_val); + + Self::read() + } else { + CfiInt::default() + } + } + + /// Assert the counters are equal + #[inline(never)] + pub fn assert_eq(val1: CfiInt, val2: CfiInt) { + if cfg!(all(feature = "cfi", feature = "cfi-counter")) { + if !val1.is_valid() { + cfi_panic(CfiPanicInfo::CounterCorrupt); + } + if !val2.is_valid() { + cfi_panic(CfiPanicInfo::CounterCorrupt); + } + if val1 != val2 { + cfi_panic(CfiPanicInfo::CounterMismatch); + } + } + } + + #[inline(never)] + pub fn delay() { + #[cfg(all(target_arch = "riscv32", feature = "cfi", feature = "cfi-counter"))] + unsafe { + let cycles = prng().next() % 256; + let real_cyc = 1 + cycles / 2; + core::arch::asm!( + "1:", + "addi {0}, {0}, -1", + "bne {0}, zero, 1b", + inout(reg) real_cyc => _, + options(nomem, nostack), + ); + } + } + + /// Read counter value + fn read() -> CfiInt { + unsafe { + #[cfg(feature = "cfi-test")] + { + CfiInt::from_raw( + core::ptr::read_volatile(&CFI_VAL as *const u32), + core::ptr::read_volatile(&CFI_MASK as *const u32), + ) + } + + #[cfg(not(feature = "cfi-test"))] + { + CfiInt::from_raw( + core::ptr::read_volatile(CFI_VAL_ORG as *const u32), + core::ptr::read_volatile(CFI_MASK_ORG as *const u32), + ) + } + } + } + + /// Write counter value + fn write(val: CfiInt) { + unsafe { + #[cfg(feature = "cfi-test")] + { + core::ptr::write_volatile(&mut CFI_VAL as *mut u32, val.val); + core::ptr::write_volatile(&mut CFI_MASK as *mut u32, val.masked_val); + } + + #[cfg(not(feature = "cfi-test"))] + { + core::ptr::write_volatile(CFI_VAL_ORG as *mut u32, val.val); + core::ptr::write_volatile(CFI_MASK_ORG as *mut u32, val.masked_val); + } + } + } +} diff --git a/cfi/lib/src/lib.rs b/cfi/lib/src/lib.rs new file mode 100644 index 0000000000..503873b610 --- /dev/null +++ b/cfi/lib/src/lib.rs @@ -0,0 +1,20 @@ +/*++ + +Licensed under the Apache-2.0 license. + +File Name: + + lib.rs + +--*/ + +#![no_std] +extern crate core; + +mod cfi; +mod cfi_ctr; +mod xoshiro; + +pub use cfi::*; +pub use cfi_ctr::{CfiCounter, CfiInt}; +pub use xoshiro::Xoshiro128; diff --git a/cfi/lib/src/xoshiro.rs b/cfi/lib/src/xoshiro.rs new file mode 100644 index 0000000000..74818b8978 --- /dev/null +++ b/cfi/lib/src/xoshiro.rs @@ -0,0 +1,116 @@ +/*++ + +Licensed under the Apache-2.0 license. + +File Name: + + xoshiro.rs + +Abstract: + + File contains implementation of RNG based on System.Random Xoshiro128** algorithm. + +References: + https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Random.Xoshiro128StarStarImpl.cs + +--*/ + +use core::cell::Cell; + +use crate::{cfi_panic, CfiPanicInfo}; + +/// Provides an implementation of the xoshiro128** algorithm. This implementation is used +/// on 32-bit when no seed is specified and an instance of the base Random class is constructed. +/// As such, we are free to implement however we see fit, without back compat concerns around +/// the sequence of numbers generated or what methods call what other methods. +#[repr(C)] +pub struct Xoshiro128 { + // It is critical for safety that every bit-pattern of this struct + // is valid (no padding, no enums, no references), similar to the requirements for + // zerocopy::FromBytes. + s0: Cell, + s1: Cell, + s2: Cell, + s3: Cell, +} + +impl Xoshiro128 { + /// Create a new instance of the xoshiro128** algorithm seeded with zeroes. + pub(crate) const fn new_unseeded() -> Self { + Self::new_with_seed(0, 0, 0, 0) + } + + /// Create a new instance of the xoshiro128** algorithm with a seed. + pub const fn new_with_seed(s0: u32, s1: u32, s2: u32, s3: u32) -> Self { + Self { + s0: Cell::new(s0), + s1: Cell::new(s1), + s2: Cell::new(s2), + s3: Cell::new(s3), + } + } + + /// Get a reference to a xoshiro instance backed by static memory + /// + /// # Safety + /// + /// Caller must verify that the memory locations between `addr` and + /// `addr + size_of::()` are valid and meet the alignment + /// requirements of Xoshiro128, and are not used for anything else. + pub unsafe fn from_address(addr: u32) -> &'static Self { + &*(addr as *const Xoshiro128) + } + + pub fn seed_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]); + } else { + cfi_panic(CfiPanicInfo::TrngError) + } + + // Atlease one value must be non-zero + if self.s0.get() | self.s1.get() | self.s2.get() | self.s3.get() != 0 { + break; + } + } + } + + /// Get the next random number + pub fn next(&self) -> u32 { + // next is based on the algorithm from http://prng.di.unimi.it/xoshiro128starstar.c: + // + // Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) + // + // To the extent possible under law, the author has dedicated all copyright + // and related and neighboring rights to this software to the public domain + // worldwide. This software is distributed without any warranty. + // + // See . + let mut s0 = self.s0.get(); + let mut s1 = self.s1.get(); + let mut s2 = self.s2.get(); + let mut s3 = self.s3.get(); + + let result = u32::wrapping_mul(u32::wrapping_mul(s1, 5).rotate_left(7), 9); + let t = s1 << 9; + + s2 ^= s0; + s3 ^= s1; + s1 ^= s2; + s0 ^= s3; + + s2 ^= t; + s3 = s3.rotate_left(11); + + self.s0.set(s0); + self.s1.set(s1); + self.s2.set(s2); + self.s3.set(s3); + + result + } +} diff --git a/cfi/lib/tests/test_derive.rs b/cfi/lib/tests/test_derive.rs new file mode 100644 index 0000000000..6ba3564b23 --- /dev/null +++ b/cfi/lib/tests/test_derive.rs @@ -0,0 +1,90 @@ +/*++ + +Licensed under the Apache-2.0 license. + +File Name: + + test_derive.rs + +--*/ + +use caliptra_cfi_derive::{cfi_impl_fn, cfi_mod_fn}; +use caliptra_cfi_lib::{CfiCounter, Xoshiro128}; + +#[cfi_mod_fn] +fn test1(val: T) -> T { + test2(val) +} + +#[cfi_mod_fn] +fn test2(val: T) -> T { + val +} + +struct Test; + +impl Test { + #[cfi_mod_fn] + fn test1(val: T) -> T { + test2(val) + } + + #[cfi_mod_fn] + #[allow(dead_code)] + fn test2(val: T) -> T { + val + } + + #[cfi_impl_fn] + fn test_self1(&self, val: T) -> T { + test2(val) + } + + #[cfi_impl_fn] + #[allow(dead_code)] + fn test_self2(&self, val: T) -> T { + test2(val) + } +} + +#[test] +#[cfg(feature = "cfi-counter")] +#[should_panic(expected = "CFI Panic = CounterCorrupt")] +fn test_with_not_initialized_counter() { + CfiCounter::corrupt(); + assert_eq!(test1(10), 10); +} + +#[test] +fn test_with_initialized_counter() { + CfiCounter::reset_for_test(); + assert_eq!(test1(10), 10); + + assert_eq!(Test::test1(10), 10); + + let test = Test; + assert_eq!(test.test_self1(10), 10); +} + +#[test] +fn test_rand() { + // Expected random numbers generated from a modified implementation of: + // https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Random.Xoshiro128StarStarImpl.cs + let expected_rand_num: [u32; 20] = [ + 11520, 0, 5927040, 70819200, 2031721883, 1637235492, 1287239034, 3734860849, 3729100597, + 4258142804, 337829053, 2142557243, 3576906021, 2006103318, 3870238204, 1001584594, + 3804789018, 2299676403, 3571406116, 2962224741, + ]; + let prng = Xoshiro128::new_with_seed(1, 2, 3, 4); + for expected_rand_num in expected_rand_num.iter() { + assert_eq!(prng.next(), *expected_rand_num); + } +} + +#[test] +fn test_rand_stress() { + let prng = Xoshiro128::new_with_seed(1, 2, 3, 4); + for _idx in 0..1000 { + prng.next(); + } +} diff --git a/drivers/src/memory_layout.rs b/drivers/src/memory_layout.rs index 796cdaa4b6..ed84f876c8 100644 --- a/drivers/src/memory_layout.rs +++ b/drivers/src/memory_layout.rs @@ -33,7 +33,13 @@ pub const FMCALIAS_TBS_ORG: u32 = 0x50003C00; pub const RTALIAS_TBS_ORG: u32 = 0x50004000; pub const PCR_LOG_ORG: u32 = 0x50004400; pub const FUSE_LOG_ORG: u32 = 0x50004800; -pub const BOOT_STATUS_ORG: u32 = 0x50004BFC; +pub const BOOT_STATUS_ORG: u32 = 0x50004BE4; +pub const CFI_VAL_ORG: u32 = 0x50004BE8; +pub const CFI_MASK_ORG: u32 = 0x50004BEC; +pub const CFI_XO_S0_ORG: u32 = 0x50004BF0; +pub const CFI_XO_S1_ORG: u32 = 0x50004BF4; +pub const CFI_XO_S2_ORG: u32 = 0x50004BF8; +pub const CFI_XO_S3_ORG: u32 = 0x50004BFC; pub const DATA_ORG: u32 = 0x50004C00; pub const STACK_ORG: u32 = 0x5001A000; pub const ESTACK_ORG: u32 = 0x5001F800; @@ -54,8 +60,7 @@ pub const LDEVID_TBS_SIZE: u32 = 1024; pub const FMCALIAS_TBS_SIZE: u32 = 1024; pub const RTALIAS_TBS_SIZE: u32 = 1024; pub const PCR_LOG_SIZE: usize = 1024; -pub const FUSE_LOG_SIZE: usize = 1020; -pub const BOOT_STATUS_SIZE: u32 = 4; +pub const FUSE_LOG_SIZE: usize = 996; pub const DATA_SIZE: u32 = 85 * 1024; pub const STACK_SIZE: u32 = 22 * 1024; pub const ESTACK_SIZE: u32 = 1024; @@ -108,12 +113,6 @@ fn mem_layout_test_fuselog() { assert_eq!((BOOT_STATUS_ORG - FUSE_LOG_ORG), FUSE_LOG_SIZE as u32); } -#[test] -#[allow(clippy::assertions_on_constants)] -fn mem_layout_test_bootstatus() { - assert_eq!((DATA_ORG - BOOT_STATUS_ORG), BOOT_STATUS_SIZE); -} - #[test] #[allow(clippy::assertions_on_constants)] fn mem_layout_test_data() { diff --git a/error/src/lib.rs b/error/src/lib.rs index 76199938a9..8a65cd57a3 100644 --- a/error/src/lib.rs +++ b/error/src/lib.rs @@ -346,6 +346,20 @@ impl CaliptraError { /// Unknown Reset Error pub const ROM_UNKNOWN_RESET_FLOW: CaliptraError = CaliptraError::new_const(0x01040020); + /// ROM CFI Errors + pub const ROM_CFI_PANIC_UNKNOWN: CaliptraError = CaliptraError::new_const(0x1040050); + pub const ROM_CFI_PANIC_COUNTER_CORRUPT: CaliptraError = CaliptraError::new_const(0x1040051); + pub const ROM_CFI_PANIC_COUNTER_OVERFLOW: CaliptraError = CaliptraError::new_const(0x1040052); + pub const ROM_CFI_PANIC_COUNTER_UNDERFLOW: CaliptraError = CaliptraError::new_const(0x1040053); + pub const ROM_CFI_PANIC_COUNTER_MISMATCH: CaliptraError = CaliptraError::new_const(0x1040054); + pub const ROM_CFI_PANIC_ASSERT_EQ_FAILURE: CaliptraError = CaliptraError::new_const(0x1040055); + pub const ROM_CFI_PANIC_ASSERT_NE_FAILURE: CaliptraError = CaliptraError::new_const(0x1040056); + pub const ROM_CFI_PANIC_ASSERT_GT_FAILURE: CaliptraError = CaliptraError::new_const(0x1040057); + pub const ROM_CFI_PANIC_ASSERT_LT_FAILURE: CaliptraError = CaliptraError::new_const(0x1040058); + 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); + /// ROM Global Errors pub const ROM_GLOBAL_NMI: CaliptraError = CaliptraError::new_const(0x01050001); pub const ROM_GLOBAL_EXCEPTION: CaliptraError = CaliptraError::new_const(0x01050002); diff --git a/rom/dev/Cargo.toml b/rom/dev/Cargo.toml index 0ad4d53504..aca9e01ad3 100644 --- a/rom/dev/Cargo.toml +++ b/rom/dev/Cargo.toml @@ -7,6 +7,8 @@ edition = "2021" rust-version = "1.70" [dependencies] +caliptra-cfi-lib = { workspace = true, default-features = false, features = ["cfi", "cfi-counter" ] } +caliptra-cfi-derive.workspace = true caliptra_common = { workspace = true, default-features = false } caliptra-drivers.workspace = true caliptra-error = { workspace = true, default-features = false } @@ -48,6 +50,7 @@ std = [ ] no-fmc = [] val-rom = [] +no-cfi = [] [[bin]] name = "asm_tests" diff --git a/rom/dev/Makefile b/rom/dev/Makefile index 383fa35ee2..3eaed94233 100644 --- a/rom/dev/Makefile +++ b/rom/dev/Makefile @@ -86,6 +86,7 @@ bloat: build cargo \ "--config=$(EXTRA_CARGO_CONFIG)" \ bloat \ + --bin caliptra-rom \ --profile firmware \ --target=riscv32imc-unknown-none-elf \ --no-default-features \ diff --git a/rom/dev/src/fht.rs b/rom/dev/src/fht.rs index 0aaebbdea5..fe1b9ca90d 100644 --- a/rom/dev/src/fht.rs +++ b/rom/dev/src/fht.rs @@ -12,6 +12,7 @@ Abstract: --*/ +use caliptra_cfi_derive::cfi_mod_fn; use caliptra_common::{ keyids::{KEY_ID_FMC_PRIV_KEY, KEY_ID_ROM_FMC_CDI}, memory_layout::{FHT_ORG, FMCALIAS_TBS_ORG, FUSE_LOG_ORG, LDEVID_TBS_ORG, PCR_LOG_ORG}, @@ -166,6 +167,7 @@ pub fn make_fht(env: &RomEnv) -> FirmwareHandoffTable { } } +#[cfg_attr(not(feature = "no-cfi"), cfi_mod_fn)] pub fn store(fht: FirmwareHandoffTable) { let slice = unsafe { let ptr = FHT_ORG as *mut u8; diff --git a/rom/dev/src/flow/cold_reset/crypto.rs b/rom/dev/src/flow/cold_reset/crypto.rs index 4363d95e24..8929a1a153 100644 --- a/rom/dev/src/flow/cold_reset/crypto.rs +++ b/rom/dev/src/flow/cold_reset/crypto.rs @@ -13,6 +13,7 @@ Abstract: --*/ use crate::rom_env::RomEnv; +use caliptra_cfi_derive::cfi_impl_fn; use caliptra_common::keyids::KEY_ID_TMP; use caliptra_drivers::*; use caliptra_x509::Ecdsa384Signature; @@ -64,6 +65,7 @@ impl Crypto { /// # Returns /// /// * `Array4x5` - Digest + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] pub fn sha1_digest(env: &mut RomEnv, data: &[u8]) -> CaliptraResult { env.sha1.digest(data) } @@ -79,6 +81,7 @@ impl Crypto { /// /// * `Array4x8` - Digest #[inline(always)] + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] pub fn sha256_digest(env: &mut RomEnv, data: &[u8]) -> CaliptraResult { env.sha256.digest(data) } @@ -93,6 +96,7 @@ impl Crypto { /// # Returns /// /// * `Array4x12` - Digest + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] pub fn sha384_digest(env: &mut RomEnv, data: &[u8]) -> CaliptraResult { env.sha384.digest(data) } @@ -105,6 +109,7 @@ impl Crypto { /// * `key` - HMAC384 key slot /// * `data` - Input data to hash /// * `tag` - Key slot to store the tag + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] pub fn hmac384_mac( env: &mut RomEnv, key: KeyId, @@ -134,6 +139,7 @@ impl Crypto { /// * `label` - Input label /// * `context` - Input context /// * `output` - Key slot to store the output + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] pub fn hmac384_kdf( env: &mut RomEnv, key: KeyId, @@ -168,6 +174,7 @@ impl Crypto { /// # Returns /// /// * `Ecc384KeyPair` - Private Key slot id and public key pairs + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] pub fn ecc384_key_gen( env: &mut RomEnv, cdi: KeyId, @@ -208,6 +215,7 @@ impl Crypto { /// # Returns /// /// * `Ecc384Signature` - Signature + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] pub fn ecdsa384_sign( env: &mut RomEnv, priv_key: KeyId, @@ -237,6 +245,7 @@ impl Crypto { /// # Returns /// /// `Ecc384Result` - Ecc384Result::Success if the signature verification passed else an error code. + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] pub fn ecdsa384_verify( env: &mut RomEnv, pub_key: &Ecc384PubKey, diff --git a/rom/dev/src/flow/cold_reset/dice.rs b/rom/dev/src/flow/cold_reset/dice.rs index 711a7181b1..054bb37c45 100644 --- a/rom/dev/src/flow/cold_reset/dice.rs +++ b/rom/dev/src/flow/cold_reset/dice.rs @@ -14,6 +14,7 @@ Abstract: --*/ use super::crypto::Ecc384KeyPair; +use caliptra_cfi_derive::cfi_impl_fn; /// DICE Layer Input #[derive(Debug)] @@ -42,6 +43,7 @@ pub struct DiceOutput { } impl DiceOutput { + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] pub fn zeroize(&mut self) { self.subj_key_pair.zeroize(); self.subj_sn.fill(0); diff --git a/rom/dev/src/flow/cold_reset/fmc_alias.rs b/rom/dev/src/flow/cold_reset/fmc_alias.rs index c8c05fa74b..f2e2f4fb78 100644 --- a/rom/dev/src/flow/cold_reset/fmc_alias.rs +++ b/rom/dev/src/flow/cold_reset/fmc_alias.rs @@ -21,6 +21,8 @@ use crate::cprintln; use crate::flow::cold_reset::{copy_tbs, TbsType}; use crate::print::HexBytes; use crate::rom_env::RomEnv; +use caliptra_cfi_derive::cfi_impl_fn; +use caliptra_cfi_lib::{cfi_assert, cfi_assert_eq, cfi_launder}; use caliptra_common::dice; use caliptra_common::keyids::{KEY_ID_FMC_PRIV_KEY, KEY_ID_ROM_FMC_CDI}; use caliptra_common::pcr::PCR_ID_FMC_CURRENT; @@ -36,6 +38,7 @@ pub struct FmcAliasLayer {} impl FmcAliasLayer { /// Perform derivations for the DICE layer + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] pub fn derive( env: &mut RomEnv, input: &DiceInput, @@ -59,7 +62,6 @@ impl FmcAliasLayer { // Derive DICE Key Pair from CDI let key_pair = Self::derive_key_pair(env, KEY_ID_ROM_FMC_CDI, KEY_ID_FMC_PRIV_KEY)?; - report_boot_status(FmcAliasKeyPairDerivationComplete.into()); // Generate the Subject Serial Number and Subject Key Identifier. // @@ -95,6 +97,7 @@ impl FmcAliasLayer { /// * `env` - ROM Environment /// * `measurements` - Array containing the FMC measurements /// * `cdi` - Key Slot to store the generated CDI + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn derive_cdi(env: &mut RomEnv, measurements: &Array4x12, cdi: KeyId) -> CaliptraResult<()> { let mut measurements: [u8; 48] = measurements.into(); @@ -115,12 +118,20 @@ impl FmcAliasLayer { /// # Returns /// /// * `Ecc384KeyPair` - Derive DICE Layer Key Pair + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn derive_key_pair( env: &mut RomEnv, cdi: KeyId, priv_key: KeyId, ) -> CaliptraResult { - Crypto::ecc384_key_gen(env, cdi, b"fmc_alias_keygen", priv_key) + let result = Crypto::ecc384_key_gen(env, cdi, b"fmc_alias_keygen", priv_key); + if cfi_launder(result.is_ok()) { + cfi_assert!(result.is_ok()); + report_boot_status(FmcAliasKeyPairDerivationComplete.into()); + } else { + cfi_assert!(result.is_err()); + } + result } /// Generate Local Device ID Certificate Signature @@ -130,6 +141,7 @@ impl FmcAliasLayer { /// * `env` - ROM Environment /// * `input` - DICE Input /// * `output` - DICE Output + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn generate_cert_sig( env: &mut RomEnv, input: &DiceInput, @@ -180,7 +192,10 @@ impl FmcAliasLayer { // Verify the signature of the `To Be Signed` portion let result = Crypto::ecdsa384_verify(env, auth_pub_key, tbs.tbs(), sig)?; - if result != Ecc384Result::Success { + if cfi_launder(result) == Ecc384Result::Success { + cfi_assert!(result == Ecc384Result::Success); + } else { + cfi_assert!(result != Ecc384Result::Success); return Err(CaliptraError::FMC_ALIAS_CERT_VERIFY); } diff --git a/rom/dev/src/flow/cold_reset/fw_processor.rs b/rom/dev/src/flow/cold_reset/fw_processor.rs index ec5cf7f0d4..c7e022c043 100644 --- a/rom/dev/src/flow/cold_reset/fw_processor.rs +++ b/rom/dev/src/flow/cold_reset/fw_processor.rs @@ -17,6 +17,8 @@ use crate::fuse::log_fuse_data; use crate::rom_env::RomEnv; use crate::{cprintln, verifier::RomImageVerificationEnv}; use crate::{pcr, wdt}; +use caliptra_cfi_derive::cfi_impl_fn; +use caliptra_cfi_lib::{cfi_assert, cfi_assert_eq, cfi_launder}; use caliptra_common::{cprint, memory_layout::MAN1_ORG, FuseLogEntryId, RomBootStatus::*}; use caliptra_drivers::*; use caliptra_image_types::{ImageManifest, IMAGE_BYTE_SIZE}; @@ -162,6 +164,7 @@ impl FirmwareProcessor { /// # Returns /// /// * `Manifest` - Caliptra Image Bundle Manifest + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn load_manifest(txn: &mut MailboxRecvTxn) -> CaliptraResult { let slice = unsafe { let ptr = MAN1_ORG as *mut u32; @@ -170,10 +173,14 @@ impl FirmwareProcessor { txn.copy_request(slice)?; - if let Some(result) = ImageManifest::read_from(slice.as_bytes()) { + let opt = ImageManifest::read_from(slice.as_bytes()); + let result = opt.is_some(); + if cfi_launder(result) { + cfi_assert!(result); report_boot_status(FwProcessorManifestLoadComplete.into()); - Ok(result) + Ok(opt.unwrap()) } else { + cfi_assert!(!result); Err(CaliptraError::FW_PROC_MANIFEST_READ_FAILURE) } } @@ -183,6 +190,7 @@ impl FirmwareProcessor { /// # Arguments /// /// * `env` - ROM Environment + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn verify_image( venv: &mut RomImageVerificationEnv, manifest: &ImageManifest, @@ -213,6 +221,7 @@ impl FirmwareProcessor { /// /// # Returns /// * CaliptraResult + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn update_fuse_log(log_info: &ImageVerificationLogInfo) -> CaliptraResult<()> { // Log VendorPubKeyIndex log_fuse_data( @@ -295,6 +304,7 @@ impl FirmwareProcessor { /// * `txn` - Mailbox Receive Transaction // Inlined to reduce ROM size #[inline(always)] + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn load_image(manifest: &ImageManifest, txn: &mut MailboxRecvTxn) -> CaliptraResult<()> { cprintln!( "[afmc] Loading FMC at address 0x{:08x} len {}", @@ -332,6 +342,7 @@ impl FirmwareProcessor { /// /// * `env` - ROM Environment /// * `info` - Image Verification Info + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn populate_data_vault(data_vault: &mut DataVault, info: &ImageVerificationInfo) { data_vault.write_cold_reset_entry48(ColdResetEntry48::FmcTci, &info.fmc.digest.into()); diff --git a/rom/dev/src/flow/cold_reset/idev_id.rs b/rom/dev/src/flow/cold_reset/idev_id.rs index 7c1ed5aef8..960458af29 100644 --- a/rom/dev/src/flow/cold_reset/idev_id.rs +++ b/rom/dev/src/flow/cold_reset/idev_id.rs @@ -19,6 +19,8 @@ use super::x509::*; use crate::cprintln; use crate::print::HexBytes; use crate::rom_env::RomEnv; +use caliptra_cfi_derive::cfi_impl_fn; +use caliptra_cfi_lib::{cfi_assert, cfi_assert_eq, cfi_launder}; use caliptra_common::keyids::{KEY_ID_FE, KEY_ID_IDEVID_PRIV_KEY, KEY_ID_ROM_FMC_CDI, KEY_ID_UDS}; use caliptra_common::RomBootStatus::*; use caliptra_drivers::*; @@ -48,6 +50,7 @@ impl InitDevIdLayer { /// # Returns /// /// * `DiceOutput` - DICE layer output + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] pub fn derive(env: &mut RomEnv) -> CaliptraResult { cprintln!("[idev] ++"); cprintln!("[idev] CDI.KEYID = {}", KEY_ID_ROM_FMC_CDI as u8); @@ -104,6 +107,7 @@ impl InitDevIdLayer { /// /// * `env` - ROM Environment /// * `uds` - Key Vault slot to store the decrypted UDS in + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn decrypt_uds(env: &mut RomEnv, uds: KeyId) -> CaliptraResult<()> { // Engage the Deobfuscation Engine to decrypt the UDS env.doe.decrypt_uds(&DOE_UDS_IV, uds)?; @@ -117,6 +121,7 @@ impl InitDevIdLayer { /// /// * `env` - ROM Environment /// * `slot` - Key Vault slot to store the decrypted UDS in + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn decrypt_field_entropy(env: &mut RomEnv, fe: KeyId) -> CaliptraResult<()> { // Engage the Deobfuscation Engine to decrypt the UDS env.doe.decrypt_field_entropy(&DOE_FE_IV, fe)?; @@ -129,6 +134,7 @@ impl InitDevIdLayer { /// # Arguments /// /// * `env` - ROM Environment + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn clear_doe_secrets(env: &mut RomEnv) -> CaliptraResult<()> { let result = env.doe.clear_secrets(); if result.is_ok() { @@ -144,6 +150,7 @@ impl InitDevIdLayer { /// * `env` - ROM Environment /// * `uds` - Key slot holding the UDS /// * `cdi` - Key Slot to store the generated CDI + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn derive_cdi(env: &mut RomEnv, uds: KeyId, cdi: KeyId) -> CaliptraResult<()> { Crypto::hmac384_kdf(env, uds, b"idevid_cdi", None, cdi)?; @@ -164,14 +171,18 @@ impl InitDevIdLayer { /// # Returns /// /// * `Ecc384KeyPair` - Derive DICE Layer Key Pair + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn derive_key_pair( env: &mut RomEnv, cdi: KeyId, priv_key: KeyId, ) -> CaliptraResult { let result = Crypto::ecc384_key_gen(env, cdi, b"idevid_keygen", priv_key); - if result.is_ok() { + if cfi_launder(result.is_ok()) { + cfi_assert!(result.is_ok()); report_boot_status(IDevIdKeyPairDerivationComplete.into()); + } else { + cfi_assert!(result.is_err()); } result } @@ -205,6 +216,7 @@ impl InitDevIdLayer { /// /// * `env` - ROM Environment /// * `output` - DICE Output + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn make_csr(env: &mut RomEnv, output: &DiceOutput) -> CaliptraResult<()> { let key_pair = &output.subj_key_pair; @@ -234,7 +246,10 @@ impl InitDevIdLayer { // Verify the signature of the `To Be Signed` portion let result = Crypto::ecdsa384_verify(env, &key_pair.pub_key, tbs.tbs(), sig)?; - if result != Ecc384Result::Success { + if cfi_launder(result) == Ecc384Result::Success { + cfi_assert!(result == Ecc384Result::Success); + } else { + cfi_assert!(result != Ecc384Result::Success); return Err(CaliptraError::ROM_IDEVID_CSR_VERIFICATION_FAILURE); } diff --git a/rom/dev/src/flow/cold_reset/ldev_id.rs b/rom/dev/src/flow/cold_reset/ldev_id.rs index f5a14d62e4..6bfa18b667 100644 --- a/rom/dev/src/flow/cold_reset/ldev_id.rs +++ b/rom/dev/src/flow/cold_reset/ldev_id.rs @@ -20,6 +20,8 @@ use crate::cprintln; use crate::flow::cold_reset::{copy_tbs, TbsType}; use crate::print::HexBytes; use crate::rom_env::RomEnv; +use caliptra_cfi_derive::cfi_impl_fn; +use caliptra_cfi_lib::{cfi_assert, cfi_assert_eq, cfi_launder}; use caliptra_common::keyids::{KEY_ID_FE, KEY_ID_LDEVID_PRIV_KEY, KEY_ID_ROM_FMC_CDI}; use caliptra_common::RomBootStatus::*; use caliptra_drivers::*; @@ -40,6 +42,7 @@ impl LocalDevIdLayer { /// # Returns /// /// * `DiceOutput` - key pair, subject identifier serial number, subject key identifier + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] pub fn derive(env: &mut RomEnv, input: &DiceInput) -> CaliptraResult { cprintln!("[ldev] ++"); cprintln!("[ldev] CDI.KEYID = {}", KEY_ID_ROM_FMC_CDI as u8); @@ -92,6 +95,7 @@ impl LocalDevIdLayer { /// * `env` - ROM Environment /// * `fe` - Key slot holding the field entropy /// * `cdi` - Key Slot to store the generated CDI + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn derive_cdi(env: &mut RomEnv, fe: KeyId, cdi: KeyId) -> CaliptraResult<()> { Crypto::hmac384_mac(env, cdi, &b"ldevid_cdi".into(), cdi)?; Crypto::hmac384_mac(env, cdi, &KeyReadArgs::new(fe).into(), cdi)?; @@ -113,14 +117,18 @@ impl LocalDevIdLayer { /// # Returns /// /// * `Ecc384KeyPair` - Derive DICE Layer Key Pair + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn derive_key_pair( env: &mut RomEnv, cdi: KeyId, priv_key: KeyId, ) -> CaliptraResult { let result = Crypto::ecc384_key_gen(env, cdi, b"ldevid_keygen", priv_key); - if result.is_ok() { + if cfi_launder(result.is_ok()) { + cfi_assert!(result.is_ok()); report_boot_status(LDevIdKeyPairDerivationComplete.into()); + } else { + cfi_assert!(result.is_err()); } result } @@ -132,6 +140,7 @@ impl LocalDevIdLayer { /// * `env` - ROM Environment /// * `input` - DICE Input /// * `output` - DICE Output + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn generate_cert_sig( env: &mut RomEnv, input: &DiceInput, @@ -175,7 +184,10 @@ impl LocalDevIdLayer { // Verify the signature of the `To Be Signed` portion let result = Crypto::ecdsa384_verify(env, auth_pub_key, tbs.tbs(), sig)?; - if result != Ecc384Result::Success { + if cfi_launder(result) == Ecc384Result::Success { + cfi_assert!(result == Ecc384Result::Success); + } else { + cfi_assert!(result != Ecc384Result::Success); return Err(CaliptraError::ROM_LDEVID_CSR_VERIFICATION_FAILURE); } diff --git a/rom/dev/src/flow/cold_reset/mod.rs b/rom/dev/src/flow/cold_reset/mod.rs index d6d4453ee4..617063a80b 100644 --- a/rom/dev/src/flow/cold_reset/mod.rs +++ b/rom/dev/src/flow/cold_reset/mod.rs @@ -27,6 +27,7 @@ use crate::flow::cold_reset::fw_processor::FirmwareProcessor; use crate::flow::cold_reset::idev_id::InitDevIdLayer; use crate::flow::cold_reset::ldev_id::LocalDevIdLayer; use crate::{cprintln, rom_env::RomEnv}; +use caliptra_cfi_derive::{cfi_impl_fn, cfi_mod_fn}; use caliptra_common::RomBootStatus::*; use caliptra_common::{ memory_layout::{FMCALIAS_TBS_ORG, FMCALIAS_TBS_SIZE, LDEVID_TBS_ORG, LDEVID_TBS_SIZE}, @@ -48,6 +49,7 @@ impl ColdResetFlow { /// /// * `env` - ROM Environment #[inline(never)] + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] pub fn run(env: &mut RomEnv) -> CaliptraResult> { cprintln!("[cold-reset] ++"); report_boot_status(ColdResetStarted.into()); @@ -86,6 +88,7 @@ impl ColdResetFlow { /// /// # Returns /// CaliptraResult +#[cfg_attr(not(feature = "no-cfi"), cfi_mod_fn)] pub fn copy_tbs(tbs: &[u8], tbs_type: TbsType, env: &mut RomEnv) -> CaliptraResult<()> { let dst = match tbs_type { TbsType::LdevidTbs => { diff --git a/rom/dev/src/flow/mod.rs b/rom/dev/src/flow/mod.rs index 0cc74c2fa9..36e7ec1d9d 100644 --- a/rom/dev/src/flow/mod.rs +++ b/rom/dev/src/flow/mod.rs @@ -20,6 +20,8 @@ mod warm_reset; use crate::cprintln; use crate::{handle_fatal_error, rom_env::RomEnv}; +use caliptra_cfi_derive::cfi_mod_fn; +use caliptra_cfi_lib::cfi_assert_eq; use caliptra_common::FirmwareHandoffTable; use caliptra_drivers::{CaliptraResult, ResetReason}; use caliptra_error::CaliptraError; @@ -29,22 +31,35 @@ use caliptra_error::CaliptraError; /// # Arguments /// /// * `env` - ROM Environment +#[cfg_attr(not(feature = "no-cfi"), cfi_mod_fn)] pub fn run(env: &mut RomEnv) -> CaliptraResult> { let reset_reason = env.soc_ifc.reset_reason(); if cfg!(not(feature = "val-rom")) { match reset_reason { // Cold Reset Flow - ResetReason::ColdReset => cold_reset::ColdResetFlow::run(env), + ResetReason::ColdReset => { + cfi_assert_eq(env.soc_ifc.reset_reason(), ResetReason::ColdReset); + cold_reset::ColdResetFlow::run(env) + } // Warm Reset Flow - ResetReason::WarmReset => warm_reset::WarmResetFlow::run(env), + ResetReason::WarmReset => { + cfi_assert_eq(env.soc_ifc.reset_reason(), ResetReason::WarmReset); + warm_reset::WarmResetFlow::run(env) + } // Update Reset Flow - ResetReason::UpdateReset => update_reset::UpdateResetFlow::run(env), + ResetReason::UpdateReset => { + cfi_assert_eq(env.soc_ifc.reset_reason(), ResetReason::UpdateReset); + update_reset::UpdateResetFlow::run(env) + } // Unknown/Spurious Reset Flow - ResetReason::Unknown => Err(CaliptraError::ROM_UNKNOWN_RESET_FLOW), + ResetReason::Unknown => { + cfi_assert_eq(env.soc_ifc.reset_reason(), ResetReason::Unknown); + Err(CaliptraError::ROM_UNKNOWN_RESET_FLOW) + } } } else { let _result: CaliptraResult> = diff --git a/rom/dev/src/flow/update_reset.rs b/rom/dev/src/flow/update_reset.rs index 35c36bdb63..15d96bfffb 100644 --- a/rom/dev/src/flow/update_reset.rs +++ b/rom/dev/src/flow/update_reset.rs @@ -13,6 +13,7 @@ Abstract: --*/ use crate::{cprintln, pcr, rom_env::RomEnv, verifier::RomImageVerificationEnv}; +use caliptra_cfi_derive::cfi_impl_fn; use caliptra_common::memory_layout::{MAN1_ORG, MAN2_ORG}; use caliptra_common::FirmwareHandoffTable; @@ -37,6 +38,7 @@ impl UpdateResetFlow { /// # Arguments /// /// * `env` - ROM Environment + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] pub fn run(env: &mut RomEnv) -> CaliptraResult> { cprintln!("[update-reset] ++"); report_boot_status(UpdateResetStarted.into()); @@ -80,7 +82,11 @@ impl UpdateResetFlow { // Populate data vault Self::populate_data_vault(venv.data_vault, info); - Self::load_image(&manifest, recv_txn)?; + Self::load_image(&manifest, &mut recv_txn)?; + + // Drop the transaction and release the Mailbox lock after the image + // has been successfully verified and loaded in memory + drop(recv_txn); report_boot_status(UpdateResetLoadImageComplete.into()); Self::copy_regions(); @@ -102,6 +108,7 @@ impl UpdateResetFlow { /// * `env` - ROM Environment /// * 'manifest'- Manifest /// + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn verify_image( env: &mut RomImageVerificationEnv, manifest: &ImageManifest, @@ -121,6 +128,7 @@ impl UpdateResetFlow { /// /// * `manifest` - Manifest /// + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn copy_regions() { cprintln!("[update-reset] Copying MAN_2 To MAN_1"); @@ -144,7 +152,8 @@ impl UpdateResetFlow { /// * `env` - ROM Environment /// * `manifest` - Manifest /// * `txn` - Mailbox Receive Transaction - fn load_image(manifest: &ImageManifest, mut txn: MailboxRecvTxn) -> CaliptraResult<()> { + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] + fn load_image(manifest: &ImageManifest, txn: &mut MailboxRecvTxn) -> CaliptraResult<()> { cprintln!( "[update-reset] Loading Runtime at address 0x{:08x} len {}", manifest.runtime.load_addr, @@ -164,10 +173,6 @@ impl UpdateResetFlow { //Call the complete here to reset the execute bit txn.complete(true)?; - // Drop the transaction and release the Mailbox lock after the image - // has been successfully verified and loaded in memory - drop(txn); - Ok(()) } @@ -176,6 +181,7 @@ impl UpdateResetFlow { /// # Returns /// /// * `Manifest` - Caliptra Image Bundle Manifest + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn load_manifest(txn: &mut MailboxRecvTxn) -> CaliptraResult { let slice = unsafe { let ptr = MAN2_ORG as *mut u32; diff --git a/rom/dev/src/flow/warm_reset.rs b/rom/dev/src/flow/warm_reset.rs index 0b57bc37b4..f7d5123bf2 100644 --- a/rom/dev/src/flow/warm_reset.rs +++ b/rom/dev/src/flow/warm_reset.rs @@ -12,6 +12,7 @@ Abstract: --*/ use crate::{cprintln, rom_env::RomEnv}; +use caliptra_cfi_derive::cfi_impl_fn; use caliptra_common::FirmwareHandoffTable; use caliptra_error::CaliptraResult; @@ -25,6 +26,7 @@ impl WarmResetFlow { /// /// * `env` - ROM Environment #[inline(never)] + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] pub fn run(_env: &mut RomEnv) -> CaliptraResult> { cprintln!("[warm-reset] ++"); cprintln!("[warm-reset] --"); diff --git a/rom/dev/src/fuse.rs b/rom/dev/src/fuse.rs index c5f07a3459..07ace700ee 100644 --- a/rom/dev/src/fuse.rs +++ b/rom/dev/src/fuse.rs @@ -10,6 +10,7 @@ Abstract: The file contains Fuse-related Implementations. --*/ +use caliptra_cfi_derive::cfi_mod_fn; use caliptra_common::{ memory_layout::{FUSE_LOG_ORG, FUSE_LOG_SIZE}, FuseLogEntry, FuseLogEntryId, @@ -28,6 +29,7 @@ use zerocopy::AsBytes; /// * `Err(GlobalErr::FuseLogInvalidEntryId)` - Invalid Fuse log entry ID /// * `Err(GlobalErr::FuseLogUpsupportedDataLength)` - Unsupported data length /// +#[cfg_attr(not(feature = "no-cfi"), cfi_mod_fn)] pub fn log_fuse_data(entry_id: FuseLogEntryId, data: &[u8]) -> CaliptraResult<()> { if entry_id == FuseLogEntryId::Invalid { return Err(CaliptraError::ROM_GLOBAL_FUSE_LOG_INVALID_ENTRY_ID); diff --git a/rom/dev/src/lock.rs b/rom/dev/src/lock.rs index e5b149ff73..07b6348fc9 100644 --- a/rom/dev/src/lock.rs +++ b/rom/dev/src/lock.rs @@ -12,6 +12,7 @@ Abstract: --*/ +use caliptra_cfi_derive::cfi_mod_fn; use caliptra_common::pcr::{PCR_ID_FMC_CURRENT, PCR_ID_FMC_JOURNEY}; use caliptra_drivers::{ ColdResetEntry4, ColdResetEntry48, ResetReason, WarmResetEntry4, WarmResetEntry48, @@ -25,6 +26,7 @@ use crate::{cprintln, rom_env::RomEnv}; /// /// * `env` - ROM Environment /// * `reset_reason` - Reset reason +#[cfg_attr(not(feature = "no-cfi"), cfi_mod_fn)] pub fn lock_registers(env: &mut RomEnv, reset_reason: ResetReason) { cprintln!("[state] Locking Datavault"); if reset_reason == ResetReason::ColdReset { @@ -50,6 +52,7 @@ pub fn lock_registers(env: &mut RomEnv, reset_reason: ResetReason) { /// # Arguments /// /// * `env` - ROM Environment +#[cfg_attr(not(feature = "no-cfi"), cfi_mod_fn)] fn lock_cold_reset_reg(env: &mut RomEnv) { // Lock the FMC TCI in data vault until next cold reset env.data_vault @@ -81,6 +84,7 @@ fn lock_cold_reset_reg(env: &mut RomEnv) { /// # Arguments /// /// * `env` - ROM Environment +#[cfg_attr(not(feature = "no-cfi"), cfi_mod_fn)] fn lock_common_reg_set(env: &mut RomEnv) { // Lock the Runtime TCI in data vault until next reset env.data_vault diff --git a/rom/dev/src/main.rs b/rom/dev/src/main.rs index 03168a0e2a..5a97232b6c 100644 --- a/rom/dev/src/main.rs +++ b/rom/dev/src/main.rs @@ -16,6 +16,7 @@ Abstract: #![cfg_attr(feature = "val-rom", allow(unused_imports))] use crate::lock::lock_registers; +use caliptra_cfi_lib::CfiCounter; use core::hint::black_box; use caliptra_drivers::{ @@ -59,6 +60,13 @@ pub extern "C" fn rom_entry() -> ! { Err(e) => handle_fatal_error(e.into()), }; + if !cfg!(feature = "no-cfi") { + cprintln!("[state] CFI Enabled"); + CfiCounter::reset(&mut env.trng); + } else { + cprintln!("[state] CFI Disabled"); + } + let _lifecyle = match env.soc_ifc.lifecycle() { caliptra_drivers::Lifecycle::Unprovisioned => "Unprovisioned", caliptra_drivers::Lifecycle::Manufacturing => "Manufacturing", @@ -192,6 +200,13 @@ fn handle_non_fatal_error(code: u32) { report_fw_error_non_fatal(code); } +#[no_mangle] +extern "C" fn cfi_panic_handler(code: u32) -> ! { + cprintln!("CFI Panic code=0x{:08X}", code); + + handle_fatal_error(code); +} + #[allow(clippy::empty_loop)] fn handle_fatal_error(code: u32) -> ! { cprintln!("ROM Fatal Error: 0x{:08X}", code); diff --git a/rom/dev/src/pcr.rs b/rom/dev/src/pcr.rs index 460d10d1dd..e65980c72c 100644 --- a/rom/dev/src/pcr.rs +++ b/rom/dev/src/pcr.rs @@ -22,6 +22,7 @@ Note: --*/ use crate::verifier::RomImageVerificationEnv; +use caliptra_cfi_derive::{cfi_impl_fn, cfi_mod_fn}; use caliptra_common::{ memory_layout::{PCR_LOG_ORG, PCR_LOG_SIZE}, pcr::{PCR_ID_FMC_CURRENT, PCR_ID_FMC_JOURNEY}, @@ -37,10 +38,13 @@ struct PcrExtender<'a> { sha384: &'a mut Sha384, } impl PcrExtender<'_> { + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn extend(&mut self, data: Array4x12, pcr_entry_id: PcrLogEntryId) -> CaliptraResult<()> { let bytes: &[u8; 48] = &data.into(); self.extend_and_log(bytes, pcr_entry_id) } + + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn extend_u8(&mut self, data: u8, pcr_entry_id: PcrLogEntryId) -> CaliptraResult<()> { let bytes = &data.to_le_bytes(); self.extend_and_log(bytes, pcr_entry_id) @@ -61,6 +65,7 @@ impl PcrExtender<'_> { /// # Arguments /// /// * `env` - ROM Environment +#[cfg_attr(not(feature = "no-cfi"), cfi_mod_fn)] pub(crate) fn extend_pcrs( env: &mut RomImageVerificationEnv, info: &ImageVerificationInfo, @@ -122,6 +127,7 @@ pub(crate) fn extend_pcrs( /// * `Err(GlobalErr::PcrLogInvalidEntryId)` - Invalid PCR log entry ID /// * `Err(GlobalErr::PcrLogUpsupportedDataLength)` - Unsupported data length /// +#[cfg_attr(not(feature = "no-cfi"), cfi_mod_fn)] pub fn log_pcr( pcr_bank: &mut PcrBank, pcr_entry_id: PcrLogEntryId, diff --git a/rom/dev/src/wdt.rs b/rom/dev/src/wdt.rs index 8fd527317b..7980d04447 100644 --- a/rom/dev/src/wdt.rs +++ b/rom/dev/src/wdt.rs @@ -16,6 +16,7 @@ Environment: --*/ +use caliptra_cfi_derive::cfi_mod_fn; use caliptra_drivers::SocIfc; use core::cmp::max; @@ -30,8 +31,7 @@ const WDT2_TIMEOUT_CYCLES: u64 = 1; // Fire immediately after WDT1 expiry /// # Arguments /// /// * `soc_ifc` - SOC Interface -/// -/// +#[cfg_attr(not(feature = "no-cfi"), cfi_mod_fn)] pub fn start_wdt(soc_ifc: &mut SocIfc) { cprintln!("[state] Starting the Watchdog Timer"); @@ -69,7 +69,7 @@ pub fn start_wdt(soc_ifc: &mut SocIfc) { /// # Arguments /// /// * `soc_ifc` - SOC Interface -/// +#[cfg_attr(not(feature = "no-cfi"), cfi_mod_fn)] pub fn stop_wdt(soc_ifc: &mut SocIfc) { cprintln!("[state] Stopping the Watchdog Timer"); soc_ifc.configure_wdt1(false);