Skip to content

Commit

Permalink
Self Signed FMC Alias Csr
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
rusty1968 committed Dec 19, 2024
1 parent 2f8f19b commit d933c2d
Show file tree
Hide file tree
Showing 32 changed files with 845 additions and 66 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 @@ -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<u32> for CommandId {
Expand Down Expand Up @@ -155,6 +158,7 @@ pub enum MailboxResp {
CertifyKeyExtended(CertifyKeyExtendedResp),
AuthorizeAndStash(AuthorizeAndStashResp),
GetIdevCsr(GetIdevCsrResp),
GetFmcAliasCsr(GetFmcAliasCsrResp),
}

impl MailboxResp {
Expand All @@ -176,6 +180,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 @@ -197,6 +202,7 @@ impl MailboxResp {
MailboxResp::CertifyKeyExtended(resp) => Ok(resp.as_bytes_mut()),
MailboxResp::AuthorizeAndStash(resp) => Ok(resp.as_bytes_mut()),
MailboxResp::GetIdevCsr(resp) => Ok(resp.as_bytes_mut()),
MailboxResp::GetFmcAliasCsr(resp) => Ok(resp.as_bytes_mut()),
}
}

Expand Down Expand Up @@ -1017,6 +1023,41 @@ impl Default for GetIdevCsrResp {
}
}

// GET_IDEVID_CSR
#[repr(C)]
#[derive(Default, Debug, AsBytes, FromBytes, 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, AsBytes, FromBytes, 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
4 changes: 2 additions & 2 deletions common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, FHT_ORG, FHT_SIZE, MAN1_ORG};
pub use wdt::{restart_wdt, start_wdt, stop_wdt, WdtTimeout};
1 change: 1 addition & 0 deletions drivers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions drivers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
14 changes: 11 additions & 3 deletions drivers/src/memory_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ pub const DPE_ORG: u32 = 0x50005400;
pub const PCR_RESET_COUNTER_ORG: u32 = 0x50006800;
pub const AUTH_MAN_IMAGE_METADATA_LIST_ORG: u32 = 0x50006C00;
pub const IDEVID_CSR_ORG: u32 = 0x50008800;
pub const DATA_ORG: u32 = 0x50008C00;
pub const FMC_ALIAS_CSR_ORG: u32 = 0x50008C00;
pub const DATA_ORG: u32 = 0x50009000;

pub const STACK_ORG: u32 = 0x5000f800;
pub const ROM_STACK_ORG: u32 = 0x5001C000;
Expand Down Expand Up @@ -74,7 +75,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 DATA_SIZE: u32 = 27 * 1024;
pub const FMC_ALIAS_CSR_SIZE: u32 = 1024;
pub const DATA_SIZE: u32 = 26 * 1024;
pub const STACK_SIZE: u32 = 64 * 1024;
pub const ROM_STACK_SIZE: u32 = 14 * 1024;
pub const ESTACK_SIZE: u32 = 1024;
Expand Down Expand Up @@ -158,7 +160,13 @@ fn mem_layout_test_pcr_reset_counter() {
#[test]
#[allow(clippy::assertions_on_constants)]
fn mem_layout_test_idevid_csr() {
assert_eq!((DATA_ORG - IDEVID_CSR_ORG), IDEVID_CSR_SIZE);
assert_eq!((DATA_ORG - FMC_ALIAS_CSR_ORG), FMC_ALIAS_CSR_SIZE);
}

#[test]
#[allow(clippy::assertions_on_constants)]
fn mem_layout_test_fmc_alias_csr() {
assert_eq!((FMC_ALIAS_CSR_ORG - IDEVID_CSR_ORG), IDEVID_CSR_SIZE);
}

#[test]
Expand Down
92 changes: 92 additions & 0 deletions drivers/src/persistent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ use crate::{
FirmwareHandoffTable,
};

#[cfg(feature = "fmc")]
use crate::FmcAliasCsr;

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

Expand Down Expand Up @@ -52,6 +55,70 @@ pub struct IdevIdCsr {
csr: [u8; MAX_CSR_SIZE],
}

#[cfg(feature = "fmc")]
pub mod fmc_alias_csr {
use super::*;

const _: () = assert!(size_of::<FmcAliasCsr>() < memory_layout::FMC_ALIAS_CSR_SIZE as usize);

#[derive(Clone, FromBytes, AsBytes, 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<Self> {
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 {
Expand Down Expand Up @@ -164,6 +231,12 @@ pub struct PersistentData {

pub idevid_csr: IdevIdCsr,
reserved10: [u8; memory_layout::IDEVID_CSR_SIZE as usize - size_of::<IdevIdCsr>()],

#[cfg(feature = "fmc")]
pub fmc_alias_csr: FmcAliasCsr,

#[cfg(feature = "fmc")]
reserved11: [u8; memory_layout::FMC_ALIAS_CSR_SIZE as usize - size_of::<FmcAliasCsr>()],
}

impl PersistentData {
Expand Down Expand Up @@ -196,10 +269,29 @@ impl PersistentData {
addr_of!((*P).idevid_csr) as u32,
memory_layout::IDEVID_CSR_ORG
);

assert_eq!(
addr_of!((*P).idevid_csr) as u32,
memory_layout::IDEVID_CSR_ORG
);

#[cfg(not(feature = "fmc"))]
assert_eq!(
P.add(1) as u32,
memory_layout::IDEVID_CSR_ORG + memory_layout::IDEVID_CSR_SIZE
);

#[cfg(feature = "fmc")]
assert_eq!(
addr_of!((*P).fmc_alias_csr) as u32,
memory_layout::FMC_ALIAS_CSR_ORG
);

#[cfg(feature = "fmc")]
assert_eq!(
P.add(1) as u32,
memory_layout::FMC_ALIAS_CSR_ORG + memory_layout::FMC_ALIAS_CSR_SIZE
);
}
}
}
Expand Down
13 changes: 13 additions & 0 deletions error/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,9 @@ impl CaliptraError {
pub const RUNTIME_GET_IDEV_ID_UNSUPPORTED_ROM: CaliptraError =
CaliptraError::new_const(0x000E0052);

pub const RUNTIME_GET_FMC_CSR_UNPROVISIONED: CaliptraError =
CaliptraError::new_const(0x000E0053);

/// FMC Errors
pub const FMC_GLOBAL_NMI: CaliptraError = CaliptraError::new_const(0x000F0001);
pub const FMC_GLOBAL_EXCEPTION: CaliptraError = CaliptraError::new_const(0x000F0002);
Expand All @@ -464,6 +467,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
2 changes: 2 additions & 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 All @@ -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"]
1 change: 1 addition & 0 deletions fmc/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ cargo build \
--target riscv32imc-unknown-none-elf \
--profile=firmware \
--no-default-features \
--features=fmc_alias_csr \
--bin=caliptra-fmc
51 changes: 51 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::Ecc384KeyPair, keyids::KEY_ID_TMP};
use caliptra_drivers::{
Expand All @@ -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 {
Expand Down Expand Up @@ -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<Ecc384Signature> {
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
}
}
Loading

0 comments on commit d933c2d

Please sign in to comment.