Skip to content

Commit

Permalink
Add command to retrieve IDevID CSR from persistent storage.
Browse files Browse the repository at this point in the history
* This resolves
  #1687, for ROM.
  • Loading branch information
clundin25 committed Oct 23, 2024
1 parent f102017 commit c32cc0f
Show file tree
Hide file tree
Showing 12 changed files with 249 additions and 41 deletions.
41 changes: 41 additions & 0 deletions api/src/mailbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ impl CommandId {

// The authorize and stash command.
pub const AUTHORIZE_AND_STASH: Self = Self(0x4154_5348); // "ATSH"

// The get IDevID CSR command.
pub const GET_IDV_CSR: Self = Self(0x4944_4352); // "IDCR"
}

impl From<u32> for CommandId {
Expand Down Expand Up @@ -151,6 +154,7 @@ pub enum MailboxResp {
QuotePcrs(QuotePcrsResp),
CertifyKeyExtended(CertifyKeyExtendedResp),
AuthorizeAndStash(AuthorizeAndStashResp),
GetIDevIDCSR(GetIDevIDCSRResp),
}

impl MailboxResp {
Expand All @@ -171,6 +175,7 @@ impl MailboxResp {
MailboxResp::QuotePcrs(resp) => Ok(resp.as_bytes()),
MailboxResp::CertifyKeyExtended(resp) => Ok(resp.as_bytes()),
MailboxResp::AuthorizeAndStash(resp) => Ok(resp.as_bytes()),
MailboxResp::GetIDevIDCSR(resp) => Ok(resp.as_bytes()),
}
}

Expand All @@ -191,6 +196,7 @@ impl MailboxResp {
MailboxResp::QuotePcrs(resp) => Ok(resp.as_bytes_mut()),
MailboxResp::CertifyKeyExtended(resp) => Ok(resp.as_bytes_mut()),
MailboxResp::AuthorizeAndStash(resp) => Ok(resp.as_bytes_mut()),
MailboxResp::GetIDevIDCSR(resp) => Ok(resp.as_bytes_mut()),
}
}

Expand Down Expand Up @@ -458,6 +464,7 @@ pub struct GetIdevInfoResp {
pub struct GetLdevCertReq {
header: MailboxReqHeader,
}

impl Request for GetLdevCertReq {
const ID: CommandId = CommandId::GET_LDEV_CERT;
type Resp = GetLdevCertResp;
Expand Down Expand Up @@ -976,6 +983,40 @@ impl Default for SetAuthManifestReq {
}
}

// GET_IDEVID_CSR
#[repr(C)]
#[derive(Default, Debug, AsBytes, FromBytes, PartialEq, Eq)]
pub struct GetIDevIDCSRReq {
pub hdr: MailboxReqHeader,
}

impl Request for GetIDevIDCSRReq {
const ID: CommandId = CommandId::GET_IDV_CSR;
type Resp = GetIDevIDCSRResp;
}

#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, PartialEq, Eq)]
pub struct GetIDevIDCSRResp {
pub hdr: MailboxRespHeader,
pub data_size: u32,
pub data: [u8; Self::DATA_MAX_SIZE],
}
impl GetIDevIDCSRResp {
pub const DATA_MAX_SIZE: usize = 512;
}
impl ResponseVarSize for GetIDevIDCSRResp {}

impl Default for GetIDevIDCSRResp {
fn default() -> Self {
Self {
hdr: MailboxRespHeader::default(),
data_size: 0,
data: [0u8; Self::DATA_MAX_SIZE],
}
}
}

#[repr(u32)]
#[derive(Debug, PartialEq, Eq)]
pub enum ImageHashSource {
Expand Down
32 changes: 32 additions & 0 deletions drivers/src/idevid_csr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use core::mem::size_of;
use zerocopy::{AsBytes, FromBytes};
use zeroize::Zeroize;

use crate::memory_layout;

pub const MAX_CSR_SIZE: usize = 512;

#[derive(FromBytes, AsBytes, Zeroize)]
#[repr(C)]
pub struct IDevIDCsr {
pub csr: [u8; MAX_CSR_SIZE],
pub csr_len: u32,
}

impl Default for IDevIDCsr {
fn default() -> Self {
Self {
csr: [0; MAX_CSR_SIZE],
csr_len: 0,
}
}
}

impl IDevIDCsr {
/// Get the CSR buffer
pub fn get(&self) -> Option<&[u8]> {
self.csr.get(..self.csr_len as usize)
}
}

const _: () = assert!(size_of::<IDevIDCsr>() < memory_layout::IDEVID_CSR_SIZE as usize);
2 changes: 2 additions & 0 deletions drivers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub mod fuse_log;
pub mod hand_off;
mod hmac384;
mod hmac384_kdf;
mod idevid_csr;
mod key_vault;
mod kv_access;
mod lms;
Expand Down Expand Up @@ -75,6 +76,7 @@ pub use fuse_bank::{
pub use hand_off::FirmwareHandoffTable;
pub use hmac384::{Hmac384, Hmac384Data, Hmac384Key, Hmac384Op, Hmac384Tag};
pub use hmac384_kdf::hmac384_kdf;
pub use idevid_csr::{IDevIDCsr, MAX_CSR_SIZE};
pub use key_vault::{KeyId, KeyUsage, KeyVault};
pub use kv_access::{KeyReadArgs, KeyWriteArgs};
pub use lms::{
Expand Down
12 changes: 10 additions & 2 deletions drivers/src/memory_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ pub const FUSE_LOG_ORG: u32 = 0x50005000;
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 DATA_ORG: u32 = 0x50007000;
pub const IDEVID_CSR_ORG: u32 = 0x50007000;
pub const DATA_ORG: u32 = 0x50007400;

pub const STACK_ORG: u32 = 0x5001A000;
pub const ROM_STACK_ORG: u32 = 0x5001C000;
Expand Down Expand Up @@ -72,7 +73,8 @@ pub const FUSE_LOG_SIZE: u32 = 1024;
pub const DPE_SIZE: u32 = 5 * 1024;
pub const PCR_RESET_COUNTER_SIZE: u32 = 1024;
pub const AUTH_MAN_IMAGE_METADATA_LIST_MAX_SIZE: u32 = 1024;
pub const DATA_SIZE: u32 = 76 * 1024;
pub const IDEVID_CSR_SIZE: u32 = 1024;
pub const DATA_SIZE: u32 = 75 * 1024;
pub const STACK_SIZE: u32 = 22 * 1024;
pub const ROM_STACK_SIZE: u32 = 14 * 1024;
pub const ESTACK_SIZE: u32 = 1024;
Expand Down Expand Up @@ -153,6 +155,12 @@ 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);
}

#[test]
#[allow(clippy::assertions_on_constants)]
fn mem_layout_test_data() {
Expand Down
12 changes: 10 additions & 2 deletions drivers/src/persistent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use dpe::{DpeInstance, U8Bool, MAX_HANDLES};
use zerocopy::{AsBytes, FromBytes};
use zeroize::Zeroize;

use crate::IDevIDCsr;
use crate::{
fuse_log::FuseLogEntry,
memory_layout,
Expand Down Expand Up @@ -101,7 +102,11 @@ pub struct PersistentData {
#[cfg(not(feature = "runtime"))]
pub auth_manifest_image_metadata_col:
[u8; memory_layout::AUTH_MAN_IMAGE_METADATA_LIST_MAX_SIZE as usize],

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

impl PersistentData {
pub fn assert_matches_layout() {
const P: *const PersistentData = memory_layout::MAN1_ORG as *const PersistentData;
Expand All @@ -128,10 +133,13 @@ impl PersistentData {
addr_of!((*P).auth_manifest_image_metadata_col) as u32,
memory_layout::AUTH_MAN_IMAGE_METADATA_LIST_ORG
);
assert_eq!(
addr_of!((*P).idevid_csr) as u32,
memory_layout::IDEVID_CSR_ORG
);
assert_eq!(
P.add(1) as u32,
memory_layout::AUTH_MAN_IMAGE_METADATA_LIST_ORG
+ memory_layout::AUTH_MAN_IMAGE_METADATA_LIST_MAX_SIZE
memory_layout::IDEVID_CSR_ORG + memory_layout::IDEVID_CSR_SIZE
);
}
}
Expand Down
1 change: 1 addition & 0 deletions rom/dev/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ ROM supports the following set of commands before handling the FW_DOWNLOAD comma
4. **SELF_TEST_GET_RESULTS**: This command is used to check if a SELF_TEST command is in progress. [Self Test Get Results command](https://github.com/chipsalliance/caliptra-sw/blob/main/runtime/README.md#self_test_get_results).
5. **SHUTDOWN**: This command is used clear the hardware crypto blocks including the keyvault. [Shutdown command](https://github.com/chipsalliance/caliptra-sw/blob/main/runtime/README.md#shutdown).
6. **CAPABILITIES**: This command is used to query the ROM capabilities. Capabilities is a 128-bit value with individual bits indicating a specific capability. Currently, the only capability supported is ROM_BASE (bit 0). [Capabilities command](https://github.com/chipsalliance/caliptra-sw/blob/main/runtime/README.md#capabilities).
7. **GET_IDEVID_CSR**: This command is used to fetch the IDevID CSR from ROM. [Fetch IDevIDCSR command](https://github.com/chipsalliance/caliptra-sw/blob/main/runtime/README.md#get_idevid_csr).

### Downloading images from mailbox

Expand Down
18 changes: 17 additions & 1 deletion rom/dev/src/flow/cold_reset/fw_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use caliptra_cfi_lib::CfiCounter;
use caliptra_common::capabilities::Capabilities;
use caliptra_common::fips::FipsVersionCmd;
use caliptra_common::mailbox_api::{
CapabilitiesResp, CommandId, MailboxReqHeader, MailboxRespHeader, Response,
CapabilitiesResp, CommandId, GetIDevIDCSRResp, MailboxReqHeader, MailboxRespHeader, Response,
StashMeasurementReq, StashMeasurementResp,
};
use caliptra_common::pcr::PCR_ID_STASH_MEASUREMENT;
Expand Down Expand Up @@ -306,6 +306,22 @@ impl FirmwareProcessor {
resp.populate_chksum();
txn.send_response(resp.as_bytes())?;
}
CommandId::GET_IDV_CSR => {
let mut request = MailboxReqHeader::default();
Self::copy_req_verify_chksum(&mut txn, request.as_bytes_mut())?;

let csr_persistent_mem = &persistent_data.idevid_csr;
let mut resp = GetIDevIDCSRResp::default();

let csr = csr_persistent_mem
.get()
.ok_or(CaliptraError::ROM_IDEVID_INVALID_CSR)?;
resp.data_size = csr_persistent_mem.csr_len as u32;
resp.data[..resp.data_size as usize].copy_from_slice(&csr);

resp.populate_chksum();
txn.send_response(resp.as_bytes())?;
}
_ => {
cprintln!("[fwproc] Invalid command received");
// Don't complete the transaction here; let the fatal
Expand Down
48 changes: 35 additions & 13 deletions rom/dev/src/flow/cold_reset/idev_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,9 @@ use caliptra_drivers::*;
use caliptra_x509::*;
use zeroize::Zeroize;

type InitDevIdCsr<'a> = Certificate<'a, { MAX_CSR_SIZE }>;

/// Initialization Vector used by Deobfuscation Engine during UDS / field entropy decryption.
const DOE_IV: Array4x4 = Array4xN::<4, 16>([0xfb10365b, 0xa1179741, 0xfba193a1, 0x0f406d7e]);

/// Maximum Certificate Signing Request Size
const MAX_CSR_SIZE: usize = 512;

/// Dice Initial Device Identity (IDEVID) Layer
pub enum InitDevIdLayer {}

Expand Down Expand Up @@ -264,42 +259,58 @@ impl InitDevIdLayer {
cprintln!("[idev] SIG.S = {}", HexBytes(&_sig_s));

// Build the CSR with `To Be Signed` & `Signature`
let mut csr = [0u8; MAX_CSR_SIZE];
let mut dev_id_csr = IDevIDCsr::default();
let result = Ecdsa384CsrBuilder::new(tbs.tbs(), &sig.to_ecdsa())
.ok_or(CaliptraError::ROM_IDEVID_CSR_BUILDER_INIT_FAILURE);
sig.zeroize();

let csr_bldr = result?;
let csr_len = csr_bldr
.build(&mut csr)
.build(&mut dev_id_csr.csr)
.ok_or(CaliptraError::ROM_IDEVID_CSR_BUILDER_BUILD_FAILURE)?;

if csr_len > csr.len() {
if csr_len > dev_id_csr.csr.len() {
return Err(CaliptraError::ROM_IDEVID_CSR_OVERFLOW);
}

cprintln!("[idev] CSR = {}", HexBytes(&csr[..csr_len]));
dev_id_csr.csr_len = csr_len as u32;

cprintln!("[idev] CSR = {}", HexBytes(&dev_id_csr.csr[..csr_len]));
report_boot_status(IDevIdMakeCsrComplete.into());

// Execute Send CSR Flow
let result = Self::send_csr(env, InitDevIdCsr::new(&csr, csr_len));
csr.zeroize();
let mut result = Self::send_csr(env, &dev_id_csr);
if result.is_ok() {
result = Self::write_csr_to_peristent_storage(env, &dev_id_csr);
}
dev_id_csr.zeroize();

result
}

fn write_csr_to_peristent_storage(env: &mut RomEnv, csr: &IDevIDCsr) -> CaliptraResult<()> {
let mut csr_persistent_mem = &mut env.persistent_data.get_mut().idevid_csr;
csr_persistent_mem.zeroize();

let csr_buf = csr.get().ok_or(CaliptraError::ROM_IDEVID_INVALID_CSR)?;

csr_persistent_mem.csr[..csr.csr_len as usize].copy_from_slice(csr_buf);
csr_persistent_mem.csr_len = csr.csr_len;
Ok(())
}

/// Send Initial Device ID CSR to SOC
///
/// # Argument
///
/// * `env` - ROM Environment
/// * `csr` - Certificate Signing Request to send to SOC
fn send_csr(env: &mut RomEnv, csr: InitDevIdCsr) -> CaliptraResult<()> {
fn send_csr(env: &mut RomEnv, csr: &IDevIDCsr) -> CaliptraResult<()> {
loop {
// Create Mailbox send transaction to send the CSR
if let Some(mut txn) = env.mbox.try_start_send_txn() {
// Copy the CSR to mailbox
txn.send_request(0, csr.get().ok_or(CaliptraError::ROM_IDEVID_INVALID_CSR)?)?;
txn.send_request(0, &csr.get().ok_or(CaliptraError::ROM_IDEVID_INVALID_CSR)?)?;

// Signal the JTAG/SOC that Initial Device ID CSR is ready
env.soc_ifc.flow_status_set_idevid_csr_ready();
Expand All @@ -319,3 +330,14 @@ impl InitDevIdLayer {
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use caliptra_drivers::memory_layout::IDEVID_CSR_SIZE;

#[test]
fn verify_csr_fits_in_dccm() {
assert!(MAX_CSR_SIZE <= IDEVID_CSR_SIZE as usize);
}
}
23 changes: 0 additions & 23 deletions rom/dev/src/flow/cold_reset/x509.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,6 @@ use crate::cprintln;
use crate::rom_env::RomEnv;
use caliptra_drivers::*;

/// Wrapper to hold certificate buffer and length
pub struct Certificate<'a, const LEN: usize> {
buf: &'a [u8; LEN],
len: usize,
}

impl<'a, const LEN: usize> Certificate<'a, LEN> {
/// Create an instance of `Certificate`
///
/// # Arguments
///
/// * `buf` - Buffer
/// * `len` - Buffer length
pub fn new(buf: &'a [u8; LEN], len: usize) -> Self {
Self { buf, len }
}

/// Get the buffer
pub fn get(&self) -> Option<&[u8]> {
self.buf.get(..self.len)
}
}

/// X509 API
pub enum X509 {}

Expand Down
1 change: 1 addition & 0 deletions rom/dev/tests/rom_integration_tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ mod test_update_reset;
mod test_version;
mod test_warm_reset;
mod test_wdt_activation_and_stoppage;
mod tests_get_idev_csr;
Loading

0 comments on commit c32cc0f

Please sign in to comment.