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 13, 2024
1 parent dd0f98b commit 859481e
Show file tree
Hide file tree
Showing 12 changed files with 203 additions and 74 deletions.
13 changes: 12 additions & 1 deletion api/src/mailbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1032,7 +1032,7 @@ pub struct GetFmcAliasCsrReq {

impl Request for GetFmcAliasCsrReq {
const ID: CommandId = CommandId::GET_FMC_ALIAS_CSR;
type Resp = GetIdevCsrResp;
type Resp = GetFmcAliasCsrResp;
}

#[repr(C)]
Expand All @@ -1042,6 +1042,17 @@ pub struct GetFmcAliasCsrResp {
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;
}
Expand Down
28 changes: 28 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 @@ -228,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 @@ -260,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
3 changes: 3 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 Down
53 changes: 5 additions & 48 deletions fmc/src/flow/fmc_alias_csr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use caliptra_common::crypto::Ecc384KeyPair;

use crate::flow::crypto::Ecdsa384SignatureAdapter;

use zerocopy::FromBytes;
use zeroize::Zeroize;

use caliptra_drivers::okmutref;
Expand All @@ -18,53 +17,11 @@ use caliptra_drivers::FmcAliasCsr;
use caliptra_x509::FmcAliasCsrTbs;
use caliptra_x509::FmcAliasCsrTbsParams;

use caliptra_common::memory_layout;
use caliptra_drivers::{CaliptraError, CaliptraResult};

use caliptra_x509::Ecdsa384CsrBuilder;

use core::marker::PhantomData;

#[inline(always)]
unsafe fn ref_mut_from_addr<'a, T: FromBytes>(addr: u32) -> &'a mut T {
// LTO should be able to optimize out the assertions to maintain panic_is_missing

// dereferencing zero is undefined behavior
assert!(addr != 0);
assert!(addr as usize % core::mem::align_of::<T>() == 0);
assert!(core::mem::size_of::<u32>() == core::mem::size_of::<*const T>());
&mut *(addr as *mut T)
}

struct FmcAliasCsrAccessor {
// This field is here to ensure that Self::new() is the only way
// to create this type.
_phantom: PhantomData<()>,
}
impl FmcAliasCsrAccessor {
/// # Safety
///
/// It is unsound for more than one of these objects to exist simultaneously.
/// DO NOT CALL FROM RANDOM APPLICATION CODE!
pub unsafe fn new() -> Self {
Self {
_phantom: Default::default(),
}
}

/// # Safety
///
/// During the lifetime of the returned reference, it is unsound to use any
/// unsafe mechanism to read or write to this memory.
#[inline(always)]
pub fn get_mut(&mut self) -> &mut FmcAliasCsr {
// WARNING: The returned lifetime elided from `self` is critical for
// safety. Do not change this API without review by a Rust expert.
unsafe { ref_mut_from_addr(memory_layout::FMC_ALIAS_CSR_ORG) }
}
}

/// Retrieve DICE Input from HandsOff
/// Retrieve DICE Output from HandOff
///
/// # Arguments
///
Expand All @@ -91,9 +48,9 @@ fn dice_output_from_hand_off(env: &mut FmcEnv) -> CaliptraResult<DiceOutput> {
Ok(output)
}

fn write_csr_to_peristent_storage(csr: &FmcAliasCsr) -> CaliptraResult<()> {
let mut accessor = unsafe { FmcAliasCsrAccessor::new() };
let csr_persistent_mem = accessor.get_mut();
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(())
Expand Down Expand Up @@ -158,7 +115,7 @@ 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(&fmc_alias_csr);
let result = write_csr_to_peristent_storage(env, &fmc_alias_csr);

csr_buf.zeroize();

Expand Down
10 changes: 8 additions & 2 deletions fmc/src/flow/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ mod rt_alias;
mod tci;
mod x509;

use caliptra_drivers::ResetReason;

use crate::flow::rt_alias::RtAliasLayer;

use crate::fmc_env::FmcEnv;
Expand All @@ -31,8 +33,12 @@ use caliptra_drivers::CaliptraResult;
///
/// * `env` - FMC Environment
pub fn run(env: &mut FmcEnv) -> CaliptraResult<()> {
// Generate the Initial DevID Certificate Signing Request (CSR)
fmc_alias_csr::generate_csr(env)?;
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)
}
51 changes: 51 additions & 0 deletions runtime/src/get_fmc_alias_csr.rs
Original file line number Diff line number Diff line change
@@ -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::{AsBytes, FromBytes};

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<MailboxResp> {
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),
}
}
}
3 changes: 3 additions & 0 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -225,6 +227,7 @@ fn handle_command(drivers: &mut Drivers) -> CaliptraResult<MboxStatusE> {
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),
}?;

Expand Down
15 changes: 15 additions & 0 deletions runtime/tests/runtime_integration_tests/common.rs
Original file line number Diff line number Diff line change
@@ -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},
Expand Down Expand Up @@ -268,6 +269,20 @@ pub fn assert_error(
}
}

pub fn get_certs<R: Request>(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::<<R as Request>::Resp>());
let mut resp = R::Resp::new_zeroed();
resp.as_bytes_mut()[..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(
Expand Down
2 changes: 1 addition & 1 deletion runtime/tests/runtime_integration_tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -22,4 +23,3 @@ mod test_stash_measurement;
mod test_tagging;
mod test_update_reset;
mod test_warm_reset;
mod test_get_fmc_alias_csr;
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
Certificate Request:
Data:
Version: 1 (0x0)
Subject: CN=Caliptra 1.0 FMC Alias/serialNumber=65F6BB3FAE445D0D0DB36F3DC84999B60B059CF63D3E25FE00C47B239857F3BB
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (384 bit)
pub:
04:cb:0e:91:9a:d7:5f:9e:02:f2:39:8a:28:a9:3f:
6d:f3:01:36:37:c8:5c:d3:26:26:77:71:88:93:5c:
6c:e8:3a:c5:c4:bb:df:05:db:15:c1:38:97:f0:f5:
ca:e3:44:76:b4:e8:c5:b8:28:b9:82:8d:11:db:ca:
79:92:4f:8c:1b:09:37:cb:d2:f5:3c:47:b9:dd:26:
78:5b:d5:d8:11:96:52:6f:b7:d7:31:8f:9a:9f:e1:
cf:9d:95:b0:64:d5:39
ASN1 OID: secp384r1
NIST CURVE: P-384
Attributes:
Requested Extensions:
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:5
X509v3 Key Usage: critical
Certificate Sign
2.23.133.5.4.4:
0....................
Signature Algorithm: ecdsa-with-SHA384
Signature Value:
30:65:02:31:00:cf:f3:d2:d8:30:86:5a:f7:f9:d4:3d:63:d3:
eb:c2:1e:16:f5:d1:3b:1e:98:38:ca:3d:8f:da:ed:9d:44:8f:
d5:f6:41:35:73:8a:14:05:91:63:17:58:94:4f:56:df:ea:02:
30:4f:db:4a:2e:26:f2:aa:ec:74:41:e4:7e:c2:6a:c5:07:e9:
b3:50:52:bb:5c:68:4b:83:ea:07:33:09:84:0b:a1:b9:8a:9f:
d8:57:73:b0:3b:76:62:f3:4e:7f:32:9f:4f
Loading

0 comments on commit 859481e

Please sign in to comment.