Skip to content

Commit

Permalink
runtime/mailbox: Add mailbox command to reconstruct IDevId cert
Browse files Browse the repository at this point in the history
Retrieve the IDevId cert signature from fuses and append it to the
mailbox input data.

Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
  • Loading branch information
ArthurHeymans authored and jhand2 committed Sep 1, 2023
1 parent 56afd73 commit f1aea6b
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 6 deletions.
29 changes: 29 additions & 0 deletions common/src/mailbox_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub struct CommandId(pub u32);
impl CommandId {
pub const FIRMWARE_LOAD: Self = Self(0x46574C44); // "FWLD"
pub const GET_IDEV_CSR: Self = Self(0x49444556); // "IDEV"
pub const GET_IDEV_CERT: Self = Self(0x49444543); // IDEC
pub const GET_IDEV_INFO: Self = Self(0x49444549); // IDEI
pub const GET_LDEV_CERT: Self = Self(0x4C444556); // "LDEV"
pub const ECDSA384_VERIFY: Self = Self(0x53494756); // "SIGV"
Expand Down Expand Up @@ -51,6 +52,7 @@ impl From<CommandId> for u32 {
#[allow(clippy::large_enum_variant)]
pub enum MailboxResp {
Header(MailboxRespHeader),
GetIdevCert(GetIdevCertResp),
GetIdevCsr(GetIdevCsrResp),
GetIdevInfo(GetIdevInfoResp),
GetLdevCert(GetLdevCertResp),
Expand All @@ -65,6 +67,7 @@ impl MailboxResp {
pub fn as_bytes(&self) -> &[u8] {
match self {
MailboxResp::Header(resp) => resp.as_bytes(),
MailboxResp::GetIdevCert(resp) => resp.as_bytes(),
MailboxResp::GetIdevCsr(resp) => resp.as_bytes(),
MailboxResp::GetIdevInfo(resp) => resp.as_bytes(),
MailboxResp::GetLdevCert(resp) => resp.as_bytes(),
Expand All @@ -79,6 +82,7 @@ impl MailboxResp {
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
match self {
MailboxResp::Header(resp) => resp.as_bytes_mut(),
MailboxResp::GetIdevCert(resp) => resp.as_bytes_mut(),
MailboxResp::GetIdevCsr(resp) => resp.as_bytes_mut(),
MailboxResp::GetIdevInfo(resp) => resp.as_bytes_mut(),
MailboxResp::GetLdevCert(resp) => resp.as_bytes_mut(),
Expand Down Expand Up @@ -156,6 +160,31 @@ impl GetIdevCsrResp {
pub const DATA_MAX_SIZE: usize = 1024;
}

// GET_IDEV_CERT
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, PartialEq, Eq)]
pub struct GetIdevCertReq {
pub hdr: MailboxReqHeader,
pub tbs_size: u32,
pub signature_r: [u8; 48],
pub signature_s: [u8; 48],
pub tbs: [u8; GetIdevCertReq::DATA_MAX_SIZE], // variable length
}
impl GetIdevCertReq {
pub const DATA_MAX_SIZE: usize = 916; // Req max size = Resp max size - MAX_ECDSA384_SIG_LEN
}

#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, PartialEq, Eq)]
pub struct GetIdevCertResp {
pub hdr: MailboxRespHeader,
pub cert_size: u32,
pub cert: [u8; GetIdevCertResp::DATA_MAX_SIZE], // variable length
}
impl GetIdevCertResp {
pub const DATA_MAX_SIZE: usize = 1024;
}

// GET_IDEV_INFO
// No command-specific input args
#[repr(C)]
Expand Down
1 change: 1 addition & 0 deletions error/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ impl CaliptraError {
pub const RUNTIME_DISABLE_ATTESTATION_FAILED: CaliptraError =
CaliptraError::new_const(0x000E0011);
pub const RUNTIME_HANDOFF_INVALID_PARM: CaliptraError = CaliptraError::new_const(0x000E0012);
pub const RUNTIME_GET_DEVID_CERT_FAILED: CaliptraError = CaliptraError::new_const(0x000E0013);

/// FMC Errors
pub const FMC_GLOBAL_NMI: CaliptraError = CaliptraError::new_const(0x000F0001);
Expand Down
47 changes: 45 additions & 2 deletions runtime/src/info.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
// Licensed under the Apache-2.0 license

use crate::{handoff::RtHandoff, Drivers};
use caliptra_common::mailbox_api::{FwInfoResp, MailboxResp, MailboxRespHeader, GetIdevInfoResp};
use caliptra_drivers::CaliptraResult;
use caliptra_common::mailbox_api::{
FwInfoResp, GetIdevCertReq, GetIdevCertResp, GetIdevInfoResp, MailboxResp, MailboxRespHeader,
};
use caliptra_drivers::{CaliptraError, CaliptraResult};
use caliptra_x509::{Ecdsa384CertBuilder, Ecdsa384Signature};
use zerocopy::FromBytes;

pub struct FwInfoCmd;
impl FwInfoCmd {
Expand Down Expand Up @@ -42,3 +46,42 @@ impl IDevIdInfoCmd {
}
}

pub struct IDevIdCertCmd;
impl IDevIdCertCmd {
pub(crate) fn execute(cmd_args: &[u8]) -> CaliptraResult<MailboxResp> {
if let Some(cmd) = GetIdevCertReq::read_from(cmd_args) {
// Validate tbs
let Ok(in_len) = usize::try_from(cmd.tbs_size) else {
return Err(CaliptraError::RUNTIME_MAILBOX_INVALID_PARAMS);
};
if in_len > cmd.tbs.len() {
return Err(CaliptraError::RUNTIME_MAILBOX_INVALID_PARAMS);
}

let sig = Ecdsa384Signature {
r: cmd.signature_r,
s: cmd.signature_s,
};

let Some(builder) = Ecdsa384CertBuilder::new(&cmd.tbs[..in_len], &sig) else {
return Err(CaliptraError::RUNTIME_GET_DEVID_CERT_FAILED);
};

let mut cert = [0; GetIdevCertResp::DATA_MAX_SIZE];
let Some(cert_size) = builder.build(&mut cert) else {
return Err(CaliptraError::RUNTIME_GET_DEVID_CERT_FAILED);
};
let Ok(cert_size) = u32::try_from(cert_size) else {
return Err(CaliptraError::RUNTIME_GET_DEVID_CERT_FAILED);
};

Ok(MailboxResp::GetIdevCert(GetIdevCertResp {
hdr: MailboxRespHeader::default(),
cert_size,
cert,
}))
} else {
Err(CaliptraError::RUNTIME_INSUFFICIENT_MEMORY)
}
}
}
3 changes: 2 additions & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub use disable::DisableAttestationCmd;
use dpe_crypto::DpeCrypto;
pub use dpe_platform::{DpePlatform, VENDOR_ID, VENDOR_SKU};
pub use fips::{FipsSelfTestCmd, FipsShutdownCmd, FipsVersionCmd};
pub use info::{FwInfoCmd, IDevIdInfoCmd};
pub use info::{FwInfoCmd, IDevIdCertCmd, IDevIdInfoCmd};
pub use invoke_dpe::InvokeDpeCmd;
pub use stash_measurement::StashMeasurementCmd;
pub use verify::EcdsaVerifyCmd;
Expand Down Expand Up @@ -229,6 +229,7 @@ fn handle_command(drivers: &mut Drivers) -> CaliptraResult<MboxStatusE> {
// Handle the request and generate the response
let mut resp = match CommandId::from(req_packet.cmd) {
CommandId::FIRMWARE_LOAD => Err(CaliptraError::RUNTIME_UNIMPLEMENTED_COMMAND),
CommandId::GET_IDEV_CERT => IDevIdCertCmd::execute(cmd_bytes),
CommandId::GET_IDEV_CSR => Err(CaliptraError::RUNTIME_UNIMPLEMENTED_COMMAND),
CommandId::GET_IDEV_INFO => IDevIdInfoCmd::execute(drivers),
CommandId::GET_LDEV_CERT => Err(CaliptraError::RUNTIME_UNIMPLEMENTED_COMMAND),
Expand Down
39 changes: 37 additions & 2 deletions runtime/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ pub mod common;

use caliptra_builder::{ImageOptions, APP_WITH_UART, FMC_WITH_UART};
use caliptra_common::mailbox_api::{
CommandId, EcdsaVerifyReq, FipsVersionResp, FwInfoResp, InvokeDpeReq, InvokeDpeResp,
MailboxReqHeader, MailboxRespHeader, StashMeasurementReq, StashMeasurementResp, GetIdevInfoResp
CommandId, EcdsaVerifyReq, FipsVersionResp, FwInfoResp, GetIdevCertReq, GetIdevCertResp,
GetIdevInfoResp, InvokeDpeReq, InvokeDpeResp, MailboxReqHeader, MailboxRespHeader,
StashMeasurementReq, StashMeasurementResp,
};
use caliptra_drivers::Ecc384PubKey;
use caliptra_hw_model::{DefaultHwModel, HwModel, ModelError, ShaAccMode};
Expand Down Expand Up @@ -720,3 +721,37 @@ fn test_idev_id_info() {
GetIdevInfoResp::read_from(resp.as_slice()).unwrap();
}

#[test]
fn test_idev_id_cert() {
let mut model = run_rt_test(None, None);

let fake_tbs = [0xef, 0xbe, 0xad, 0xde];

let mut tbs: [u8; GetIdevCertReq::DATA_MAX_SIZE] = [0; GetIdevCertReq::DATA_MAX_SIZE];
tbs[..fake_tbs.len()].copy_from_slice(&fake_tbs);
let cmd = GetIdevCertReq {
hdr: MailboxReqHeader { chksum: 0 },
tbs,
signature_r: [0; 48],
signature_s: [0; 48],
tbs_size: fake_tbs.len().try_into().unwrap(),
};

let checksum = caliptra_common::checksum::calc_checksum(
u32::from(CommandId::GET_IDEV_CERT),
&cmd.as_bytes()[4..],
);

let cmd = GetIdevCertReq {
hdr: MailboxReqHeader { chksum: checksum },
..cmd
};

let resp = model
.mailbox_execute(u32::from(CommandId::GET_IDEV_CERT), cmd.as_bytes())
.unwrap()
.expect("We expected a response");

let cert = GetIdevCertResp::read_from(resp.as_slice()).unwrap();
assert!(cmd.tbs_size < cert.cert_size);
}
2 changes: 1 addition & 1 deletion x509/src/cert_bldr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ impl Default for Ecdsa384Signature {

impl Ecdsa384Signature {
/// ECDSA Coordinate length
const ECDSA_COORD_LEN: usize = 48;
pub const ECDSA_COORD_LEN: usize = 48;

/// Get the length of DER encoded unsigned integer
#[inline(never)]
Expand Down

0 comments on commit f1aea6b

Please sign in to comment.