Skip to content

Commit

Permalink
Self Signed FMC Alias Csr (#1863)
Browse files Browse the repository at this point in the history
* 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.

* Code review feedback.

* Remove fmc-alias-csr feature.

* NIT changes.

* Remove unused test_data

* Revert changes to strings.

* Fix RESERVED_MEMORY size.

* Remove dead code

(cherry picked from commit fa6b1a9)
  • Loading branch information
rusty1968 authored and mhatrevi committed Feb 18, 2025
1 parent 51e8b9a commit d6d1cdf
Show file tree
Hide file tree
Showing 33 changed files with 789 additions and 65 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 41 additions & 0 deletions api/src/mailbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ impl CommandId {
// The get IDevID ECC CSR command.
pub const GET_IDEV_ECC_CSR: Self = Self(0x4944_4352); // "IDCR"

// The get FMC Alias CSR command.
pub const GET_FMC_ALIAS_CSR: Self = Self(0x464D_4352); // "FMCR"

// Debug unlock commands
pub const MANUF_DEBUG_UNLOCK_REQ_TOKEN: Self = Self(0x4d445554); // "MDUT"
pub const PRODUCTION_AUTH_DEBUG_UNLOCK_REQ: Self = Self(0x50445552); // "PDUR"
Expand Down Expand Up @@ -161,6 +164,7 @@ pub enum MailboxResp {
CertifyKeyExtended(CertifyKeyExtendedResp),
AuthorizeAndStash(AuthorizeAndStashResp),
GetIdevCsr(GetIdevCsrResp),
GetFmcAliasCsr(GetFmcAliasCsrResp),
}

impl MailboxResp {
Expand All @@ -182,6 +186,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()),
}
}

Expand All @@ -203,6 +208,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()),
}
}

Expand Down Expand Up @@ -1018,6 +1024,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 {
Expand Down
2 changes: 2 additions & 0 deletions builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ pub fn build_firmware_elfs_uncached<'a>(
fwid,
fs::read(target_dir.join(TARGET).join(PROFILE).join(fwid.bin_name))?,
);
println!("Target: {:?}", target_dir.join(TARGET).join(PROFILE).join(fwid.bin_name));
}
}
Ok(fwids
Expand Down Expand Up @@ -314,6 +315,7 @@ pub fn build_firmware_elf(id: &FwId<'static>) -> io::Result<Arc<Vec<u8>>> {

if let Some(fw_dir) = std::env::var_os("CALIPTRA_PREBUILT_FW_DIR") {
let path = PathBuf::from(fw_dir).join(id.elf_filename());
println!("Reading prebuilt firmware from {}", path.display());
let result = std::fs::read(&path).map_err(|e| {
io::Error::new(
e.kind(),
Expand Down
2 changes: 1 addition & 1 deletion common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ 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 = 21 * 1024;
pub const FMC_SIZE: u32 = 23 * 1024;
pub const RUNTIME_ORG: u32 = FMC_ORG + FMC_SIZE;
pub const RUNTIME_SIZE: u32 = 128 * 1024;

Expand Down
2 changes: 0 additions & 2 deletions cpu/gen/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// Licensed under the Apache-2.0 license
use caliptra_common::memory_layout::*;
// [TODO][CAP2] Add MLDSA
pub fn gen_memory_x(iccm_org: u32, iccm_size: u32) -> String {
format!(
r#"
Expand All @@ -13,7 +12,6 @@ pub fn gen_memory_x(iccm_org: u32, iccm_size: u32) -> String {
CFI_STATE_ORG = 0x{CFI_STATE_ORG:08X};
ICCM_SIZE = 0x{iccm_size:08X};
DCCM_SIZE = 0x{DCCM_SIZE:08X};
DATA_SIZE = 0x{DATA_SIZE:08X};
Expand Down
2 changes: 2 additions & 0 deletions drivers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,10 @@ pub use okref::okmutref;
pub use okref::okref;
pub use pcr_bank::{PcrBank, PcrId};
pub use pcr_reset::PcrResetCounter;
pub use persistent::fmc_alias_csr::FmcAliasCsr;
#[cfg(feature = "runtime")]
pub use persistent::AuthManifestImageMetadataList;

pub use persistent::{
Ecc384IdevIdCsr, FuseLogArray, InitDevIdCsrEnvelope, Mldsa87IdevIdCsr, PcrLogArray,
PersistentData, PersistentDataAccessor, StashMeasurementArray, ECC384_MAX_CSR_SIZE,
Expand Down
2 changes: 1 addition & 1 deletion drivers/src/memory_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub const MBOX_SIZE: u32 = 256 * 1024;
pub const ICCM_SIZE: u32 = 256 * 1024;
pub const DCCM_SIZE: u32 = 256 * 1024;
pub const ROM_DATA_SIZE: u32 = 996;
pub const DATA_SIZE: u32 = 74 * 1024;
pub const DATA_SIZE: u32 = 73 * 1024;
pub const STACK_SIZE: u32 = 85 * 1024;
pub const ROM_STACK_SIZE: u32 = 61 * 1024;
pub const ESTACK_SIZE: u32 = 1024;
Expand Down
80 changes: 73 additions & 7 deletions drivers/src/persistent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

use core::{marker::PhantomData, mem::size_of, ptr::addr_of};

use crate::{
fuse_log::FuseLogEntry,
memory_layout,
pcr_log::{MeasurementLogEntry, PcrLogEntry},
DataVault, FirmwareHandoffTable, FmcAliasCsr, Mldsa87PubKey,
};
#[cfg(feature = "runtime")]
use caliptra_auth_man_types::{
AuthManifestImageMetadata, AuthManifestImageMetadataCollection,
Expand All @@ -14,13 +20,6 @@ use dpe::{DpeInstance, U8Bool, MAX_HANDLES};
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, TryFromBytes};
use zeroize::Zeroize;

use crate::{
fuse_log::FuseLogEntry,
memory_layout,
pcr_log::{MeasurementLogEntry, PcrLogEntry},
DataVault, FirmwareHandoffTable, Mldsa87PubKey,
};

#[cfg(feature = "runtime")]
use crate::pcr_reset::PcrResetCounter;

Expand All @@ -44,6 +43,7 @@ pub const PCR_RESET_COUNTER_SIZE: u32 = 1024;
pub const AUTH_MAN_IMAGE_METADATA_MAX_SIZE: u32 = 7 * 1024;
pub const IDEVID_CSR_ENVELOP_SIZE: u32 = 9 * 1024;
pub const MLDSA87_MAX_CSR_SIZE: usize = 7680;
pub const FMC_ALIAS_CSR_SIZE: u32 = 1024;
pub const PCR_LOG_MAX_COUNT: usize = 17;
pub const FUSE_LOG_MAX_COUNT: usize = 62;
pub const MEASUREMENT_MAX_COUNT: usize = 8;
Expand Down Expand Up @@ -144,6 +144,59 @@ macro_rules! impl_idevid_csr {
impl_idevid_csr!(Ecc384IdevIdCsr, ECC384_MAX_CSR_SIZE);
impl_idevid_csr!(Mldsa87IdevIdCsr, MLDSA87_MAX_CSR_SIZE);

pub mod fmc_alias_csr {
use super::*;
const _: () = assert!(size_of::<FmcAliasCsr>() < FMC_ALIAS_CSR_SIZE as usize);
#[derive(Clone, TryFromBytes, IntoBytes, Zeroize)]
#[repr(C)]
pub struct FmcAliasCsr {
csr_len: u32,
csr: [u8; ECC384_MAX_CSR_SIZE],
}
impl Default for FmcAliasCsr {
fn default() -> Self {
Self {
csr_len: Self::UNPROVISIONED_CSR,
csr: [0; ECC384_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<Self> {
if csr_len >= ECC384_MAX_CSR_SIZE {
return Err(CaliptraError::FMC_ALIAS_INVALID_CSR);
}
let mut _self = Self {
csr_len: csr_len as u32,
csr: [0; ECC384_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
}
}
}

pub type Hmac384Tag = [u8; SHA384_DIGEST_BYTE_SIZE];
pub type Hmac512Tag = [u8; SHA512_DIGEST_BYTE_SIZE];

Expand Down Expand Up @@ -250,6 +303,9 @@ pub struct PersistentData {

pub idevid_csr_envelop: InitDevIdCsrEnvelope,
reserved10: [u8; IDEVID_CSR_ENVELOP_SIZE as usize - size_of::<InitDevIdCsrEnvelope>()],

pub fmc_alias_csr: FmcAliasCsr,
reserved11: [u8; FMC_ALIAS_CSR_SIZE as usize - size_of::<FmcAliasCsr>()],
}

impl PersistentData {
Expand Down Expand Up @@ -364,6 +420,16 @@ impl PersistentData {
memory_layout::PERSISTENT_DATA_ORG + persistent_data_offset
);

persistent_data_offset += IDEVID_CSR_ENVELOP_SIZE;
assert_eq!(
addr_of!((*P).fmc_alias_csr) as u32,
memory_layout::PERSISTENT_DATA_ORG + persistent_data_offset
);

assert_eq!(
P.add(1) as u32,
memory_layout::PERSISTENT_DATA_ORG + size_of::<PersistentData>() as u32
);
assert_eq!(P.add(1) as u32, memory_layout::DATA_ORG);
}
}
Expand Down
16 changes: 16 additions & 0 deletions error/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,12 @@ impl CaliptraError {
pub const RUNTIME_KEY_LADDER_TARGET_SVN_TOO_LARGE: CaliptraError =
CaliptraError::new_const(0x000E0056);

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);
Expand All @@ -546,6 +552,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);

Expand Down
1 change: 1 addition & 0 deletions fmc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
52 changes: 52 additions & 0 deletions fmc/src/flow/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{self, Ecc384KeyPair, MlDsaKeyPair},
Expand All @@ -17,6 +22,21 @@ use caliptra_drivers::{
Mldsa87Seed,
};

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 {
Expand Down Expand Up @@ -134,6 +154,38 @@ impl Crypto {
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
/// * `pub_key` - Public key to verify with
/// * `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<Ecc384Signature> {
let mut digest = env.sha2_512_384.sha384_digest(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
}

/// Generate MLDSA Key Pair
///
/// # Arguments
Expand Down
Loading

0 comments on commit d6d1cdf

Please sign in to comment.