From 4180fb4c5dd6e22c49c546fe2fe2c2e9e34c2288 Mon Sep 17 00:00:00 2001 From: Anthony Rocha Date: Wed, 11 Dec 2024 18:14:40 -0800 Subject: [PATCH 1/4] Self Signed FMC Alias Csr - FMC modfied to generate a self signed FMC Alias CSR test upon cold boot. - Persistent driver modified to add persistent memory for the FMC Alias CSR - Runtime modified to expose an API to retrieve it. - Test case created to verify the self signed FMC Alias CSR. - Test case created to verify the RT Alias Certificate with the pub key of the FMC Alias CSR. --- Cargo.lock | 1 + api/src/mailbox.rs | 41 ++++ common/src/lib.rs | 4 +- drivers/Cargo.toml | 1 + drivers/src/lib.rs | 3 + drivers/src/persistent.rs | 82 +++++++- error/src/lib.rs | 13 ++ fmc/Cargo.toml | 2 + fmc/build.sh | 1 + fmc/src/flow/crypto.rs | 51 +++++ fmc/src/flow/fmc_alias_csr.rs | 123 ++++++++++++ fmc/src/flow/mod.rs | 10 + fmc/src/flow/rt_alias.rs | 4 - fmc/src/hand_off.rs | 22 +-- runtime/Cargo.toml | 2 +- runtime/src/drivers.rs | 6 +- runtime/src/get_fmc_alias_csr.rs | 51 +++++ runtime/src/lib.rs | 11 +- runtime/src/main.rs | 15 +- .../tests/runtime_integration_tests/common.rs | 17 +- .../tests/runtime_integration_tests/main.rs | 1 + .../test_data/fmc_alias_csr.der | Bin 0 -> 447 bytes .../test_data/fmc_alias_csr.txt | 33 ++++ .../test_get_fmc_alias_csr.rs | 90 +++++++++ .../fake_collateral_boot_test.rs | 9 +- .../caliptra_integration_tests/smoke_test.rs | 13 +- x509/build/build.rs | 13 ++ x509/build/csr.rs | 2 +- x509/build/fmc_alias_csr_tbs.rs | 89 +++++++++ x509/src/fmc_alias_csr.rs | 177 ++++++++++++++++++ x509/src/lib.rs | 2 + 31 files changed, 823 insertions(+), 66 deletions(-) create mode 100644 fmc/src/flow/fmc_alias_csr.rs create mode 100644 runtime/src/get_fmc_alias_csr.rs create mode 100644 runtime/tests/runtime_integration_tests/test_data/fmc_alias_csr.der create mode 100644 runtime/tests/runtime_integration_tests/test_data/fmc_alias_csr.txt create mode 100644 runtime/tests/runtime_integration_tests/test_get_fmc_alias_csr.rs create mode 100644 x509/build/fmc_alias_csr_tbs.rs create mode 100644 x509/src/fmc_alias_csr.rs diff --git a/Cargo.lock b/Cargo.lock index 981b5b16ff..ad85d64611 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -518,6 +518,7 @@ dependencies = [ "openssl", "ufmt", "zerocopy", + "zeroize", ] [[package]] diff --git a/api/src/mailbox.rs b/api/src/mailbox.rs index 0a0906fbbd..e600e5d703 100644 --- a/api/src/mailbox.rs +++ b/api/src/mailbox.rs @@ -54,6 +54,9 @@ impl CommandId { // The get IDevID CSR command. pub const GET_IDEV_CSR: Self = Self(0x4944_4352); // "IDCR" + + // The get FMC Alias CSR command. + pub const GET_FMC_ALIAS_CSR: Self = Self(0x464D_4352); // "FMCR" } impl From for CommandId { @@ -153,6 +156,7 @@ pub enum MailboxResp { CertifyKeyExtended(CertifyKeyExtendedResp), AuthorizeAndStash(AuthorizeAndStashResp), GetIdevCsr(GetIdevCsrResp), + GetFmcAliasCsr(GetFmcAliasCsrResp), } impl MailboxResp { @@ -174,6 +178,7 @@ impl MailboxResp { MailboxResp::CertifyKeyExtended(resp) => Ok(resp.as_bytes()), MailboxResp::AuthorizeAndStash(resp) => Ok(resp.as_bytes()), MailboxResp::GetIdevCsr(resp) => Ok(resp.as_bytes()), + MailboxResp::GetFmcAliasCsr(resp) => Ok(resp.as_bytes()), } } @@ -195,6 +200,7 @@ impl MailboxResp { MailboxResp::CertifyKeyExtended(resp) => Ok(resp.as_mut_bytes()), MailboxResp::AuthorizeAndStash(resp) => Ok(resp.as_mut_bytes()), MailboxResp::GetIdevCsr(resp) => Ok(resp.as_mut_bytes()), + MailboxResp::GetFmcAliasCsr(resp) => Ok(resp.as_mut_bytes()), } } @@ -1010,6 +1016,41 @@ impl Default for GetIdevCsrResp { } } +// GET_FMC_ALIAS_CSR +#[repr(C)] +#[derive(Default, Debug, IntoBytes, FromBytes, KnownLayout, Immutable, PartialEq, Eq)] +pub struct GetFmcAliasCsrReq { + pub hdr: MailboxReqHeader, +} + +impl Request for GetFmcAliasCsrReq { + const ID: CommandId = CommandId::GET_FMC_ALIAS_CSR; + type Resp = GetFmcAliasCsrResp; +} + +#[repr(C)] +#[derive(Debug, IntoBytes, FromBytes, KnownLayout, Immutable, PartialEq, Eq)] +pub struct GetFmcAliasCsrResp { + pub hdr: MailboxRespHeader, + pub data_size: u32, + pub data: [u8; Self::DATA_MAX_SIZE], +} + +impl Default for GetFmcAliasCsrResp { + fn default() -> Self { + Self { + hdr: MailboxRespHeader::default(), + data_size: 0, + data: [0u8; Self::DATA_MAX_SIZE], + } + } +} + +impl GetFmcAliasCsrResp { + pub const DATA_MAX_SIZE: usize = 512; +} +impl ResponseVarSize for GetFmcAliasCsrResp {} + #[repr(u32)] #[derive(Debug, PartialEq, Eq)] pub enum ImageHashSource { diff --git a/common/src/lib.rs b/common/src/lib.rs index 8ae0376696..8fb9032abc 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -38,9 +38,9 @@ pub use fuse::{FuseLogEntry, FuseLogEntryId}; pub use pcr::{PcrLogEntry, PcrLogEntryId, RT_FW_CURRENT_PCR, RT_FW_JOURNEY_PCR}; pub const FMC_ORG: u32 = 0x40000000; -pub const FMC_SIZE: u32 = 20 * 1024; +pub const FMC_SIZE: u32 = 22 * 1024 - 512; pub const RUNTIME_ORG: u32 = FMC_ORG + FMC_SIZE; -pub const RUNTIME_SIZE: u32 = 97 * 1024; +pub const RUNTIME_SIZE: u32 = 95 * 1024 + 512; pub use memory_layout::{DATA_ORG, PERSISTENT_DATA_ORG}; pub use wdt::{restart_wdt, start_wdt, stop_wdt, WdtTimeout}; diff --git a/drivers/Cargo.toml b/drivers/Cargo.toml index e112f63655..ff90f5fa5c 100644 --- a/drivers/Cargo.toml +++ b/drivers/Cargo.toml @@ -37,6 +37,7 @@ verilator = ["caliptra-hw-model/verilator"] no-cfi = [] "hw-1.0" = ["caliptra-builder/hw-1.0", "caliptra-registers/hw-1.0"] fips-test-hooks = [] +fmc_alias_csr = [] [dev-dependencies] caliptra-api.workspace = true diff --git a/drivers/src/lib.rs b/drivers/src/lib.rs index b663bf8087..5988219dc8 100644 --- a/drivers/src/lib.rs +++ b/drivers/src/lib.rs @@ -86,8 +86,11 @@ pub use okref::okmutref; pub use okref::okref; pub use pcr_bank::{PcrBank, PcrId}; pub use pcr_reset::PcrResetCounter; +#[cfg(feature = "fmc")] +pub use persistent::fmc_alias_csr::FmcAliasCsr; #[cfg(feature = "runtime")] pub use persistent::AuthManifestImageMetadataList; + pub use persistent::{ FuseLogArray, IdevIdCsr, PcrLogArray, PersistentData, PersistentDataAccessor, StashMeasurementArray, FUSE_LOG_MAX_COUNT, MAX_CSR_SIZE, MEASUREMENT_MAX_COUNT, diff --git a/drivers/src/persistent.rs b/drivers/src/persistent.rs index f6a008a9f0..1533b3554a 100644 --- a/drivers/src/persistent.rs +++ b/drivers/src/persistent.rs @@ -21,6 +21,9 @@ use crate::{ FirmwareHandoffTable, }; +#[cfg(feature = "fmc")] +use crate::FmcAliasCsr; + #[cfg(feature = "runtime")] use crate::pcr_reset::PcrResetCounter; @@ -38,7 +41,8 @@ pub const DPE_SIZE: u32 = 5 * 1024; pub const PCR_RESET_COUNTER_SIZE: u32 = 1024; pub const AUTH_MAN_IMAGE_METADATA_MAX_SIZE: u32 = 7 * 1024; pub const IDEVID_CSR_SIZE: u32 = 1024; -pub const RESERVED_MEMORY_SIZE: u32 = 19 * 1024; +pub const FMC_ALIAS_CSR_SIZE: u32 = 1024; +pub const RESERVED_MEMORY_SIZE: u32 = 18 * 1024; pub const PCR_LOG_MAX_COUNT: usize = 17; pub const FUSE_LOG_MAX_COUNT: usize = 62; @@ -61,6 +65,7 @@ pub type AuthManifestImageMetadataList = [AuthManifestImageMetadata; AUTH_MANIFEST_IMAGE_METADATA_MAX_COUNT]; const _: () = assert!(MAX_CSR_SIZE < IDEVID_CSR_SIZE as usize); +const _: () = assert!(MAX_CSR_SIZE < FMC_ALIAS_CSR_SIZE as usize); #[derive(Clone, TryFromBytes, IntoBytes, Zeroize)] #[repr(C)] @@ -69,6 +74,70 @@ pub struct IdevIdCsr { csr: [u8; MAX_CSR_SIZE], } +#[cfg(feature = "fmc")] +pub mod fmc_alias_csr { + use super::*; + + const _: () = assert!(size_of::() < FMC_ALIAS_CSR_SIZE as usize); + + #[derive(Clone, TryFromBytes, IntoBytes, Zeroize)] + #[repr(C)] + pub struct FmcAliasCsr { + csr_len: u32, + csr: [u8; MAX_CSR_SIZE], + } + + impl Default for FmcAliasCsr { + fn default() -> Self { + Self { + csr_len: Self::UNPROVISIONED_CSR, + csr: [0; MAX_CSR_SIZE], + } + } + } + + impl FmcAliasCsr { + /// The `csr_len` field is set to this constant when a ROM image supports CSR generation but + /// the CSR generation flag was not enabled. + /// + /// This is used by the runtime to distinguish ROM images that support CSR generation from + /// ones that do not. + /// + /// u32::MAX is too large to be a valid CSR, so we use it to encode this state. + pub const UNPROVISIONED_CSR: u32 = u32::MAX; + + /// Get the CSR buffer + pub fn get(&self) -> Option<&[u8]> { + self.csr.get(..self.csr_len as usize) + } + + /// Create `Self` from a csr slice. `csr_len` MUST be the actual length of the csr. + pub fn new(csr_buf: &[u8], csr_len: usize) -> CaliptraResult { + if csr_len >= MAX_CSR_SIZE { + return Err(CaliptraError::FMC_ALIAS_INVALID_CSR); + } + + let mut _self = Self { + csr_len: csr_len as u32, + csr: [0; MAX_CSR_SIZE], + }; + _self.csr[..csr_len].copy_from_slice(&csr_buf[..csr_len]); + + Ok(_self) + } + + /// Get the length of the CSR in bytes. + pub fn get_csr_len(&self) -> u32 { + self.csr_len + } + + /// Check if the CSR was unprovisioned + pub fn is_unprovisioned(&self) -> bool { + self.csr_len == Self::UNPROVISIONED_CSR + } + } +} + impl Default for IdevIdCsr { fn default() -> Self { Self { @@ -193,6 +262,15 @@ pub struct PersistentData { pub idevid_csr: IdevIdCsr, reserved10: [u8; IDEVID_CSR_SIZE as usize - size_of::()], + #[cfg(feature = "fmc")] + pub fmc_alias_csr: FmcAliasCsr, + + #[cfg(feature = "fmc")] + reserved11: [u8; FMC_ALIAS_CSR_SIZE as usize - size_of::()], + + #[cfg(not(feature = "fmc"))] + pub fmc_alias_csr: [u8; FMC_ALIAS_CSR_SIZE as usize], + // Reserved memory for future objects. // New objects should always source memory from this range. // Taking memory from this reserve does NOT break hitless updates. @@ -283,7 +361,7 @@ impl PersistentData { persistent_data_offset += IDEVID_CSR_SIZE; assert_eq!( - addr_of!((*P).reserved_memory) as u32, + addr_of!((*P).fmc_alias_csr) as u32, memory_layout::PERSISTENT_DATA_ORG + persistent_data_offset ); diff --git a/error/src/lib.rs b/error/src/lib.rs index 2bd9d10957..b477793ae8 100644 --- a/error/src/lib.rs +++ b/error/src/lib.rs @@ -450,6 +450,9 @@ impl CaliptraError { pub const RUNTIME_AUTH_MANIFEST_IMAGE_METADATA_LIST_DUPLICATE_FIRMWARE_ID: CaliptraError = CaliptraError::new_const(0x000E0053); + pub const RUNTIME_GET_FMC_CSR_UNPROVISIONED: CaliptraError = + CaliptraError::new_const(0x000E0054); + /// FMC Errors pub const FMC_GLOBAL_NMI: CaliptraError = CaliptraError::new_const(0x000F0001); pub const FMC_GLOBAL_EXCEPTION: CaliptraError = CaliptraError::new_const(0x000F0002); @@ -466,6 +469,16 @@ impl CaliptraError { pub const FMC_GLOBAL_WDT_EXPIRED: CaliptraError = CaliptraError::new_const(0x000F000D); pub const FMC_UNKNOWN_RESET: CaliptraError = CaliptraError::new_const(0x000F000E); + /// FMC Alias CSR Errors + pub const FMC_ALIAS_CSR_BUILDER_INIT_FAILURE: CaliptraError = + CaliptraError::new_const(0x000F000F); + pub const FMC_ALIAS_CSR_BUILDER_BUILD_FAILURE: CaliptraError = + CaliptraError::new_const(0x000F0010); + pub const FMC_ALIAS_INVALID_CSR: CaliptraError = CaliptraError::new_const(0x000F0011); + pub const FMC_ALIAS_CSR_VERIFICATION_FAILURE: CaliptraError = + CaliptraError::new_const(0x000F0012); + pub const FMC_ALIAS_CSR_OVERFLOW: CaliptraError = CaliptraError::new_const(0x000F0013); + /// TRNG_EXT Errors pub const DRIVER_TRNG_EXT_TIMEOUT: CaliptraError = CaliptraError::new_const(0x00100001); diff --git a/fmc/Cargo.toml b/fmc/Cargo.toml index ce8cbb61f9..7de33fa57e 100644 --- a/fmc/Cargo.toml +++ b/fmc/Cargo.toml @@ -17,6 +17,7 @@ ufmt.workspace = true zerocopy.workspace = true caliptra-cfi-lib = { workspace = true, default-features = false, features = ["cfi", "cfi-counter" ] } caliptra-cfi-derive.workspace = true +zeroize.workspace = true [build-dependencies] @@ -41,3 +42,4 @@ itrng = ["caliptra-hw-model/itrng"] verilator = ["caliptra-hw-model/verilator"] fake-fmc = [] "hw-1.0" = ["caliptra-builder/hw-1.0", "caliptra-cpu/hw-1.0", "caliptra-drivers/hw-1.0", "caliptra-registers/hw-1.0"] +fmc_alias_csr = ["caliptra-drivers/fmc_alias_csr"] \ No newline at end of file diff --git a/fmc/build.sh b/fmc/build.sh index 0feabf5fd8..dce5b31441 100755 --- a/fmc/build.sh +++ b/fmc/build.sh @@ -9,4 +9,5 @@ cargo build \ --target riscv32imc-unknown-none-elf \ --profile=firmware \ --no-default-features \ + --features=fmc_alias_csr \ --bin=caliptra-fmc diff --git a/fmc/src/flow/crypto.rs b/fmc/src/flow/crypto.rs index 23e83edae9..60e6a4ca2b 100644 --- a/fmc/src/flow/crypto.rs +++ b/fmc/src/flow/crypto.rs @@ -5,7 +5,12 @@ File Name: Abstract: Crypto helper routines --*/ +use caliptra_x509::Ecdsa384Signature; + use crate::fmc_env::FmcEnv; +use caliptra_drivers::okmutref; +use zeroize::Zeroize; + use caliptra_cfi_derive::cfi_impl_fn; use caliptra_common::{crypto::Ecc384KeyPair, keyids::KEY_ID_TMP}; use caliptra_drivers::{ @@ -14,6 +19,21 @@ use caliptra_drivers::{ KeyWriteArgs, Sha256Alg, }; +pub trait Ecdsa384SignatureAdapter { + /// Convert to ECDSA Signature + fn to_ecdsa(&self) -> Ecdsa384Signature; +} + +impl Ecdsa384SignatureAdapter for Ecc384Signature { + /// Convert to ECDSA Signatuure + fn to_ecdsa(&self) -> Ecdsa384Signature { + Ecdsa384Signature { + r: (&self.r).into(), + s: (&self.s).into(), + } + } +} + pub enum Crypto {} impl Crypto { @@ -187,4 +207,35 @@ impl Crypto { let digest = okref(&digest)?; env.ecc384.verify(pub_key, digest, sig) } + + /// Sign the data using ECC Private Key. + /// Verify the signature using the ECC Public Key. + /// + /// This routine calculates the digest of the `data`, signs the hash and returns the signature. + /// This routine also verifies the signature using the public key. + /// + /// # Arguments + /// + /// * `env` - FMC Environment + /// * `priv_key` - Key slot to retrieve the private key + /// * `data` - Input data to hash + /// + /// # Returns + /// + /// * `Ecc384Signature` - Signature + #[inline(always)] + pub fn ecdsa384_sign_and_verify( + env: &mut FmcEnv, + priv_key: KeyId, + pub_key: &Ecc384PubKey, + data: &[u8], + ) -> CaliptraResult { + let mut digest = Self::sha384_digest(env, data); + let digest = okmutref(&mut digest)?; + let priv_key_args = KeyReadArgs::new(priv_key); + let priv_key = Ecc384PrivKeyIn::Key(priv_key_args); + let result = env.ecc384.sign(&priv_key, pub_key, digest, &mut env.trng); + digest.0.zeroize(); + result + } } diff --git a/fmc/src/flow/fmc_alias_csr.rs b/fmc/src/flow/fmc_alias_csr.rs new file mode 100644 index 0000000000..386ba45f81 --- /dev/null +++ b/fmc/src/flow/fmc_alias_csr.rs @@ -0,0 +1,123 @@ +// Licensed under the Apache-2.0 license + +use crate::flow::crypto::Crypto; +use crate::flow::dice::DiceOutput; +use crate::flow::x509::X509; +use crate::fmc_env::FmcEnv; +use crate::HandOff; +use caliptra_common::crypto::Ecc384KeyPair; + +use crate::flow::crypto::Ecdsa384SignatureAdapter; + +use zeroize::Zeroize; + +use caliptra_drivers::okmutref; +use caliptra_drivers::FmcAliasCsr; + +use caliptra_x509::FmcAliasCsrTbs; +use caliptra_x509::FmcAliasCsrTbsParams; + +use caliptra_drivers::{CaliptraError, CaliptraResult}; + +use caliptra_x509::Ecdsa384CsrBuilder; + +/// Retrieve DICE Output from HandOff +/// +/// # Arguments +/// +/// * `hand_off` - HandOff +/// +/// # Returns +/// +/// * `DiceInput` - DICE Layer Input +fn dice_output_from_hand_off(env: &mut FmcEnv) -> CaliptraResult { + let auth_pub = HandOff::fmc_pub_key(env); + let subj_sn = X509::subj_sn(env, &auth_pub)?; + let subj_key_id = X509::subj_key_id(env, &auth_pub)?; + // Create initial output + let output = DiceOutput { + cdi: HandOff::fmc_cdi(env), + subj_key_pair: Ecc384KeyPair { + priv_key: HandOff::fmc_priv_key(env), + pub_key: auth_pub, + }, + subj_sn, + subj_key_id, + }; + + Ok(output) +} + +fn write_csr_to_peristent_storage(env: &mut FmcEnv, csr: &FmcAliasCsr) -> CaliptraResult<()> { + let csr_persistent_mem = &mut env.persistent_data.get_mut().fmc_alias_csr; + + *csr_persistent_mem = csr.clone(); + + Ok(()) +} + +#[inline(always)] +pub fn generate_csr(env: &mut FmcEnv) -> CaliptraResult<()> { + dice_output_from_hand_off(env).and_then(|output| make_csr(env, &output)) +} + +/// Generate FMC Alias CSR +/// +/// # Arguments +/// +/// * `env` - FMC Environment +/// * `output` - DICE Output +// Inlined to reduce FMC size +#[inline(always)] +pub fn make_csr(env: &mut FmcEnv, output: &DiceOutput) -> CaliptraResult<()> { + let key_pair = &output.subj_key_pair; + + // CSR `To Be Signed` Parameters + let params = FmcAliasCsrTbsParams { + // Unique Endpoint Identifier + ueid: &X509::ueid(env)?, + + // Subject Name + subject_sn: &output.subj_sn, + + // Public Key + public_key: &key_pair.pub_key.to_der(), + }; + + // Generate the `To Be Signed` portion of the CSR + let tbs = FmcAliasCsrTbs::new(¶ms); + + // Sign the `To Be Signed` portion + let mut sig = + Crypto::ecdsa384_sign_and_verify(env, key_pair.priv_key, &key_pair.pub_key, tbs.tbs()); + let sig = okmutref(&mut sig)?; + + let _pub_x: [u8; 48] = key_pair.pub_key.x.into(); + let _pub_y: [u8; 48] = key_pair.pub_key.y.into(); + + let _sig_r: [u8; 48] = (&sig.r).into(); + let _sig_s: [u8; 48] = (&sig.s).into(); + + // Build the CSR with `To Be Signed` & `Signature` + let mut csr_buf = [0; caliptra_drivers::MAX_CSR_SIZE]; + let result = Ecdsa384CsrBuilder::new(tbs.tbs(), &sig.to_ecdsa()) + .ok_or(CaliptraError::FMC_ALIAS_CSR_BUILDER_INIT_FAILURE); + sig.zeroize(); + + let csr_bldr = result?; + let csr_len = csr_bldr + .build(&mut csr_buf) + .ok_or(CaliptraError::FMC_ALIAS_CSR_BUILDER_BUILD_FAILURE)?; + + if csr_len > csr_buf.len() { + return Err(CaliptraError::FMC_ALIAS_CSR_OVERFLOW); + } + + let fmc_alias_csr = FmcAliasCsr::new(&csr_buf, csr_len)?; + + let result = write_csr_to_peristent_storage(env, &fmc_alias_csr); + + csr_buf.zeroize(); + + result +} diff --git a/fmc/src/flow/mod.rs b/fmc/src/flow/mod.rs index 5e5d44712d..466dc1c518 100644 --- a/fmc/src/flow/mod.rs +++ b/fmc/src/flow/mod.rs @@ -14,11 +14,14 @@ Abstract: mod crypto; pub mod dice; +mod fmc_alias_csr; mod pcr; mod rt_alias; mod tci; mod x509; +use caliptra_drivers::ResetReason; + use crate::flow::rt_alias::RtAliasLayer; use crate::fmc_env::FmcEnv; @@ -30,5 +33,12 @@ use caliptra_drivers::CaliptraResult; /// /// * `env` - FMC Environment pub fn run(env: &mut FmcEnv) -> CaliptraResult<()> { + let reset_reason = env.soc_ifc.reset_reason(); + + if reset_reason == ResetReason::ColdReset { + // Generate the FMC Alias Certificate Signing Request (CSR) + fmc_alias_csr::generate_csr(env)?; + } + RtAliasLayer::run(env) } diff --git a/fmc/src/flow/rt_alias.rs b/fmc/src/flow/rt_alias.rs index 1e51ce9e72..a356375fd8 100644 --- a/fmc/src/flow/rt_alias.rs +++ b/fmc/src/flow/rt_alias.rs @@ -55,7 +55,6 @@ impl RtAliasLayer { // Derive CDI Self::derive_cdi(env, input.cdi, KEY_ID_RT_CDI)?; report_boot_status(FmcBootStatus::RtAliasDeriveCdiComplete as u32); - cprintln!("[alias rt] Derive Key Pair"); cprintln!( "[alias rt] Store priv key in slot 0x{:x}", KEY_ID_RT_PRIV_KEY as u8 @@ -100,18 +99,15 @@ impl RtAliasLayer { #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] #[inline(never)] pub fn run(env: &mut FmcEnv) -> CaliptraResult<()> { - cprintln!("[alias rt] Extend RT PCRs"); Self::extend_pcrs(env)?; cprintln!("[alias rt] Extend RT PCRs Done"); - cprintln!("[alias rt] Lock RT PCRs"); env.pcr_bank .set_pcr_lock(caliptra_common::RT_FW_CURRENT_PCR); env.pcr_bank .set_pcr_lock(caliptra_common::RT_FW_JOURNEY_PCR); cprintln!("[alias rt] Lock RT PCRs Done"); - cprintln!("[alias rt] Populate DV"); Self::populate_dv(env)?; cprintln!("[alias rt] Populate DV Done"); report_boot_status(crate::FmcBootStatus::RtMeasurementComplete as u32); diff --git a/fmc/src/hand_off.rs b/fmc/src/hand_off.rs index 6033fcdc1a..d80ab0734a 100644 --- a/fmc/src/hand_off.rs +++ b/fmc/src/hand_off.rs @@ -45,24 +45,14 @@ impl HandOff { /// Retrieve FMC CDI pub fn fmc_cdi(env: &FmcEnv) -> KeyId { - let ds: DataStore = - Self::fht(env) - .fmc_cdi_kv_hdl - .try_into() - .unwrap_or_else(|e: CaliptraError| { - cprintln!("[fht] Invalid CDI KV handle"); - handle_fatal_error(e.into()) - }); + let ds: DataStore = Self::fht(env) + .fmc_cdi_kv_hdl + .try_into() + .unwrap_or_else(|e: CaliptraError| handle_fatal_error(e.into())); match ds { - KeyVaultSlot(key_id) => { - cprintln!("[fht] Handoff : FMC CDI: {:?}", key_id as u8); - key_id - } - _ => { - cprintln!("[fht] Invalid KeySlot KV Entry"); - handle_fatal_error(CaliptraError::FMC_HANDOFF_INVALID_PARAM.into()) - } + KeyVaultSlot(key_id) => key_id, + _ => handle_fatal_error(CaliptraError::FMC_HANDOFF_INVALID_PARAM.into()), } } diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 2a70738d43..3669787260 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -11,7 +11,7 @@ caliptra-cfi-lib-git = { workspace = true, default-features = false, features = caliptra-cfi-derive-git.workspace = true caliptra_common = { workspace = true, default-features = false, features = ["runtime"] } caliptra-cpu.workspace = true -caliptra-drivers = { workspace = true, features = ["runtime"] } +caliptra-drivers = { workspace = true, features = ["fmc", "runtime"] } caliptra-error = { workspace = true, default-features = false } caliptra-image-types = { workspace = true, default-features = false } caliptra-auth-man-types = { workspace = true, default-features = false } diff --git a/runtime/src/drivers.rs b/runtime/src/drivers.rs index 107aa4fc21..8769a0e3cd 100644 --- a/runtime/src/drivers.rs +++ b/runtime/src/drivers.rs @@ -229,7 +229,7 @@ impl Drivers { } match result { Ok(_) => { - cprintln!("Disabled attestation due to DPE validation failure"); + cprintln!("Disabled attest : DPE valid fail"); // store specific validation error in CPTRA_FW_EXTENDED_ERROR_INFO drivers.soc_ifc.set_fw_extended_error(e.get_error_code()); caliptra_drivers::report_fw_error_non_fatal( @@ -259,9 +259,7 @@ impl Drivers { } match result { Ok(_) => { - cprintln!( - "Disabled attestation due to DPE used context limits being breached" - ); + cprintln!("Disable attest DPE used context limit breach"); caliptra_drivers::report_fw_error_non_fatal(e.into()); } Err(e) => { diff --git a/runtime/src/get_fmc_alias_csr.rs b/runtime/src/get_fmc_alias_csr.rs new file mode 100644 index 0000000000..76d17ae1ce --- /dev/null +++ b/runtime/src/get_fmc_alias_csr.rs @@ -0,0 +1,51 @@ +// Licensed under the Apache-2.0 license + +use crate::Drivers; + +use caliptra_cfi_derive_git::cfi_impl_fn; +use caliptra_cfi_lib_git::cfi_launder; + +use caliptra_common::{ + cprintln, + mailbox_api::{GetFmcAliasCsrReq, GetFmcAliasCsrResp, MailboxResp, MailboxRespHeader}, +}; +use caliptra_error::{CaliptraError, CaliptraResult}; + +use caliptra_drivers::{FmcAliasCsr, IdevIdCsr}; + +use zerocopy::{FromBytes, IntoBytes}; + +pub struct GetFmcAliasCsrCmd; +impl GetFmcAliasCsrCmd { + // #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] + #[inline(never)] + pub(crate) fn execute(drivers: &mut Drivers, cmd_args: &[u8]) -> CaliptraResult { + let csr_persistent_mem = &drivers.persistent_data.get().fmc_alias_csr; + + match csr_persistent_mem.get_csr_len() { + FmcAliasCsr::UNPROVISIONED_CSR => Err(CaliptraError::RUNTIME_GET_FMC_CSR_UNPROVISIONED), + len => { + let mut resp = GetFmcAliasCsrResp { + data_size: len, + ..Default::default() + }; + + let csr = csr_persistent_mem + .get() + .ok_or(CaliptraError::RUNTIME_GET_FMC_CSR_UNPROVISIONED)?; + + // NOTE: This code will not panic. + // + // csr is guranteed to be the same size as `len`, and therefore + // `resp.data_size` by the `FmcAliasCsr::get` API. + // + // A valid `IDevIDCsr` cannot be larger than `MAX_CSR_SIZE`, which is the max + // size of the buffer in `GetIdevCsrResp` + resp.data[..resp.data_size as usize].copy_from_slice(csr); + + Ok(MailboxResp::GetFmcAliasCsr(resp)) + } + _ => Err(CaliptraError::RUNTIME_INTERNAL), + } + } +} diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index aa802cedb2..a6af89223d 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -22,6 +22,7 @@ mod dpe_crypto; mod dpe_platform; mod drivers; pub mod fips; +mod get_fmc_alias_csr; mod get_idev_csr; pub mod handoff; mod hmac; @@ -58,6 +59,7 @@ pub use fips::FipsShutdownCmd; pub use fips::{fips_self_test_cmd, fips_self_test_cmd::SelfTestStatus}; pub use populate_idev::PopulateIDevIdCertCmd; +pub use get_fmc_alias_csr::GetFmcAliasCsrCmd; pub use get_idev_csr::GetIdevCsrCmd; pub use info::{FwInfoCmd, IDevIdInfoCmd}; pub use invoke_dpe::InvokeDpeCmd; @@ -175,11 +177,7 @@ fn handle_command(drivers: &mut Drivers) -> CaliptraResult { let req_packet = Packet::copy_from_mbox(drivers)?; let cmd_bytes = req_packet.as_bytes()?; - cprintln!( - "[rt] Received command=0x{:x}, len={}", - req_packet.cmd, - req_packet.len - ); + cprintln!("[rt]cmd =0x{:x}, len={}", req_packet.cmd, req_packet.len); // Handle the request and generate the response let mut resp = match CommandId::from(req_packet.cmd) { @@ -229,6 +227,7 @@ fn handle_command(drivers: &mut Drivers) -> CaliptraResult { CommandId::SET_AUTH_MANIFEST => SetAuthManifestCmd::execute(drivers, cmd_bytes), CommandId::AUTHORIZE_AND_STASH => AuthorizeAndStashCmd::execute(drivers, cmd_bytes), CommandId::GET_IDEV_CSR => GetIdevCsrCmd::execute(drivers, cmd_bytes), + CommandId::GET_FMC_ALIAS_CSR => GetFmcAliasCsrCmd::execute(drivers, cmd_bytes), _ => Err(CaliptraError::RUNTIME_UNIMPLEMENTED_COMMAND), }; let resp = okmutref(&mut resp)?; @@ -272,7 +271,7 @@ pub fn handle_mailbox_commands(drivers: &mut Drivers) -> CaliptraResult<()> { } match result { Ok(_) => { - cprintln!("Disabled attestation due to cmd busy during warm reset"); + cprintln!("Disabled attest - cmd busy + warm rst"); caliptra_drivers::report_fw_error_non_fatal( CaliptraError::RUNTIME_CMD_BUSY_DURING_WARM_RESET.into(), ); diff --git a/runtime/src/main.rs b/runtime/src/main.rs index 6c844d30e6..8558a5cf92 100644 --- a/runtime/src/main.rs +++ b/runtime/src/main.rs @@ -28,14 +28,7 @@ use core::hint::black_box; #[cfg(feature = "std")] pub fn main() {} -const BANNER: &str = r#" - ____ _ _ _ ____ _____ - / ___|__ _| (_)_ __ | |_ _ __ __ _ | _ \_ _| -| | / _` | | | '_ \| __| '__/ _` | | |_) || | -| |__| (_| | | | |_) | |_| | | (_| | | _ < | | - \____\__,_|_|_| .__/ \__|_| \__,_| |_| \_\|_| - |_| -"#; +const BANNER: &str = r#"Caliptra RT"#; #[no_mangle] #[allow(clippy::empty_loop)] @@ -79,15 +72,15 @@ pub extern "C" fn entry_point() -> ! { } drivers.run_reset_flow().unwrap_or_else(|e| { - cprintln!("[rt] Runtime failed reset flow"); + cprintln!("[rt] failed reset flow"); handle_fatal_error(e.into()); }); if !drivers.persistent_data.get().fht.is_valid() { - cprintln!("[rt] Runtime can't load FHT"); + cprintln!("[rt] can't load FHT"); handle_fatal_error(caliptra_drivers::CaliptraError::RUNTIME_HANDOFF_FHT_NOT_LOADED.into()); } - cprintln!("[rt] Runtime listening for mailbox commands..."); + cprintln!("[rt] listening for commands..."); if let Err(e) = caliptra_runtime::handle_mailbox_commands(&mut drivers) { handle_fatal_error(e.into()); } diff --git a/runtime/tests/runtime_integration_tests/common.rs b/runtime/tests/runtime_integration_tests/common.rs index 020df5fc08..1e1bdd8eeb 100644 --- a/runtime/tests/runtime_integration_tests/common.rs +++ b/runtime/tests/runtime_integration_tests/common.rs @@ -1,5 +1,6 @@ // Licensed under the Apache-2.0 license +use caliptra_api::mailbox::Request; use caliptra_api::SocManager; use caliptra_builder::{ firmware::{APP_WITH_UART, APP_WITH_UART_FPGA, FMC_WITH_UART}, @@ -34,7 +35,7 @@ use openssl::{ x509::{X509Builder, X509}, x509::{X509Name, X509NameBuilder}, }; -use zerocopy::{FromBytes, IntoBytes}; +use zerocopy::{FromBytes, FromZeros, IntoBytes}; pub const TEST_LABEL: [u8; 48] = [ 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, @@ -276,6 +277,20 @@ pub fn assert_error( } } +pub fn get_certs(model: &mut DefaultHwModel) -> R::Resp { + let payload = MailboxReqHeader { + chksum: caliptra_common::checksum::calc_checksum(u32::from(R::ID), &[]), + }; + let resp_data = model + .mailbox_execute(u32::from(R::ID), payload.as_bytes()) + .unwrap() + .unwrap(); + assert!(resp_data.len() <= std::mem::size_of::<::Resp>()); + let mut resp = R::Resp::new_zeroed(); + resp.as_mut_bytes()[..resp_data.len()].copy_from_slice(&resp_data); + resp +} + pub fn get_fmc_alias_cert(model: &mut DefaultHwModel) -> GetFmcAliasCertResp { let payload = MailboxReqHeader { chksum: caliptra_common::checksum::calc_checksum( diff --git a/runtime/tests/runtime_integration_tests/main.rs b/runtime/tests/runtime_integration_tests/main.rs index 417946cda3..4384566326 100644 --- a/runtime/tests/runtime_integration_tests/main.rs +++ b/runtime/tests/runtime_integration_tests/main.rs @@ -8,6 +8,7 @@ mod test_certs; mod test_disable; mod test_ecdsa; mod test_fips; +mod test_get_fmc_alias_csr; mod test_get_idev_csr; mod test_info; mod test_invoke_dpe; diff --git a/runtime/tests/runtime_integration_tests/test_data/fmc_alias_csr.der b/runtime/tests/runtime_integration_tests/test_data/fmc_alias_csr.der new file mode 100644 index 0000000000000000000000000000000000000000..c20863f96c074789a71252b93f9b6f48a19e238e GIT binary patch literal 447 zcmXqLV%%-e#OTPx$Y79TC~qLk#vIDR%p>NUn3GvhQk1A*sAr(y=IgBBn3I`UZ0Kp= z4pP7>>|kciSy!s_Ue-S=5`sxkAX+inhuN(Hyn*Z?p+^HK&UNX( z`pwa_xJ!g}VzPL|6#uaMub2${Z+q#feOmRV#PLbpp{%3qFE, + ) { + let get_rt_alias_cert_resp = get_certs::(model); + assert_ne!(0, get_rt_alias_cert_resp.data_size); + + let der = &get_rt_alias_cert_resp.data[..get_rt_alias_cert_resp.data_size as usize]; + let cert = openssl::x509::X509::from_der(der).unwrap(); + + assert!( + cert.verify(&pub_key).unwrap(), + "Invalid public key. Unable to verify RT Alias Cert", + ); + } + fn get_fmc_alias_csr(model: &mut DefaultHwModel) -> openssl::x509::X509Req { + let get_fmc_alias_csr_resp = get_certs::(model); + + assert_ne!( + FmcAliasCsr::UNPROVISIONED_CSR, + get_fmc_alias_csr_resp.data_size + ); + assert_ne!(0, get_fmc_alias_csr_resp.data_size); + + let csr_der = &get_fmc_alias_csr_resp.data[..get_fmc_alias_csr_resp.data_size as usize]; + let csr = openssl::x509::X509Req::from_der(csr_der).unwrap(); + + assert_ne!([0; MAX_CSR_SIZE], csr_der); + + csr + } + let mut model = run_rt_test(RuntimeTestArgs::default()); + + let csr = get_fmc_alias_csr(&mut model); + + let pubkey = csr.public_key().unwrap(); + assert!( + csr.verify(&pubkey).unwrap(), + "Invalid public key. Unable to verify FMC Alias CSR", + ); + + verify_rt_cert(&mut model, pubkey); +} + +#[test] +fn test_missing_csr() { + let mut model = run_rt_test(RuntimeTestArgs::default()); + + model.step_until(|m| { + m.soc_ifc().cptra_boot_status().read() == u32::from(RtBootStatus::RtReadyForCommands) + }); + + let payload = MailboxReqHeader { + chksum: caliptra_common::checksum::calc_checksum(u32::from(CommandId::GET_IDEV_CSR), &[]), + }; + + let response = model + .mailbox_execute(CommandId::GET_IDEV_CSR.into(), payload.as_bytes()) + .unwrap_err(); + + match get_ci_rom_version() { + // 1.0 and 1.1 ROM do not support this feature + CiRomVersion::Rom1_0 | CiRomVersion::Rom1_1 => assert_eq!( + response, + ModelError::MailboxCmdFailed(CaliptraError::RUNTIME_GET_IDEV_ID_UNSUPPORTED_ROM.into()) + ), + _ => assert_eq!( + response, + ModelError::MailboxCmdFailed(CaliptraError::RUNTIME_GET_IDEV_ID_UNPROVISIONED.into()) + ), + }; +} diff --git a/test/tests/caliptra_integration_tests/fake_collateral_boot_test.rs b/test/tests/caliptra_integration_tests/fake_collateral_boot_test.rs index 7460870fe7..ecb6eaba6c 100755 --- a/test/tests/caliptra_integration_tests/fake_collateral_boot_test.rs +++ b/test/tests/caliptra_integration_tests/fake_collateral_boot_test.rs @@ -93,14 +93,7 @@ fn fake_boot_test() { assert_output_contains(&output, "Running Caliptra ROM"); assert_output_contains(&output, "[fake-rom-cold-reset]"); assert_output_contains(&output, "Running Caliptra FMC"); - assert_output_contains( - &output, - r#" - / ___|__ _| (_)_ __ | |_ _ __ __ _ | _ \_ _| -| | / _` | | | '_ \| __| '__/ _` | | |_) || | -| |__| (_| | | | |_) | |_| | | (_| | | _ < | | - \____\__,_|_|_| .__/ \__|_| \__,_| |_| \_\|_|"#, - ); + assert_output_contains(&output, r#"Caliptra RT"#); let payload = MailboxReqHeader { chksum: caliptra_common::checksum::calc_checksum(u32::from(CommandId::GET_LDEV_CERT), &[]), diff --git a/test/tests/caliptra_integration_tests/smoke_test.rs b/test/tests/caliptra_integration_tests/smoke_test.rs index 4d1a7562ff..2501ed90dd 100644 --- a/test/tests/caliptra_integration_tests/smoke_test.rs +++ b/test/tests/caliptra_integration_tests/smoke_test.rs @@ -235,7 +235,7 @@ fn smoke_test() { .unwrap(); if firmware::rom_from_env() == &firmware::ROM_WITH_UART { - hw.step_until_output_contains("[rt] Runtime listening for mailbox commands...\n") + hw.step_until_output_contains("[rt] listening for commands...\n") .unwrap(); let output = hw.output().take(usize::MAX); assert_output_contains(&output, "Running Caliptra ROM"); @@ -250,14 +250,7 @@ fn smoke_test() { assert_output_contains(&output, "[kat] LMS"); assert_output_contains(&output, "[kat] --"); assert_output_contains(&output, "Running Caliptra FMC"); - assert_output_contains( - &output, - r#" - / ___|__ _| (_)_ __ | |_ _ __ __ _ | _ \_ _| -| | / _` | | | '_ \| __| '__/ _` | | |_) || | -| |__| (_| | | | |_) | |_| | | (_| | | _ < | | - \____\__,_|_|_| .__/ \__|_| \__,_| |_| \_\|_|"#, - ); + assert_output_contains(&output, r#"Caliptra RT"#); } let ldev_cert_resp = hw.mailbox_execute_req(GetLdevCertReq::default()).unwrap(); @@ -788,7 +781,7 @@ fn test_rt_wdt_timeout() { hw.step_until_boot_status(RUNTIME_BOOT_STATUS_READY, true); let fmc_target = hw.output().sink().now(); - let rt_wdt_timeout_cycles = fmc_target - wdt_start - 5_000; + let rt_wdt_timeout_cycles = fmc_target - wdt_start - 2_000; drop(hw); let security_state = *caliptra_hw_model::SecurityState::default().set_debug_locked(true); diff --git a/x509/build/build.rs b/x509/build/build.rs index aa728c6eaa..37df7dfdf9 100644 --- a/x509/build/build.rs +++ b/x509/build/build.rs @@ -39,6 +39,7 @@ fn main() { let out_dir = out_dir_os_str.to_str().unwrap(); gen_init_devid_csr(out_dir); + gen_fmc_alias_csr(out_dir); gen_local_devid_cert(out_dir); gen_fmc_alias_cert(out_dir); gen_rt_alias_cert(out_dir); @@ -58,6 +59,18 @@ fn gen_init_devid_csr(out_dir: &str) { CodeGen::gen_code("InitDevIdCsrTbs", template, out_dir); } +#[cfg(feature = "generate_templates")] +fn gen_fmc_alias_csr(out_dir: &str) { + let mut usage = KeyUsage::default(); + usage.set_key_cert_sign(true); + let bldr = csr::CsrTemplateBuilder::::new() + .add_basic_constraints_ext(true, 5) + .add_key_usage_ext(usage) + .add_ueid_ext(&[0xFF; 17]); + let template = bldr.tbs_template("Caliptra 1.0 FMC Alias"); + CodeGen::gen_code("FmcAliasCsrTbs", template, out_dir); +} + /// Generate Local DeviceId Certificate Template #[cfg(feature = "generate_templates")] fn gen_local_devid_cert(out_dir: &str) { diff --git a/x509/build/csr.rs b/x509/build/csr.rs index 3293b71849..1752ac090a 100644 --- a/x509/build/csr.rs +++ b/x509/build/csr.rs @@ -8,7 +8,7 @@ File Name: Abstract: - File contains generation of X509 Certificate Signing Request (CSR) To Be Singed (TBS) + File contains generation of X509 Certificate Signing Request (CSR) To Be Signed (TBS) template that can be substituted at firmware runtime. --*/ diff --git a/x509/build/fmc_alias_csr_tbs.rs b/x509/build/fmc_alias_csr_tbs.rs new file mode 100644 index 0000000000..71d9afb0b3 --- /dev/null +++ b/x509/build/fmc_alias_csr_tbs.rs @@ -0,0 +1,89 @@ +#[doc = "++ + +Licensed under the Apache-2.0 license. + +Abstract: + + Regenerate the template by building caliptra-x509-build with the generate-templates flag. + +--"] +pub struct FmcAliasCsrTbsParams<'a> { + pub ueid: &'a [u8; 17usize], + pub public_key: &'a [u8; 97usize], + pub subject_sn: &'a [u8; 64usize], +} +impl<'a> FmcAliasCsrTbsParams<'a> { + pub const UEID_LEN: usize = 17usize; + pub const PUBLIC_KEY_LEN: usize = 97usize; + pub const SUBJECT_SN_LEN: usize = 64usize; +} +pub struct FmcAliasCsrTbs { + tbs: [u8; Self::TBS_TEMPLATE_LEN], +} +impl FmcAliasCsrTbs { + const UEID_OFFSET: usize = 308usize; + const PUBLIC_KEY_OFFSET: usize = 140usize; + const SUBJECT_SN_OFFSET: usize = 53usize; + const UEID_LEN: usize = 17usize; + const PUBLIC_KEY_LEN: usize = 97usize; + const SUBJECT_SN_LEN: usize = 64usize; + pub const TBS_TEMPLATE_LEN: usize = 325usize; + const TBS_TEMPLATE: [u8; Self::TBS_TEMPLATE_LEN] = [ + 48u8, 130u8, 1u8, 65u8, 2u8, 1u8, 0u8, 48u8, 108u8, 49u8, 31u8, 48u8, 29u8, 6u8, 3u8, 85u8, + 4u8, 3u8, 12u8, 22u8, 67u8, 97u8, 108u8, 105u8, 112u8, 116u8, 114u8, 97u8, 32u8, 49u8, + 46u8, 48u8, 32u8, 70u8, 77u8, 67u8, 32u8, 65u8, 108u8, 105u8, 97u8, 115u8, 49u8, 73u8, + 48u8, 71u8, 6u8, 3u8, 85u8, 4u8, 5u8, 19u8, 64u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, + 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, + 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, + 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, + 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 48u8, 118u8, 48u8, + 16u8, 6u8, 7u8, 42u8, 134u8, 72u8, 206u8, 61u8, 2u8, 1u8, 6u8, 5u8, 43u8, 129u8, 4u8, 0u8, + 34u8, 3u8, 98u8, 0u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, + 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, + 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, + 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, + 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, + 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, + 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 160u8, 86u8, 48u8, 84u8, + 6u8, 9u8, 42u8, 134u8, 72u8, 134u8, 247u8, 13u8, 1u8, 9u8, 14u8, 49u8, 71u8, 48u8, 69u8, + 48u8, 18u8, 6u8, 3u8, 85u8, 29u8, 19u8, 1u8, 1u8, 255u8, 4u8, 8u8, 48u8, 6u8, 1u8, 1u8, + 255u8, 2u8, 1u8, 5u8, 48u8, 14u8, 6u8, 3u8, 85u8, 29u8, 15u8, 1u8, 1u8, 255u8, 4u8, 4u8, + 3u8, 2u8, 2u8, 4u8, 48u8, 31u8, 6u8, 6u8, 103u8, 129u8, 5u8, 5u8, 4u8, 4u8, 4u8, 21u8, + 48u8, 19u8, 4u8, 17u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, + 95u8, 95u8, 95u8, 95u8, 95u8, 95u8, + ]; + pub fn new(params: &FmcAliasCsrTbsParams) -> Self { + let mut template = Self { + tbs: Self::TBS_TEMPLATE, + }; + template.apply(params); + template + } + pub fn sign( + &self, + sign_fn: impl Fn(&[u8]) -> Result, + ) -> Result { + sign_fn(&self.tbs) + } + pub fn tbs(&self) -> &[u8] { + &self.tbs + } + fn apply(&mut self, params: &FmcAliasCsrTbsParams) { + #[inline(always)] + fn apply_slice( + buf: &mut [u8; 325usize], + val: &[u8; LEN], + ) { + buf[OFFSET..OFFSET + LEN].copy_from_slice(val); + } + apply_slice::<{ Self::UEID_OFFSET }, { Self::UEID_LEN }>(&mut self.tbs, params.ueid); + apply_slice::<{ Self::PUBLIC_KEY_OFFSET }, { Self::PUBLIC_KEY_LEN }>( + &mut self.tbs, + params.public_key, + ); + apply_slice::<{ Self::SUBJECT_SN_OFFSET }, { Self::SUBJECT_SN_LEN }>( + &mut self.tbs, + params.subject_sn, + ); + } +} diff --git a/x509/src/fmc_alias_csr.rs b/x509/src/fmc_alias_csr.rs new file mode 100644 index 0000000000..99f0bc3043 --- /dev/null +++ b/x509/src/fmc_alias_csr.rs @@ -0,0 +1,177 @@ +/*++ + +Licensed under the Apache-2.0 license. + +File Name: + + idevid_csr.rs + +Abstract: + + Initial Device ID Certificate Signing Request related code. + +--*/ + +// Note: All the necessary code is auto generated +#[cfg(feature = "generate_templates")] +include!(concat!(env!("OUT_DIR"), "/fmc_alias_csr_tbs.rs")); +#[cfg(not(feature = "generate_templates"))] +include! {"../build/fmc_alias_csr_tbs.rs"} + +#[cfg(all(test, target_family = "unix"))] +mod tests { + use openssl::sha::Sha384; + use openssl::{ecdsa::EcdsaSig, x509::X509Req}; + + use x509_parser::cri_attributes::ParsedCriAttribute; + use x509_parser::extensions::ParsedExtension; + use x509_parser::oid_registry::asn1_rs::oid; + use x509_parser::prelude::{FromDer, X509CertificationRequest}; + + use super::*; + use crate::test_util::tests::*; + use crate::{Ecdsa384CsrBuilder, Ecdsa384Signature}; + + const TEST_UEID: &[u8] = &[0xAB; FmcAliasCsrTbs::UEID_LEN]; + + fn make_test_csr(subject_key: &Ecc384AsymKey) -> FmcAliasCsrTbs { + let params = FmcAliasCsrTbsParams { + public_key: &subject_key.pub_key().try_into().unwrap(), + subject_sn: &subject_key.hex_str().into_bytes().try_into().unwrap(), + ueid: &TEST_UEID.try_into().unwrap(), + }; + + FmcAliasCsrTbs::new(¶ms) + } + + #[test] + fn test_csr_signing() { + let key = Ecc384AsymKey::default(); + let ec_key = key.priv_key().ec_key().unwrap(); + let csr = make_test_csr(&key); + + let sig: EcdsaSig = csr + .sign(|b| { + let mut sha = Sha384::new(); + sha.update(b); + EcdsaSig::sign(&sha.finish(), &ec_key) + }) + .unwrap(); + + assert_ne!(csr.tbs(), FmcAliasCsrTbs::TBS_TEMPLATE); + assert_eq!( + &csr.tbs()[FmcAliasCsrTbs::PUBLIC_KEY_OFFSET + ..FmcAliasCsrTbs::PUBLIC_KEY_OFFSET + FmcAliasCsrTbs::PUBLIC_KEY_LEN], + key.pub_key(), + ); + assert_eq!( + &csr.tbs()[FmcAliasCsrTbs::SUBJECT_SN_OFFSET + ..FmcAliasCsrTbs::SUBJECT_SN_OFFSET + FmcAliasCsrTbs::SUBJECT_SN_LEN], + key.hex_str().into_bytes(), + ); + assert_eq!( + &csr.tbs()[FmcAliasCsrTbs::UEID_OFFSET + ..FmcAliasCsrTbs::UEID_OFFSET + FmcAliasCsrTbs::UEID_LEN], + TEST_UEID, + ); + + let ecdsa_sig = crate::Ecdsa384Signature { + r: sig.r().to_vec_padded(48).unwrap().try_into().unwrap(), + s: sig.s().to_vec_padded(48).unwrap().try_into().unwrap(), + }; + + let builder = crate::Ecdsa384CsrBuilder::new(csr.tbs(), &ecdsa_sig).unwrap(); + let mut buf = vec![0u8; builder.len()]; + builder.build(&mut buf).unwrap(); + + let req: X509Req = X509Req::from_der(&buf).unwrap(); + assert!(req.verify(&req.public_key().unwrap()).unwrap()); + assert!(req.verify(key.priv_key()).unwrap()); + } + + #[test] + fn test_extensions() { + let key = Ecc384AsymKey::default(); + let ec_key = key.priv_key().ec_key().unwrap(); + let csr = make_test_csr(&key); + + let sig: EcdsaSig = csr + .sign(|b| { + let mut sha = Sha384::new(); + sha.update(b); + EcdsaSig::sign(&sha.finish(), &ec_key) + }) + .unwrap(); + + let ecdsa_sig = Ecdsa384Signature { + r: sig.r().to_vec_padded(48).unwrap().try_into().unwrap(), + s: sig.s().to_vec_padded(48).unwrap().try_into().unwrap(), + }; + + let builder = Ecdsa384CsrBuilder::new(csr.tbs(), &ecdsa_sig).unwrap(); + let mut buf = vec![0u8; builder.len()]; + builder.build(&mut buf).unwrap(); + + let (_, parsed_csr) = X509CertificationRequest::from_der(&buf).unwrap(); + + let requested_extensions = parsed_csr + .certification_request_info + .iter_attributes() + .find_map(|attr| { + if let ParsedCriAttribute::ExtensionRequest(requested) = attr.parsed_attribute() { + Some(&requested.extensions) + } else { + None + } + }) + .unwrap(); + + // BasicConstraints + let bc_ext = requested_extensions + .iter() + .find(|ext| matches!(ext.parsed_extension(), ParsedExtension::BasicConstraints(_))) + .unwrap(); + let ParsedExtension::BasicConstraints(bc) = bc_ext.parsed_extension() else { + panic!("Extension is not BasicConstraints"); + }; + + assert!(bc_ext.critical); + assert!(bc.ca); + + // KeyUsage + let ku_ext = requested_extensions + .iter() + .find(|ext| matches!(ext.parsed_extension(), ParsedExtension::KeyUsage(_))) + .unwrap(); + + assert!(ku_ext.critical); + + // UEID + let ueid_ext = requested_extensions + .iter() + .find(|ext| { + if let ParsedExtension::UnsupportedExtension { oid } = ext.parsed_extension() { + oid == &oid!(2.23.133 .5 .4 .4) + } else { + false + } + }) + .unwrap(); + assert!(!ueid_ext.critical); + } + + #[test] + #[cfg(feature = "generate_templates")] + fn test_idevid_template() { + let manual_template = + std::fs::read(std::path::Path::new("./build/init_dev_id_csr_tbs.rs")).unwrap(); + let auto_generated_template = std::fs::read(std::path::Path::new(concat!( + env!("OUT_DIR"), + "/init_dev_id_csr_tbs.rs" + ))) + .unwrap(); + if auto_generated_template != manual_template { + panic!("Auto-generated IDevID CSR template is not equal to the manual template.") + } + } +} diff --git a/x509/src/lib.rs b/x509/src/lib.rs index a0be131433..b36dd2fcbf 100644 --- a/x509/src/lib.rs +++ b/x509/src/lib.rs @@ -16,6 +16,7 @@ Abstract: mod cert_bldr; mod fmc_alias_cert; +mod fmc_alias_csr; mod idevid_csr; mod ldevid_cert; mod rt_alias_cert; @@ -23,6 +24,7 @@ mod test_util; pub use cert_bldr::{Ecdsa384CertBuilder, Ecdsa384CsrBuilder, Ecdsa384Signature}; pub use fmc_alias_cert::{FmcAliasCertTbs, FmcAliasCertTbsParams}; +pub use fmc_alias_csr::{FmcAliasCsrTbs, FmcAliasCsrTbsParams}; pub use idevid_csr::{InitDevIdCsrTbs, InitDevIdCsrTbsParams}; pub use ldevid_cert::{LocalDevIdCertTbs, LocalDevIdCertTbsParams}; pub use rt_alias_cert::{RtAliasCertTbs, RtAliasCertTbsParams}; From 13e1a7b03e73ab6c53a3c0e39e11d257414419f3 Mon Sep 17 00:00:00 2001 From: Anthony Rocha Date: Wed, 1 Jan 2025 16:41:17 -0800 Subject: [PATCH 2/4] Code review feedback. --- builder/src/firmware.rs | 8 ++++---- common/src/lib.rs | 4 ++-- drivers/Cargo.toml | 2 +- drivers/src/lib.rs | 2 +- drivers/src/persistent.rs | 16 ++++++++++----- error/src/lib.rs | 3 +++ fmc/Cargo.toml | 2 +- fmc/build.sh | 2 +- fmc/src/flow/crypto.rs | 4 ++++ fmc/src/flow/fmc_alias_csr.rs | 11 +++++----- fmc/src/flow/mod.rs | 20 ++++++++++++------- runtime/Cargo.toml | 5 +++-- runtime/build.sh | 1 + runtime/src/get_fmc_alias_csr.rs | 5 +++-- runtime/src/lib.rs | 3 +++ .../caliptra_integration_tests/jtag_test.rs | 2 +- 16 files changed, 57 insertions(+), 33 deletions(-) diff --git a/builder/src/firmware.rs b/builder/src/firmware.rs index e45c5916e5..12d8e79732 100644 --- a/builder/src/firmware.rs +++ b/builder/src/firmware.rs @@ -42,7 +42,7 @@ pub const ROM_WITH_FIPS_TEST_HOOKS: FwId = FwId { pub const FMC_WITH_UART: FwId = FwId { crate_name: "caliptra-fmc", bin_name: "caliptra-fmc", - features: &["emu"], + features: &["emu", "fmc-alias-csr"], }; pub const FMC_FAKE_WITH_UART: FwId = FwId { @@ -54,13 +54,13 @@ pub const FMC_FAKE_WITH_UART: FwId = FwId { pub const APP: FwId = FwId { crate_name: "caliptra-runtime", bin_name: "caliptra-runtime", - features: &["fips_self_test"], + features: &["fips_self_test", "fmc-alias-csr"], }; pub const APP_WITH_UART: FwId = FwId { crate_name: "caliptra-runtime", bin_name: "caliptra-runtime", - features: &["emu", "fips_self_test"], + features: &["emu", "fips_self_test", "fmc-alias-csr"], }; pub const APP_WITH_UART_FIPS_TEST_HOOKS: FwId = FwId { @@ -72,7 +72,7 @@ pub const APP_WITH_UART_FIPS_TEST_HOOKS: FwId = FwId { pub const APP_WITH_UART_FPGA: FwId = FwId { crate_name: "caliptra-runtime", bin_name: "caliptra-runtime", - features: &["emu", "fips_self_test", "fpga_realtime"], + features: &["emu", "fips_self_test", "fmc-alias-csr", "fpga_realtime"], }; pub const APP_ZEROS: FwId = FwId { diff --git a/common/src/lib.rs b/common/src/lib.rs index 8fb9032abc..8c804df09a 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -38,9 +38,9 @@ pub use fuse::{FuseLogEntry, FuseLogEntryId}; pub use pcr::{PcrLogEntry, PcrLogEntryId, RT_FW_CURRENT_PCR, RT_FW_JOURNEY_PCR}; pub const FMC_ORG: u32 = 0x40000000; -pub const FMC_SIZE: u32 = 22 * 1024 - 512; +pub const FMC_SIZE: u32 = 21 * 1024; pub const RUNTIME_ORG: u32 = FMC_ORG + FMC_SIZE; -pub const RUNTIME_SIZE: u32 = 95 * 1024 + 512; +pub const RUNTIME_SIZE: u32 = 96 * 1024; pub use memory_layout::{DATA_ORG, PERSISTENT_DATA_ORG}; pub use wdt::{restart_wdt, start_wdt, stop_wdt, WdtTimeout}; diff --git a/drivers/Cargo.toml b/drivers/Cargo.toml index ff90f5fa5c..04caa0a43f 100644 --- a/drivers/Cargo.toml +++ b/drivers/Cargo.toml @@ -37,7 +37,7 @@ verilator = ["caliptra-hw-model/verilator"] no-cfi = [] "hw-1.0" = ["caliptra-builder/hw-1.0", "caliptra-registers/hw-1.0"] fips-test-hooks = [] -fmc_alias_csr = [] +fmc-alias-csr = [] [dev-dependencies] caliptra-api.workspace = true diff --git a/drivers/src/lib.rs b/drivers/src/lib.rs index 5988219dc8..0e74ccbb1b 100644 --- a/drivers/src/lib.rs +++ b/drivers/src/lib.rs @@ -86,7 +86,7 @@ pub use okref::okmutref; pub use okref::okref; pub use pcr_bank::{PcrBank, PcrId}; pub use pcr_reset::PcrResetCounter; -#[cfg(feature = "fmc")] +#[cfg(feature = "fmc-alias-csr")] pub use persistent::fmc_alias_csr::FmcAliasCsr; #[cfg(feature = "runtime")] pub use persistent::AuthManifestImageMetadataList; diff --git a/drivers/src/persistent.rs b/drivers/src/persistent.rs index 1533b3554a..7e66545363 100644 --- a/drivers/src/persistent.rs +++ b/drivers/src/persistent.rs @@ -21,7 +21,7 @@ use crate::{ FirmwareHandoffTable, }; -#[cfg(feature = "fmc")] +#[cfg(feature = "fmc-alias-csr")] use crate::FmcAliasCsr; #[cfg(feature = "runtime")] @@ -74,7 +74,7 @@ pub struct IdevIdCsr { csr: [u8; MAX_CSR_SIZE], } -#[cfg(feature = "fmc")] +#[cfg(feature = "fmc-alias-csr")] pub mod fmc_alias_csr { use super::*; @@ -262,13 +262,13 @@ pub struct PersistentData { pub idevid_csr: IdevIdCsr, reserved10: [u8; IDEVID_CSR_SIZE as usize - size_of::()], - #[cfg(feature = "fmc")] + #[cfg(feature = "fmc-alias-csr")] pub fmc_alias_csr: FmcAliasCsr, - #[cfg(feature = "fmc")] + #[cfg(feature = "fmc-alias-csr")] reserved11: [u8; FMC_ALIAS_CSR_SIZE as usize - size_of::()], - #[cfg(not(feature = "fmc"))] + #[cfg(not(feature = "fmc-alias-csr"))] pub fmc_alias_csr: [u8; FMC_ALIAS_CSR_SIZE as usize], // Reserved memory for future objects. @@ -365,6 +365,12 @@ impl PersistentData { memory_layout::PERSISTENT_DATA_ORG + persistent_data_offset ); + persistent_data_offset += FMC_ALIAS_CSR_SIZE; + assert_eq!( + addr_of!((*P).reserved_memory) as u32, + memory_layout::PERSISTENT_DATA_ORG + persistent_data_offset + ); + assert_eq!( P.add(1) as u32, memory_layout::PERSISTENT_DATA_ORG + memory_layout::PERSISTENT_DATA_SIZE diff --git a/error/src/lib.rs b/error/src/lib.rs index b477793ae8..8cbcbb449f 100644 --- a/error/src/lib.rs +++ b/error/src/lib.rs @@ -453,6 +453,9 @@ impl CaliptraError { pub const RUNTIME_GET_FMC_CSR_UNPROVISIONED: CaliptraError = CaliptraError::new_const(0x000E0054); + pub const RUNTIME_GET_FMC_CSR_UNSUPPORTED_FMC: CaliptraError = + CaliptraError::new_const(0x000E0055); + /// FMC Errors pub const FMC_GLOBAL_NMI: CaliptraError = CaliptraError::new_const(0x000F0001); pub const FMC_GLOBAL_EXCEPTION: CaliptraError = CaliptraError::new_const(0x000F0002); diff --git a/fmc/Cargo.toml b/fmc/Cargo.toml index 7de33fa57e..eacf45d763 100644 --- a/fmc/Cargo.toml +++ b/fmc/Cargo.toml @@ -42,4 +42,4 @@ itrng = ["caliptra-hw-model/itrng"] verilator = ["caliptra-hw-model/verilator"] fake-fmc = [] "hw-1.0" = ["caliptra-builder/hw-1.0", "caliptra-cpu/hw-1.0", "caliptra-drivers/hw-1.0", "caliptra-registers/hw-1.0"] -fmc_alias_csr = ["caliptra-drivers/fmc_alias_csr"] \ No newline at end of file +fmc-alias-csr = ["caliptra-drivers/fmc-alias-csr"] \ No newline at end of file diff --git a/fmc/build.sh b/fmc/build.sh index dce5b31441..dcd7526e37 100755 --- a/fmc/build.sh +++ b/fmc/build.sh @@ -9,5 +9,5 @@ cargo build \ --target riscv32imc-unknown-none-elf \ --profile=firmware \ --no-default-features \ - --features=fmc_alias_csr \ + --features=fmc-alias-csr \ --bin=caliptra-fmc diff --git a/fmc/src/flow/crypto.rs b/fmc/src/flow/crypto.rs index 60e6a4ca2b..e1e275305f 100644 --- a/fmc/src/flow/crypto.rs +++ b/fmc/src/flow/crypto.rs @@ -8,7 +8,9 @@ Abstract: use caliptra_x509::Ecdsa384Signature; use crate::fmc_env::FmcEnv; +#[cfg(feature = "fmc-alias-csr")] use caliptra_drivers::okmutref; +#[cfg(feature = "fmc-alias-csr")] use zeroize::Zeroize; use caliptra_cfi_derive::cfi_impl_fn; @@ -218,12 +220,14 @@ impl Crypto { /// /// * `env` - FMC Environment /// * `priv_key` - Key slot to retrieve the private key + /// * `pub_key` - Public key to verify with /// * `data` - Input data to hash /// /// # Returns /// /// * `Ecc384Signature` - Signature #[inline(always)] + #[cfg(feature = "fmc-alias-csr")] pub fn ecdsa384_sign_and_verify( env: &mut FmcEnv, priv_key: KeyId, diff --git a/fmc/src/flow/fmc_alias_csr.rs b/fmc/src/flow/fmc_alias_csr.rs index 386ba45f81..dccb688e28 100644 --- a/fmc/src/flow/fmc_alias_csr.rs +++ b/fmc/src/flow/fmc_alias_csr.rs @@ -12,6 +12,7 @@ use crate::flow::crypto::Ecdsa384SignatureAdapter; use zeroize::Zeroize; use caliptra_drivers::okmutref; + use caliptra_drivers::FmcAliasCsr; use caliptra_x509::FmcAliasCsrTbs; @@ -25,7 +26,7 @@ use caliptra_x509::Ecdsa384CsrBuilder; /// /// # Arguments /// -/// * `hand_off` - HandOff +/// * `env` - FMC Environment /// /// # Returns /// @@ -48,12 +49,10 @@ fn dice_output_from_hand_off(env: &mut FmcEnv) -> CaliptraResult { Ok(output) } -fn write_csr_to_peristent_storage(env: &mut FmcEnv, csr: &FmcAliasCsr) -> CaliptraResult<()> { +fn write_csr_to_peristent_storage(env: &mut FmcEnv, csr: &FmcAliasCsr) { let csr_persistent_mem = &mut env.persistent_data.get_mut().fmc_alias_csr; *csr_persistent_mem = csr.clone(); - - Ok(()) } #[inline(always)] @@ -115,9 +114,9 @@ pub fn make_csr(env: &mut FmcEnv, output: &DiceOutput) -> CaliptraResult<()> { let fmc_alias_csr = FmcAliasCsr::new(&csr_buf, csr_len)?; - let result = write_csr_to_peristent_storage(env, &fmc_alias_csr); + write_csr_to_peristent_storage(env, &fmc_alias_csr); csr_buf.zeroize(); - result + Ok(()) } diff --git a/fmc/src/flow/mod.rs b/fmc/src/flow/mod.rs index 466dc1c518..c532f5441c 100644 --- a/fmc/src/flow/mod.rs +++ b/fmc/src/flow/mod.rs @@ -14,14 +14,13 @@ Abstract: mod crypto; pub mod dice; +#[cfg(feature = "fmc-alias-csr")] mod fmc_alias_csr; mod pcr; mod rt_alias; mod tci; mod x509; -use caliptra_drivers::ResetReason; - use crate::flow::rt_alias::RtAliasLayer; use crate::fmc_env::FmcEnv; @@ -33,11 +32,18 @@ use caliptra_drivers::CaliptraResult; /// /// * `env` - FMC Environment pub fn run(env: &mut FmcEnv) -> CaliptraResult<()> { - let reset_reason = env.soc_ifc.reset_reason(); - - if reset_reason == ResetReason::ColdReset { - // Generate the FMC Alias Certificate Signing Request (CSR) - fmc_alias_csr::generate_csr(env)?; + #[cfg(feature = "fmc-alias-csr")] + { + use caliptra_cfi_lib::cfi_assert_eq; + use caliptra_drivers::ResetReason; + + let reset_reason = env.soc_ifc.reset_reason(); + + if reset_reason == ResetReason::ColdReset { + cfi_assert_eq(env.soc_ifc.reset_reason(), ResetReason::ColdReset); + // Generate the FMC Alias Certificate Signing Request (CSR) + fmc_alias_csr::generate_csr(env)?; + } } RtAliasLayer::run(env) diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 3669787260..8f521e7ede 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -11,7 +11,7 @@ caliptra-cfi-lib-git = { workspace = true, default-features = false, features = caliptra-cfi-derive-git.workspace = true caliptra_common = { workspace = true, default-features = false, features = ["runtime"] } caliptra-cpu.workspace = true -caliptra-drivers = { workspace = true, features = ["fmc", "runtime"] } +caliptra-drivers = { workspace = true, features = ["fmc-alias-csr", "runtime"] } caliptra-error = { workspace = true, default-features = false } caliptra-image-types = { workspace = true, default-features = false } caliptra-auth-man-types = { workspace = true, default-features = false } @@ -64,4 +64,5 @@ fips_self_test=[] no-cfi = ["caliptra-image-verify/no-cfi", "caliptra-drivers/no-cfi"] fpga_realtime = ["caliptra-drivers/fpga_realtime"] "hw-1.0" = ["caliptra-builder/hw-1.0", "caliptra-drivers/hw-1.0", "caliptra-registers/hw-1.0", "caliptra-kat/hw-1.0","caliptra-cpu/hw-1.0"] -fips-test-hooks = ["caliptra-drivers/fips-test-hooks"] \ No newline at end of file +fips-test-hooks = ["caliptra-drivers/fips-test-hooks"] +fmc-alias-csr = ["caliptra-drivers/fmc-alias-csr"] \ No newline at end of file diff --git a/runtime/build.sh b/runtime/build.sh index 4d38168cfd..79dda8ca62 100755 --- a/runtime/build.sh +++ b/runtime/build.sh @@ -9,4 +9,5 @@ cargo build \ --target riscv32imc-unknown-none-elf \ --profile=firmware \ --no-default-features \ + --features=fmc-alias-csr \ --bin=caliptra-runtime diff --git a/runtime/src/get_fmc_alias_csr.rs b/runtime/src/get_fmc_alias_csr.rs index 76d17ae1ce..245550e862 100644 --- a/runtime/src/get_fmc_alias_csr.rs +++ b/runtime/src/get_fmc_alias_csr.rs @@ -17,13 +17,14 @@ use zerocopy::{FromBytes, IntoBytes}; pub struct GetFmcAliasCsrCmd; impl GetFmcAliasCsrCmd { - // #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] #[inline(never)] pub(crate) fn execute(drivers: &mut Drivers, cmd_args: &[u8]) -> CaliptraResult { let csr_persistent_mem = &drivers.persistent_data.get().fmc_alias_csr; match csr_persistent_mem.get_csr_len() { FmcAliasCsr::UNPROVISIONED_CSR => Err(CaliptraError::RUNTIME_GET_FMC_CSR_UNPROVISIONED), + 0 => Err(CaliptraError::RUNTIME_GET_FMC_CSR_UNSUPPORTED_FMC), len => { let mut resp = GetFmcAliasCsrResp { data_size: len, @@ -39,7 +40,7 @@ impl GetFmcAliasCsrCmd { // csr is guranteed to be the same size as `len`, and therefore // `resp.data_size` by the `FmcAliasCsr::get` API. // - // A valid `IDevIDCsr` cannot be larger than `MAX_CSR_SIZE`, which is the max + // A valid `FmcAliasCsr` cannot be larger than `MAX_CSR_SIZE`, which is the max // size of the buffer in `GetIdevCsrResp` resp.data[..resp.data_size as usize].copy_from_slice(csr); diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index a6af89223d..c996e3c4cb 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -22,6 +22,7 @@ mod dpe_crypto; mod dpe_platform; mod drivers; pub mod fips; +#[cfg(feature = "fmc-alias-csr")] mod get_fmc_alias_csr; mod get_idev_csr; pub mod handoff; @@ -59,6 +60,7 @@ pub use fips::FipsShutdownCmd; pub use fips::{fips_self_test_cmd, fips_self_test_cmd::SelfTestStatus}; pub use populate_idev::PopulateIDevIdCertCmd; +#[cfg(feature = "fmc-alias-csr")] pub use get_fmc_alias_csr::GetFmcAliasCsrCmd; pub use get_idev_csr::GetIdevCsrCmd; pub use info::{FwInfoCmd, IDevIdInfoCmd}; @@ -227,6 +229,7 @@ fn handle_command(drivers: &mut Drivers) -> CaliptraResult { CommandId::SET_AUTH_MANIFEST => SetAuthManifestCmd::execute(drivers, cmd_bytes), CommandId::AUTHORIZE_AND_STASH => AuthorizeAndStashCmd::execute(drivers, cmd_bytes), CommandId::GET_IDEV_CSR => GetIdevCsrCmd::execute(drivers, cmd_bytes), + #[cfg(feature = "fmc-alias-csr")] CommandId::GET_FMC_ALIAS_CSR => GetFmcAliasCsrCmd::execute(drivers, cmd_bytes), _ => Err(CaliptraError::RUNTIME_UNIMPLEMENTED_COMMAND), }; diff --git a/test/tests/caliptra_integration_tests/jtag_test.rs b/test/tests/caliptra_integration_tests/jtag_test.rs index 77131fae84..9814f15a4e 100644 --- a/test/tests/caliptra_integration_tests/jtag_test.rs +++ b/test/tests/caliptra_integration_tests/jtag_test.rs @@ -121,7 +121,7 @@ fn gdb_test() { .unwrap(); hw.step(); - hw.step_until_output_contains("[rt] Runtime listening for mailbox commands...\n") + hw.step_until_output_contains("[rt] listening for commands...\n") .unwrap(); #[cfg(feature = "fpga_realtime")] From cc00397c35e861ff91f74c93b7b1eb8b695a1505 Mon Sep 17 00:00:00 2001 From: Anthony Rocha Date: Fri, 10 Jan 2025 13:49:58 -0800 Subject: [PATCH 3/4] Remove fmc-alias-csr feature. --- builder/src/firmware.rs | 8 ++++---- drivers/Cargo.toml | 1 - drivers/src/lib.rs | 1 - drivers/src/persistent.rs | 7 ------- fmc/Cargo.toml | 1 - fmc/build.sh | 1 - fmc/src/flow/crypto.rs | 3 --- fmc/src/flow/mod.rs | 2 -- runtime/Cargo.toml | 3 +-- runtime/build.sh | 1 - runtime/src/lib.rs | 3 --- 11 files changed, 5 insertions(+), 26 deletions(-) diff --git a/builder/src/firmware.rs b/builder/src/firmware.rs index 12d8e79732..e45c5916e5 100644 --- a/builder/src/firmware.rs +++ b/builder/src/firmware.rs @@ -42,7 +42,7 @@ pub const ROM_WITH_FIPS_TEST_HOOKS: FwId = FwId { pub const FMC_WITH_UART: FwId = FwId { crate_name: "caliptra-fmc", bin_name: "caliptra-fmc", - features: &["emu", "fmc-alias-csr"], + features: &["emu"], }; pub const FMC_FAKE_WITH_UART: FwId = FwId { @@ -54,13 +54,13 @@ pub const FMC_FAKE_WITH_UART: FwId = FwId { pub const APP: FwId = FwId { crate_name: "caliptra-runtime", bin_name: "caliptra-runtime", - features: &["fips_self_test", "fmc-alias-csr"], + features: &["fips_self_test"], }; pub const APP_WITH_UART: FwId = FwId { crate_name: "caliptra-runtime", bin_name: "caliptra-runtime", - features: &["emu", "fips_self_test", "fmc-alias-csr"], + features: &["emu", "fips_self_test"], }; pub const APP_WITH_UART_FIPS_TEST_HOOKS: FwId = FwId { @@ -72,7 +72,7 @@ pub const APP_WITH_UART_FIPS_TEST_HOOKS: FwId = FwId { pub const APP_WITH_UART_FPGA: FwId = FwId { crate_name: "caliptra-runtime", bin_name: "caliptra-runtime", - features: &["emu", "fips_self_test", "fmc-alias-csr", "fpga_realtime"], + features: &["emu", "fips_self_test", "fpga_realtime"], }; pub const APP_ZEROS: FwId = FwId { diff --git a/drivers/Cargo.toml b/drivers/Cargo.toml index 04caa0a43f..e112f63655 100644 --- a/drivers/Cargo.toml +++ b/drivers/Cargo.toml @@ -37,7 +37,6 @@ verilator = ["caliptra-hw-model/verilator"] no-cfi = [] "hw-1.0" = ["caliptra-builder/hw-1.0", "caliptra-registers/hw-1.0"] fips-test-hooks = [] -fmc-alias-csr = [] [dev-dependencies] caliptra-api.workspace = true diff --git a/drivers/src/lib.rs b/drivers/src/lib.rs index 0e74ccbb1b..cd374b32e0 100644 --- a/drivers/src/lib.rs +++ b/drivers/src/lib.rs @@ -86,7 +86,6 @@ pub use okref::okmutref; pub use okref::okref; pub use pcr_bank::{PcrBank, PcrId}; pub use pcr_reset::PcrResetCounter; -#[cfg(feature = "fmc-alias-csr")] pub use persistent::fmc_alias_csr::FmcAliasCsr; #[cfg(feature = "runtime")] pub use persistent::AuthManifestImageMetadataList; diff --git a/drivers/src/persistent.rs b/drivers/src/persistent.rs index 7e66545363..b7336c7bc8 100644 --- a/drivers/src/persistent.rs +++ b/drivers/src/persistent.rs @@ -21,7 +21,6 @@ use crate::{ FirmwareHandoffTable, }; -#[cfg(feature = "fmc-alias-csr")] use crate::FmcAliasCsr; #[cfg(feature = "runtime")] @@ -74,7 +73,6 @@ pub struct IdevIdCsr { csr: [u8; MAX_CSR_SIZE], } -#[cfg(feature = "fmc-alias-csr")] pub mod fmc_alias_csr { use super::*; @@ -262,15 +260,10 @@ pub struct PersistentData { pub idevid_csr: IdevIdCsr, reserved10: [u8; IDEVID_CSR_SIZE as usize - size_of::()], - #[cfg(feature = "fmc-alias-csr")] pub fmc_alias_csr: FmcAliasCsr, - #[cfg(feature = "fmc-alias-csr")] reserved11: [u8; FMC_ALIAS_CSR_SIZE as usize - size_of::()], - #[cfg(not(feature = "fmc-alias-csr"))] - pub fmc_alias_csr: [u8; FMC_ALIAS_CSR_SIZE as usize], - // Reserved memory for future objects. // New objects should always source memory from this range. // Taking memory from this reserve does NOT break hitless updates. diff --git a/fmc/Cargo.toml b/fmc/Cargo.toml index eacf45d763..0e020784bc 100644 --- a/fmc/Cargo.toml +++ b/fmc/Cargo.toml @@ -42,4 +42,3 @@ itrng = ["caliptra-hw-model/itrng"] verilator = ["caliptra-hw-model/verilator"] fake-fmc = [] "hw-1.0" = ["caliptra-builder/hw-1.0", "caliptra-cpu/hw-1.0", "caliptra-drivers/hw-1.0", "caliptra-registers/hw-1.0"] -fmc-alias-csr = ["caliptra-drivers/fmc-alias-csr"] \ No newline at end of file diff --git a/fmc/build.sh b/fmc/build.sh index dcd7526e37..0feabf5fd8 100755 --- a/fmc/build.sh +++ b/fmc/build.sh @@ -9,5 +9,4 @@ cargo build \ --target riscv32imc-unknown-none-elf \ --profile=firmware \ --no-default-features \ - --features=fmc-alias-csr \ --bin=caliptra-fmc diff --git a/fmc/src/flow/crypto.rs b/fmc/src/flow/crypto.rs index e1e275305f..9251ec1b30 100644 --- a/fmc/src/flow/crypto.rs +++ b/fmc/src/flow/crypto.rs @@ -8,9 +8,7 @@ Abstract: use caliptra_x509::Ecdsa384Signature; use crate::fmc_env::FmcEnv; -#[cfg(feature = "fmc-alias-csr")] use caliptra_drivers::okmutref; -#[cfg(feature = "fmc-alias-csr")] use zeroize::Zeroize; use caliptra_cfi_derive::cfi_impl_fn; @@ -227,7 +225,6 @@ impl Crypto { /// /// * `Ecc384Signature` - Signature #[inline(always)] - #[cfg(feature = "fmc-alias-csr")] pub fn ecdsa384_sign_and_verify( env: &mut FmcEnv, priv_key: KeyId, diff --git a/fmc/src/flow/mod.rs b/fmc/src/flow/mod.rs index c532f5441c..1b11ef7c71 100644 --- a/fmc/src/flow/mod.rs +++ b/fmc/src/flow/mod.rs @@ -14,7 +14,6 @@ Abstract: mod crypto; pub mod dice; -#[cfg(feature = "fmc-alias-csr")] mod fmc_alias_csr; mod pcr; mod rt_alias; @@ -32,7 +31,6 @@ use caliptra_drivers::CaliptraResult; /// /// * `env` - FMC Environment pub fn run(env: &mut FmcEnv) -> CaliptraResult<()> { - #[cfg(feature = "fmc-alias-csr")] { use caliptra_cfi_lib::cfi_assert_eq; use caliptra_drivers::ResetReason; diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 8f521e7ede..bd8ec23e8c 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -11,7 +11,7 @@ caliptra-cfi-lib-git = { workspace = true, default-features = false, features = caliptra-cfi-derive-git.workspace = true caliptra_common = { workspace = true, default-features = false, features = ["runtime"] } caliptra-cpu.workspace = true -caliptra-drivers = { workspace = true, features = ["fmc-alias-csr", "runtime"] } +caliptra-drivers = { workspace = true, features = ["runtime"] } caliptra-error = { workspace = true, default-features = false } caliptra-image-types = { workspace = true, default-features = false } caliptra-auth-man-types = { workspace = true, default-features = false } @@ -65,4 +65,3 @@ no-cfi = ["caliptra-image-verify/no-cfi", "caliptra-drivers/no-cfi"] fpga_realtime = ["caliptra-drivers/fpga_realtime"] "hw-1.0" = ["caliptra-builder/hw-1.0", "caliptra-drivers/hw-1.0", "caliptra-registers/hw-1.0", "caliptra-kat/hw-1.0","caliptra-cpu/hw-1.0"] fips-test-hooks = ["caliptra-drivers/fips-test-hooks"] -fmc-alias-csr = ["caliptra-drivers/fmc-alias-csr"] \ No newline at end of file diff --git a/runtime/build.sh b/runtime/build.sh index 79dda8ca62..4d38168cfd 100755 --- a/runtime/build.sh +++ b/runtime/build.sh @@ -9,5 +9,4 @@ cargo build \ --target riscv32imc-unknown-none-elf \ --profile=firmware \ --no-default-features \ - --features=fmc-alias-csr \ --bin=caliptra-runtime diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index c996e3c4cb..a6af89223d 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -22,7 +22,6 @@ mod dpe_crypto; mod dpe_platform; mod drivers; pub mod fips; -#[cfg(feature = "fmc-alias-csr")] mod get_fmc_alias_csr; mod get_idev_csr; pub mod handoff; @@ -60,7 +59,6 @@ pub use fips::FipsShutdownCmd; pub use fips::{fips_self_test_cmd, fips_self_test_cmd::SelfTestStatus}; pub use populate_idev::PopulateIDevIdCertCmd; -#[cfg(feature = "fmc-alias-csr")] pub use get_fmc_alias_csr::GetFmcAliasCsrCmd; pub use get_idev_csr::GetIdevCsrCmd; pub use info::{FwInfoCmd, IDevIdInfoCmd}; @@ -229,7 +227,6 @@ fn handle_command(drivers: &mut Drivers) -> CaliptraResult { CommandId::SET_AUTH_MANIFEST => SetAuthManifestCmd::execute(drivers, cmd_bytes), CommandId::AUTHORIZE_AND_STASH => AuthorizeAndStashCmd::execute(drivers, cmd_bytes), CommandId::GET_IDEV_CSR => GetIdevCsrCmd::execute(drivers, cmd_bytes), - #[cfg(feature = "fmc-alias-csr")] CommandId::GET_FMC_ALIAS_CSR => GetFmcAliasCsrCmd::execute(drivers, cmd_bytes), _ => Err(CaliptraError::RUNTIME_UNIMPLEMENTED_COMMAND), }; From 7743a48f42b66d5ba3aaeece0d61e0372ac9c4f2 Mon Sep 17 00:00:00 2001 From: Anthony Rocha Date: Fri, 10 Jan 2025 14:40:52 -0800 Subject: [PATCH 4/4] NIT changes. --- .../test_get_fmc_alias_csr.rs | 37 +------------------ x509/src/fmc_alias_csr.rs | 4 +- 2 files changed, 3 insertions(+), 38 deletions(-) diff --git a/runtime/tests/runtime_integration_tests/test_get_fmc_alias_csr.rs b/runtime/tests/runtime_integration_tests/test_get_fmc_alias_csr.rs index 4fe241c79f..e411452b76 100644 --- a/runtime/tests/runtime_integration_tests/test_get_fmc_alias_csr.rs +++ b/runtime/tests/runtime_integration_tests/test_get_fmc_alias_csr.rs @@ -2,15 +2,9 @@ use crate::common::get_certs; use caliptra_api::mailbox::GetFmcAliasCsrReq; -use caliptra_api::SocManager; -use caliptra_builder::{get_ci_rom_version, CiRomVersion}; -use caliptra_common::mailbox_api::{CommandId, GetRtAliasCertReq, MailboxReqHeader}; +use caliptra_common::mailbox_api::GetRtAliasCertReq; use caliptra_drivers::{FmcAliasCsr, MAX_CSR_SIZE}; -use caliptra_error::CaliptraError; use caliptra_hw_model::DefaultHwModel; -use caliptra_hw_model::{HwModel, ModelError}; -use caliptra_runtime::RtBootStatus; -use zerocopy::IntoBytes; use crate::common::{run_rt_test, RuntimeTestArgs}; @@ -59,32 +53,3 @@ fn test_get_fmc_alias_csr() { verify_rt_cert(&mut model, pubkey); } - -#[test] -fn test_missing_csr() { - let mut model = run_rt_test(RuntimeTestArgs::default()); - - model.step_until(|m| { - m.soc_ifc().cptra_boot_status().read() == u32::from(RtBootStatus::RtReadyForCommands) - }); - - let payload = MailboxReqHeader { - chksum: caliptra_common::checksum::calc_checksum(u32::from(CommandId::GET_IDEV_CSR), &[]), - }; - - let response = model - .mailbox_execute(CommandId::GET_IDEV_CSR.into(), payload.as_bytes()) - .unwrap_err(); - - match get_ci_rom_version() { - // 1.0 and 1.1 ROM do not support this feature - CiRomVersion::Rom1_0 | CiRomVersion::Rom1_1 => assert_eq!( - response, - ModelError::MailboxCmdFailed(CaliptraError::RUNTIME_GET_IDEV_ID_UNSUPPORTED_ROM.into()) - ), - _ => assert_eq!( - response, - ModelError::MailboxCmdFailed(CaliptraError::RUNTIME_GET_IDEV_ID_UNPROVISIONED.into()) - ), - }; -} diff --git a/x509/src/fmc_alias_csr.rs b/x509/src/fmc_alias_csr.rs index 99f0bc3043..2835cb992e 100644 --- a/x509/src/fmc_alias_csr.rs +++ b/x509/src/fmc_alias_csr.rs @@ -4,11 +4,11 @@ Licensed under the Apache-2.0 license. File Name: - idevid_csr.rs + fmc_alis_csr.rs Abstract: - Initial Device ID Certificate Signing Request related code. + FMC Alias CSR Certificate Signing Request related code. --*/