Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Self Signed FMC Alias Csr #1863

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -153,6 +156,7 @@ pub enum MailboxResp {
CertifyKeyExtended(CertifyKeyExtendedResp),
AuthorizeAndStash(AuthorizeAndStashResp),
GetIdevCsr(GetIdevCsrResp),
GetFmcAliasCsr(GetFmcAliasCsrResp),
}

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

Expand All @@ -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()),
}
}

Expand Down Expand Up @@ -1010,6 +1016,41 @@ impl Default for GetIdevCsrResp {
}
}

// GET_IDEVID_CSR
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Minor copy paste error

#[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
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;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the size-history CI job, we're still only using ~18KiB in FMC. Do we need to change the size here?

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;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: now that #1722 is merged, should be able to just add to the PersistentData driver and leave memory layout as-is

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, 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<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,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this also need to be accessible in RT?


#[cfg(feature = "fmc")]
reserved11: [u8; memory_layout::FMC_ALIAS_CSR_SIZE as usize - size_of::<FmcAliasCsr>()],
Comment on lines +238 to +239
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the fmc is not enabled, a slice of memory_layout::FMC_ALIAS_CSR_SIZE should still be reserved so PersistentData is the same size / shape between image types.

}

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 @@ -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(0x000E0053);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0x000E0053 => 0x000E0054 so RUNTIME_GET_FMC_CSR_UNPROVISIONED has a unique error code.


/// FMC Errors
pub const FMC_GLOBAL_NMI: CaliptraError = CaliptraError::new_const(0x000F0001);
pub const FMC_GLOBAL_EXCEPTION: CaliptraError = CaliptraError::new_const(0x000F0002);
Expand All @@ -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);

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like pub_key is missing from the doc comment.

/// * `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
Loading