From 487fc63d79a47c99184db1968c3ff2ec47b8efe1 Mon Sep 17 00:00:00 2001 From: Christopher Swenson Date: Wed, 6 Nov 2024 09:52:53 -0800 Subject: [PATCH] cfi: Simpler launder implementation for common types (#1714) * `cfi_launder` is meant to prevent the Rust compiler from optimizing a value away. Our current implementation uses `core::hint::black_box()`, which is the recommended way in Rust. The problem is, this appears to often force the argument to spill into memory and to be reloaded, which can be a lot of extra instructions. The original inspiration for this function is from, I believe, [OpenTitan's launder* functions](https://github.com/lowRISC/opentitan/blob/master/sw/device/lib/base/hardened.h#L193). There, they use an LLVM-specific trick of a blank inline assembly block to force the compiler to keep the argument in a register. After reviewing our code and speaking with @vsonims, it sounds like the intention of the launder in our code is to prevent the compiler from optimizing the value away (as the comments suggest), so the simpler inline assembly trick may be sufficient (since we use the official Rust compiler, which uses LLVM). The biggest problem is that we launder many types of values in our code and not all of them fit into a register. So, this PR represents an incremental change: for `u32`s and similar small types, we implement `cfi_launder` using the inline assembly trick from OpenTitan. For any other types, we have a trait that can be derived that will call `core::hint::black_box` in the same way as today. We can do future follow-up PRs to try to try to clean up some of those other uses of `cfi_launder` to hopefully shrink the code more. I also slipped in avoid a few extra copies in the verifier by using references instead of copies (this saves ~80 bytes of instruction space). This PR appears to shrink the ROM code size by 1232 bytes and the runtime firmware by 700 bytes. (cherry picked from commit 571d253f7dd79dbddcae3403c83f62edd5174e17) --- Cargo.lock | 4 + FROZEN_IMAGES.sha384sum | 4 +- cfi/derive/src/cfi_asm_test.rs | 78 +++++++++++++++ cfi/derive/src/lib.rs | 15 +++ cfi/lib/src/cfi.rs | 122 +++++++++++++++++++++-- drivers/src/array.rs | 3 +- drivers/src/fuse_bank.rs | 7 +- drivers/src/soc_ifc.rs | 3 +- fmc/src/flow/rt_alias.rs | 3 +- image/types/Cargo.toml | 2 + image/verify/src/verifier.rs | 59 +++++++---- lms-types/Cargo.toml | 2 + lms-types/src/lib.rs | 6 +- rom/dev/src/flow/cold_reset/fmc_alias.rs | 2 +- rom/dev/src/flow/cold_reset/idev_id.rs | 2 +- rom/dev/src/flow/cold_reset/ldev_id.rs | 2 +- 16 files changed, 272 insertions(+), 42 deletions(-) create mode 100644 cfi/derive/src/cfi_asm_test.rs diff --git a/Cargo.lock b/Cargo.lock index e80f952667..8711351e01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -673,6 +673,8 @@ name = "caliptra-image-types" version = "0.1.0" dependencies = [ "arbitrary", + "caliptra-cfi-derive", + "caliptra-cfi-lib", "caliptra-error", "caliptra-lms-types", "memoffset 0.8.0", @@ -709,6 +711,8 @@ name = "caliptra-lms-types" version = "0.1.0" dependencies = [ "arbitrary", + "caliptra-cfi-derive", + "caliptra-cfi-lib", "zerocopy", "zeroize", ] diff --git a/FROZEN_IMAGES.sha384sum b/FROZEN_IMAGES.sha384sum index 97f1762a43..2c902660bc 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 -9537318fd30c3e3d341cffab5721ba3242810be85e79ed9dc644c47c062555ef7519fb48857745e7ccb9917ac1fe120a caliptra-rom-no-log.bin -e4e74d2d1c4794b950a548072fc8dc4c9ab64aba7a01ae400e9fe66c64b43f715e72dc430e7318496009ebedd0412bc6 caliptra-rom-with-log.bin +ad1064cba5b190e4f5258c175b7ec7c697ccb188ba0ed18302c6e924f0ea0b10457dc753d6d2963f415fbaf761eace96 caliptra-rom-no-log.bin +4d93a6856a0cba636a5d2a9c116393f56dc3b34113f7149ae62325772c1eacb08b1d78424771cc71197252abe603eb92 caliptra-rom-with-log.bin diff --git a/cfi/derive/src/cfi_asm_test.rs b/cfi/derive/src/cfi_asm_test.rs new file mode 100644 index 0000000000..062455d83e --- /dev/null +++ b/cfi/derive/src/cfi_asm_test.rs @@ -0,0 +1,78 @@ +// Licensed under the Apache-2.0 license + +// These tests are here so that they are excluded in FPGA tests. + +// These tests don't directly import the CFI code. If they fail, +// this likely indicates that the CFI laundering code may not +// be doing what we want, and we need to investigate. + +#[cfg(test)] +mod test { + + const START: &str = " +#![no_std] + +pub fn add(mut a: u32, mut b: u32) -> u32 { + launder(a) + launder(a) + launder(b) + launder(b) +} +"; + + const LAUNDER: &str = " +#[inline(always)] +fn launder(mut val: u32) -> u32 { + // Safety: this is a no-op, since we don't modify the input. + unsafe { + core::arch::asm!( + \"/* {t} */\", + t = inout(reg) val, + ); + } + val +}"; + + const NO_LAUNDER: &str = " +#[inline(always)] +fn launder(mut val: u32) -> u32 { + val +} +"; + + fn compile_to_riscv32_asm(src: String) -> String { + let dir = std::env::temp_dir(); + let src_path = dir.join("asm.rs"); + let dst_path = dir.join("asm.s"); + + std::fs::write(src_path.clone(), src).expect("could not write asm file"); + + let p = std::process::Command::new("rustc") + .args([ + "--crate-type=lib", + "--target", + "riscv32imc-unknown-none-elf", + "-C", + "opt-level=s", + "--emit", + "asm", + src_path.to_str().expect("could not convert path"), + "-o", + dst_path.to_str().expect("could not convert path"), + ]) + .output() + .expect("failed to compile"); + assert!(p.status.success()); + std::fs::read_to_string(dst_path).expect("could not read asm file") + } + + #[test] + fn test_launder() { + // With no laundering, LLVM can simplify the double add to a shift left. + let src = format!("{}{}", START, NO_LAUNDER); + let asm = compile_to_riscv32_asm(src); + assert!(asm.contains("sll")); + + // With laundering, LLVM cannot simplify the double add and has to use the register twice. + let src = format!("{}{}", START, LAUNDER); + let asm = compile_to_riscv32_asm(src); + assert!(!asm.contains("sll")); + } +} diff --git a/cfi/derive/src/lib.rs b/cfi/derive/src/lib.rs index 3ea4644e6e..2b6b61a559 100644 --- a/cfi/derive/src/lib.rs +++ b/cfi/derive/src/lib.rs @@ -16,11 +16,14 @@ References: --*/ +mod cfi_asm_test; + 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::DeriveInput; use syn::FnArg; use syn::ItemFn; @@ -94,3 +97,15 @@ fn cfi_fn(mod_fn: bool, input: TokenStream) -> TokenStream { code.into() } + +#[proc_macro_derive(Launder)] +pub fn derive_launder_trait(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let name = input.ident; + let (impl_generics, ty_generics, _) = input.generics.split_for_impl(); + let expanded = quote! { + impl #impl_generics caliptra_cfi_lib::LaunderTrait<#name #ty_generics> for caliptra_cfi_lib::Launder<#name #ty_generics> {} + impl #impl_generics caliptra_cfi_lib::LaunderTrait<&#name #ty_generics> for caliptra_cfi_lib::Launder<&#name #ty_generics> {} + }; + TokenStream::from(expanded) +} diff --git a/cfi/lib/src/cfi.rs b/cfi/lib/src/cfi.rs index e45997992f..4204c2e01c 100644 --- a/cfi/lib/src/cfi.rs +++ b/cfi/lib/src/cfi.rs @@ -20,7 +20,7 @@ use caliptra_error::CaliptraError; use crate::CfiCounter; use core::cfg; use core::cmp::{Eq, Ord, PartialEq, PartialOrd}; -use core::marker::Copy; +use core::marker::{Copy, PhantomData}; /// CFI Panic Information #[derive(Debug, Clone, Copy, Eq, PartialEq)] @@ -94,16 +94,107 @@ impl From for CaliptraError { /// # Returns /// /// `T` - Same value -pub fn cfi_launder(val: T) -> T { +pub fn cfi_launder(val: T) -> T +where + Launder: LaunderTrait, +{ 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) + Launder { _val: PhantomData }.launder(val) } else { val } } +pub trait LaunderTrait { + fn launder(&self, val: T) -> T { + core::hint::black_box(val) + } +} + +pub struct Launder { + _val: PhantomData, +} + +// Inline-assembly laundering trick is adapted from OpenTitan: +// https://github.com/lowRISC/opentitan/blob/master/sw/device/lib/base/hardened.h#L193 +// +// NOTE: This implementation is LLVM-specific, and should be considered to be +// a no-op in every other compiler. For example, GCC has in the past peered +// into the insides of assembly blocks. +// +// At the time of writing, it seems preferable to have something we know is +// correct rather than being overly clever; this is recorded here in case +// the current implementation is unsuitable and we need something more +// carefully tuned. +// +// Unlike in C, we don't have volatile assembly blocks, so this doesn't +// necessarily prevent reordering by LLVM. +// +// When we're building for static analysis, reduce false positives by +// short-circuiting the inline assembly block. +impl LaunderTrait for Launder { + #[allow(asm_sub_register)] + fn launder(&self, val: u32) -> u32 { + let mut val = val; + // Safety: this is a no-op, since we don't modify the input. + unsafe { + // We use inout so that LLVM thinks the value might + // be mutated by the assembly and can't eliminate it. + core::arch::asm!( + "/* {t} */", + t = inout(reg) val, + ); + } + val + } +} + +impl LaunderTrait for Launder { + #[allow(asm_sub_register)] + fn launder(&self, val: bool) -> bool { + let mut val = val as u32; + // Safety: this is a no-op, since we don't modify the input. + unsafe { + core::arch::asm!( + "/* {t} */", + t = inout(reg) val, + ); + } + val != 0 + } +} + +impl LaunderTrait for Launder { + #[allow(asm_sub_register)] + fn launder(&self, mut val: usize) -> usize { + // Safety: this is a no-op, since we don't modify the input. + unsafe { + core::arch::asm!( + "/* {t} */", + t = inout(reg) val, + ); + } + val + } +} + +impl LaunderTrait<[T; N]> for Launder<[T; N]> {} +impl<'a, const N: usize, T> LaunderTrait<&'a [T; N]> for Launder<&'a [T; N]> { + fn launder(&self, val: &'a [T; N]) -> &'a [T; N] { + let mut valp = val.as_ptr() as *const [T; N]; + // Safety: this is a no-op, since we don't modify the input. + unsafe { + core::arch::asm!( + "/* {t} */", + t = inout(reg) valp, + ); + &*valp + } + } +} +impl LaunderTrait> for Launder> {} +impl LaunderTrait for Launder {} + /// Control flow integrity panic /// /// This panic is raised when the control flow integrity error is detected @@ -157,6 +248,7 @@ macro_rules! cfi_assert_macro { pub fn $name(lhs: T, rhs: T) where T: $trait1 + $trait2, + Launder: LaunderTrait, { if cfg!(feature = "cfi") { CfiCounter::delay(); @@ -184,10 +276,28 @@ 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); +// special case for bool assert +#[inline(always)] +#[allow(unused)] +pub fn cfi_assert_bool(cond: bool) { + if cfg!(feature = "cfi") { + CfiCounter::delay(); + if !cond { + cfi_panic(CfiPanicInfo::AssertEqFail); + } + + // Second check for glitch protection + CfiCounter::delay(); + if !cfi_launder(cond) { + cfi_panic(CfiPanicInfo::AssertEqFail); + } + } +} + #[macro_export] macro_rules! cfi_assert { ($cond: expr) => { - cfi_assert_eq($cond, true) + cfi_assert_bool($cond) }; } diff --git a/drivers/src/array.rs b/drivers/src/array.rs index bbaab1f09c..de8372309b 100644 --- a/drivers/src/array.rs +++ b/drivers/src/array.rs @@ -13,6 +13,7 @@ Abstract: --*/ +use caliptra_cfi_derive::Launder; use core::mem::MaybeUninit; use zerocopy::{AsBytes, FromBytes}; use zeroize::Zeroize; @@ -26,7 +27,7 @@ macro_rules! static_assert { /// The `Array4xN` type represents large arrays in the native format of the Caliptra /// cryptographic hardware, and provides From traits for converting to/from byte arrays. #[repr(transparent)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Zeroize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Launder, Zeroize)] pub struct Array4xN(pub [u32; W]); impl Array4xN { pub const fn new(val: [u32; W]) -> Self { diff --git a/drivers/src/fuse_bank.rs b/drivers/src/fuse_bank.rs index 9b060ed41c..f12455319d 100644 --- a/drivers/src/fuse_bank.rs +++ b/drivers/src/fuse_bank.rs @@ -13,6 +13,7 @@ Abstract: --*/ use crate::Array4x12; +use caliptra_cfi_derive::Launder; use caliptra_registers::soc_ifc::SocIfcReg; use zerocopy::AsBytes; @@ -33,7 +34,7 @@ pub enum X509KeyIdAlgo { } bitflags::bitflags! { - #[derive(Default, Copy, Clone, Debug)] + #[derive(Default, Copy, Clone, Debug, Launder)] pub struct VendorPubKeyRevocation : u32 { const KEY0 = 0b0001; const KEY1 = 0b0010; @@ -87,7 +88,7 @@ impl FuseBank<'_> { /// * None /// /// # Returns - /// key id crypto algorithm + /// key id crypto algorithm /// pub fn idev_id_x509_key_id_algo(&self) -> X509KeyIdAlgo { let soc_ifc_regs = self.soc_ifc.regs(); @@ -112,7 +113,7 @@ impl FuseBank<'_> { /// * None /// /// # Returns - /// manufacturer serial number + /// manufacturer serial number /// pub fn ueid(&self) -> [u8; 17] { let soc_ifc_regs = self.soc_ifc.regs(); diff --git a/drivers/src/soc_ifc.rs b/drivers/src/soc_ifc.rs index ff32420e47..872a1722a4 100644 --- a/drivers/src/soc_ifc.rs +++ b/drivers/src/soc_ifc.rs @@ -12,6 +12,7 @@ Abstract: --*/ +use caliptra_cfi_derive::Launder; use caliptra_error::{CaliptraError, CaliptraResult}; use caliptra_registers::soc_ifc::enums::DeviceLifecycleE; use caliptra_registers::soc_ifc::{self, SocIfcReg}; @@ -382,7 +383,7 @@ impl From for MfgFlags { } /// Reset Reason -#[derive(Debug, Eq, PartialEq, Copy, Clone)] +#[derive(Debug, Eq, PartialEq, Copy, Clone, Launder)] pub enum ResetReason { /// Cold Reset ColdReset, diff --git a/fmc/src/flow/rt_alias.rs b/fmc/src/flow/rt_alias.rs index 404925dde4..1e51ce9e72 100644 --- a/fmc/src/flow/rt_alias.rs +++ b/fmc/src/flow/rt_alias.rs @@ -12,8 +12,7 @@ Abstract: --*/ use caliptra_cfi_derive::cfi_impl_fn; -use caliptra_cfi_lib::cfi_assert_eq; -use caliptra_cfi_lib::{cfi_assert, cfi_launder}; +use caliptra_cfi_lib::{cfi_assert, cfi_assert_bool, cfi_assert_eq, cfi_launder}; use crate::flow::crypto::Crypto; use crate::flow::dice::{DiceInput, DiceOutput}; diff --git a/image/types/Cargo.toml b/image/types/Cargo.toml index d1a27d45cc..c245bb219c 100644 --- a/image/types/Cargo.toml +++ b/image/types/Cargo.toml @@ -10,6 +10,8 @@ doctest = false [dependencies] arbitrary = { workspace = true, optional = true } +caliptra-cfi-derive.workspace = true +caliptra-cfi-lib.workspace = true caliptra-lms-types.workspace = true memoffset.workspace = true zerocopy.workspace = true diff --git a/image/verify/src/verifier.rs b/image/verify/src/verifier.rs index 16b90ec4f3..15bd546054 100644 --- a/image/verify/src/verifier.rs +++ b/image/verify/src/verifier.rs @@ -17,12 +17,14 @@ use core::num::NonZeroU32; use crate::*; #[cfg(all(not(test), not(feature = "no-cfi")))] use caliptra_cfi_derive::cfi_impl_fn; -use caliptra_cfi_lib::{cfi_assert, cfi_assert_eq, cfi_assert_ge, cfi_assert_ne, cfi_launder}; +use caliptra_cfi_lib::{ + cfi_assert, cfi_assert_bool, cfi_assert_eq, cfi_assert_ge, cfi_assert_ne, cfi_launder, +}; use caliptra_drivers::*; use caliptra_image_types::*; use memoffset::offset_of; -const ZERO_DIGEST: ImageDigest = [0u32; SHA384_DIGEST_WORD_SIZE]; +const ZERO_DIGEST: &ImageDigest = &[0u32; SHA384_DIGEST_WORD_SIZE]; /// Header Info struct HeaderInfo<'a> { @@ -294,15 +296,21 @@ impl ImageVerifier { pub_key_info: &ImageVendorPubKeyInfo, ) -> Result<(), NonZeroU32> { // We skip vendor public key check in unprovisioned state - if cfi_launder(self.env.dev_lifecycle()) == Lifecycle::Unprovisioned { - cfi_assert_eq(self.env.dev_lifecycle(), Lifecycle::Unprovisioned); + if cfi_launder(self.env.dev_lifecycle() as u32) == Lifecycle::Unprovisioned as u32 { + cfi_assert_eq( + self.env.dev_lifecycle() as u32, + Lifecycle::Unprovisioned as u32, + ); return Ok(()); } else { - cfi_assert_ne(self.env.dev_lifecycle(), Lifecycle::Unprovisioned); + cfi_assert_ne( + self.env.dev_lifecycle() as u32, + Lifecycle::Unprovisioned as u32, + ); } // Read expected value from the fuses - let expected = self.env.vendor_pub_key_info_digest_fuses(); + let expected = &self.env.vendor_pub_key_info_digest_fuses(); // Vendor public key digest from the fuses must never be zero if cfi_launder(expected) == ZERO_DIGEST { @@ -352,7 +360,7 @@ impl ImageVerifier { ) }; - let actual = self + let actual = &self .env .sha384_digest(range.start, range.len() as u32) .map_err(|err| { @@ -363,7 +371,7 @@ impl ImageVerifier { if cfi_launder(expected) != actual { Err(CaliptraError::IMAGE_VERIFIER_ERR_VENDOR_PUB_KEY_DIGEST_MISMATCH)?; } else { - caliptra_cfi_lib::cfi_assert_eq_12_words(&expected, &actual); + caliptra_cfi_lib::cfi_assert_eq_12_words(expected, actual); } // [TODO] Verify active public key's digest from the descriptor hash list. @@ -387,7 +395,7 @@ impl ImageVerifier { ) }; - let actual = self + let actual = &self .env .sha384_digest(range.start, range.len() as u32) .map_err(|err| { @@ -395,28 +403,28 @@ impl ImageVerifier { CaliptraError::IMAGE_VERIFIER_ERR_OWNER_PUB_KEY_DIGEST_FAILURE })?; - let fuses_digest = self.env.owner_pub_key_digest_fuses(); + let fuses_digest = &self.env.owner_pub_key_digest_fuses(); if fuses_digest == ZERO_DIGEST { - caliptra_cfi_lib::cfi_assert_eq_12_words(&fuses_digest, &ZERO_DIGEST); + caliptra_cfi_lib::cfi_assert_eq_12_words(fuses_digest, ZERO_DIGEST); } else if fuses_digest != actual { return Err(CaliptraError::IMAGE_VERIFIER_ERR_OWNER_PUB_KEY_DIGEST_MISMATCH); } else { - caliptra_cfi_lib::cfi_assert_eq_12_words(&fuses_digest, &actual); + caliptra_cfi_lib::cfi_assert_eq_12_words(fuses_digest, actual); } if cfi_launder(reason) == ResetReason::UpdateReset { - let cold_boot_digest = self.env.owner_pub_key_digest_dv(); + let cold_boot_digest = &self.env.owner_pub_key_digest_dv(); if cfi_launder(cold_boot_digest) != actual { return Err(CaliptraError::IMAGE_VERIFIER_ERR_UPDATE_RESET_OWNER_DIGEST_FAILURE); } else { - caliptra_cfi_lib::cfi_assert_eq_12_words(&cold_boot_digest, &actual); + caliptra_cfi_lib::cfi_assert_eq_12_words(cold_boot_digest, actual); } } else { cfi_assert_ne(reason, ResetReason::UpdateReset); } - Ok((actual, fuses_digest != ZERO_DIGEST)) + Ok((*actual, fuses_digest != ZERO_DIGEST)) } /// Verify Header @@ -480,7 +488,11 @@ impl ImageVerifier { // Verify owner LMS signature let (owner_lms_pub_key, owner_lms_sig) = info.owner_lms_info; - self.verify_owner_lms_sig(&digest_owner, owner_lms_pub_key, owner_lms_sig)?; + self.verify_owner_lms_sig( + &digest_owner, + cfi_launder(owner_lms_pub_key), + cfi_launder(owner_lms_sig), + )?; let verif_info = TocInfo { len: header.toc_len, @@ -499,10 +511,10 @@ impl ImageVerifier { pub_key: &ImageEccPubKey, sig: &ImageEccSignature, ) -> CaliptraResult<()> { - if pub_key.x == ZERO_DIGEST || pub_key.y == ZERO_DIGEST { + if &pub_key.x == ZERO_DIGEST || &pub_key.y == ZERO_DIGEST { Err(CaliptraError::IMAGE_VERIFIER_ERR_OWNER_ECC_PUB_KEY_INVALID_ARG)?; } - if sig.r == ZERO_DIGEST || sig.s == ZERO_DIGEST { + if &sig.r == ZERO_DIGEST || &sig.s == ZERO_DIGEST { Err(CaliptraError::IMAGE_VERIFIER_ERR_OWNER_ECC_SIGNATURE_INVALID_ARG)?; } @@ -539,10 +551,10 @@ impl ImageVerifier { lms_info: (&ImageLmsPublicKey, &ImageLmsSignature), ) -> CaliptraResult<()> { let (ecc_pub_key, ecc_sig) = ecc_info; - if ecc_pub_key.x == ZERO_DIGEST || ecc_pub_key.y == ZERO_DIGEST { + if &ecc_pub_key.x == ZERO_DIGEST || &ecc_pub_key.y == ZERO_DIGEST { Err(CaliptraError::IMAGE_VERIFIER_ERR_VENDOR_PUB_KEY_DIGEST_INVALID_ARG)?; } - if ecc_sig.r == ZERO_DIGEST || ecc_sig.s == ZERO_DIGEST { + if &ecc_sig.r == ZERO_DIGEST || &ecc_sig.s == ZERO_DIGEST { Err(CaliptraError::IMAGE_VERIFIER_ERR_VENDOR_ECC_SIGNATURE_INVALID_ARG)?; } @@ -729,8 +741,11 @@ impl ImageVerifier { #[inline(always)] fn svn_check_required(&mut self) -> bool { // If device is unprovisioned or if rollback is enabled (anti_rollback_disable == true), don't check the SVN. - if cfi_launder(self.env.dev_lifecycle()) == Lifecycle::Unprovisioned { - cfi_assert_eq(self.env.dev_lifecycle(), Lifecycle::Unprovisioned); + if cfi_launder(self.env.dev_lifecycle() as u32) == Lifecycle::Unprovisioned as u32 { + cfi_assert_eq( + self.env.dev_lifecycle() as u32, + Lifecycle::Unprovisioned as u32, + ); false // SVN check not required } else if cfi_launder(self.env.anti_rollback_disable()) { cfi_assert!(self.env.anti_rollback_disable()); diff --git a/lms-types/Cargo.toml b/lms-types/Cargo.toml index f9a05dd372..0d60a7b426 100644 --- a/lms-types/Cargo.toml +++ b/lms-types/Cargo.toml @@ -9,5 +9,7 @@ edition = "2021" [dependencies] arbitrary = { workspace = true, optional = true } +caliptra-cfi-derive.workspace = true +caliptra-cfi-lib.workspace = true zerocopy.workspace = true zeroize.workspace = true diff --git a/lms-types/src/lib.rs b/lms-types/src/lib.rs index 11b3cc66dc..d5d1423a3e 100644 --- a/lms-types/src/lib.rs +++ b/lms-types/src/lib.rs @@ -4,6 +4,7 @@ use core::mem::size_of; +use caliptra_cfi_derive::Launder; use zerocopy::{AsBytes, BigEndian, FromBytes, LittleEndian, U32}; use zeroize::Zeroize; @@ -60,7 +61,7 @@ impl LmotsAlgorithmType { pub const LmotsSha256N24W8: Self = Self::new(8); } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Launder)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[repr(C)] pub struct LmsPublicKey { @@ -69,6 +70,7 @@ pub struct LmsPublicKey { pub id: [u8; 16], pub digest: [U32; N], } + impl Default for LmsPublicKey { fn default() -> Self { Self { @@ -133,7 +135,7 @@ unsafe impl FromBytes for LmotsSignature { } #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Launder)] #[repr(C)] pub struct LmsSignature { pub q: U32, diff --git a/rom/dev/src/flow/cold_reset/fmc_alias.rs b/rom/dev/src/flow/cold_reset/fmc_alias.rs index 1f6f3f0cb2..0fc9e7c4af 100644 --- a/rom/dev/src/flow/cold_reset/fmc_alias.rs +++ b/rom/dev/src/flow/cold_reset/fmc_alias.rs @@ -24,7 +24,7 @@ use crate::print::HexBytes; use crate::rom_env::RomEnv; #[cfg(not(feature = "no-cfi"))] use caliptra_cfi_derive::cfi_impl_fn; -use caliptra_cfi_lib::{cfi_assert, cfi_assert_eq, cfi_launder}; +use caliptra_cfi_lib::{cfi_assert, cfi_assert_bool, cfi_launder}; use caliptra_common::dice; use caliptra_common::keyids::{ KEY_ID_FMC_ECDSA_PRIV_KEY, KEY_ID_FMC_MLDSA_KEYPAIR_SEED, KEY_ID_ROM_FMC_CDI, diff --git a/rom/dev/src/flow/cold_reset/idev_id.rs b/rom/dev/src/flow/cold_reset/idev_id.rs index 705dadfc13..1cb0723119 100644 --- a/rom/dev/src/flow/cold_reset/idev_id.rs +++ b/rom/dev/src/flow/cold_reset/idev_id.rs @@ -21,7 +21,7 @@ use crate::print::HexBytes; use crate::rom_env::RomEnv; #[cfg(not(feature = "no-cfi"))] use caliptra_cfi_derive::cfi_impl_fn; -use caliptra_cfi_lib::{cfi_assert, cfi_assert_eq, cfi_launder}; +use caliptra_cfi_lib::{cfi_assert, cfi_assert_bool, cfi_launder}; use caliptra_common::keyids::{ KEY_ID_FE, KEY_ID_IDEVID_ECDSA_PRIV_KEY, KEY_ID_IDEVID_MLDSA_KEYPAIR_SEED, KEY_ID_ROM_FMC_CDI, KEY_ID_UDS, diff --git a/rom/dev/src/flow/cold_reset/ldev_id.rs b/rom/dev/src/flow/cold_reset/ldev_id.rs index 7b96fd86c4..36956cf29d 100644 --- a/rom/dev/src/flow/cold_reset/ldev_id.rs +++ b/rom/dev/src/flow/cold_reset/ldev_id.rs @@ -22,7 +22,7 @@ use crate::print::HexBytes; use crate::rom_env::RomEnv; #[cfg(not(feature = "no-cfi"))] use caliptra_cfi_derive::cfi_impl_fn; -use caliptra_cfi_lib::{cfi_assert, cfi_assert_eq, cfi_launder}; +use caliptra_cfi_lib::{cfi_assert, cfi_assert_bool, cfi_launder}; use caliptra_common::keyids::KEY_ID_LDEVID_MLDSA_KEYPAIR_SEED; use caliptra_common::keyids::{KEY_ID_FE, KEY_ID_LDEVID_ECDSA_PRIV_KEY, KEY_ID_ROM_FMC_CDI}; use caliptra_common::RomBootStatus::*;