Skip to content

Commit 9418cf0

Browse files
committed
[dpe] Make SVN in DeriveContext optional
DPE added an SVN field to `DeriveContext`. To avoid making a breaking change to Caliptra integrators, this will append a default SVN value (`0`) to the command if it is not present. This also adds a test to make sure it is handled correctly.
1 parent 059fce9 commit 9418cf0

2 files changed

Lines changed: 91 additions & 6 deletions

File tree

runtime/src/invoke_dpe.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,17 @@ use caliptra_cfi_derive::cfi_impl_fn;
2020
use caliptra_common::mailbox_api::{InvokeDpeReq, MailboxRespHeader, MailboxRespHeaderVarSize};
2121
use caliptra_drivers::{CaliptraError, CaliptraResult};
2222
use dpe::{
23-
commands::{CertifyKeyCommand, Command, CommandExecution, InitCtxCmd},
23+
commands::{
24+
CertifyKeyCommand, Command, CommandExecution, CommandHdr, DeriveContextCmd, InitCtxCmd,
25+
},
2426
context::ContextState,
2527
error::DpeErrorCode,
2628
response::ResponseHdr,
2729
DpeInstance, DpeProfile, State, U8Bool, MAX_HANDLES,
2830
};
2931
use platform::MAX_OTHER_NAME_SIZE;
3032
use ufmt::derive::uDebug;
31-
use zerocopy::{FromZeros, IntoBytes};
33+
use zerocopy::{FromBytes, FromZeros, IntoBytes};
3234

3335
#[derive(uDebug, Debug, Copy, Clone, PartialEq, Eq)]
3436
pub enum CaliptraDpeProfile {
@@ -43,6 +45,11 @@ impl From<CaliptraDpeProfile> for DpeProfile {
4345
}
4446
}
4547

48+
const _: () = assert!(
49+
core::mem::size_of::<DeriveContextCmd>() == 80,
50+
"DeriveContextCmd size changed, check if SVN compatibility logic needs updating"
51+
);
52+
4653
pub struct InvokeDpeCmd;
4754
impl InvokeDpeCmd {
4855
#[cfg_attr(feature = "cfi", cfi_impl_fn)]
@@ -57,6 +64,25 @@ impl InvokeDpeCmd {
5764
if cmd.data_size as usize > cmd.data.len() {
5865
return Err(CaliptraError::RUNTIME_MAILBOX_INVALID_PARAMS);
5966
}
67+
68+
// Append a zeroed SVN to the command if it is a DeriveContext command and the SVN is
69+
// missing. This is to support older versions of the DPE that do not include the SVN in the
70+
// DeriveContext command.
71+
if let Ok((hdr, _)) = CommandHdr::read_from_prefix(&cmd.data[..cmd.data_size as usize]) {
72+
let expected_no_svn_len =
73+
size_of::<CommandHdr>() + size_of::<DeriveContextCmd>() - size_of::<u32>();
74+
let cmd_size = cmd.data_size as usize;
75+
76+
let is_derive_context_cmd = hdr.cmd_id == Command::DERIVE_CONTEXT;
77+
let is_missing_svn = cmd_size == expected_no_svn_len;
78+
let has_space_for_svn = cmd_size + size_of::<u32>() <= cmd.data.len();
79+
80+
if is_derive_context_cmd && is_missing_svn && has_space_for_svn {
81+
cmd.data[cmd_size..cmd_size + size_of::<u32>()].fill(0);
82+
cmd.data_size += size_of::<u32>() as u32;
83+
}
84+
}
85+
6086
let command =
6187
Command::deserialize(DpeProfile::P384Sha384, &cmd.data[..cmd.data_size as usize])
6288
.map_err(|_| CaliptraError::RUNTIME_DPE_COMMAND_DESERIALIZATION_FAILED)?;

runtime/tests/runtime_integration_tests/test_invoke_dpe.rs

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use caliptra_builder::{
1212
firmware::{APP_WITH_UART, FMC_WITH_UART},
1313
ImageOptions,
1414
};
15-
use caliptra_common::mailbox_api::{InvokeDpeReq, MailboxReq, MailboxReqHeader};
15+
use caliptra_common::mailbox_api::{InvokeDpeReq, InvokeDpeResp, MailboxReq, MailboxReqHeader};
1616
use caliptra_drivers::CaliptraError;
1717
use caliptra_hw_model::{HwModel, ModelError};
1818
use caliptra_runtime::{RtBootStatus, DPE_SUPPORT, VENDOR_ID, VENDOR_SKU};
@@ -23,9 +23,9 @@ use cms::{
2323
};
2424
use dpe::{
2525
commands::{
26-
CertifyKeyCommand, CertifyKeyFlags, CertifyKeyP384Cmd, Command, DeriveContextCmd,
27-
DeriveContextFlags, GetCertificateChainCmd, GetProfileCmd, InitCtxCmd, RotateCtxCmd,
28-
RotateCtxFlags, SignFlags, SignP384Cmd,
26+
CertifyKeyCommand, CertifyKeyFlags, CertifyKeyP384Cmd, Command, CommandHdr,
27+
DeriveContextCmd, DeriveContextFlags, GetCertificateChainCmd, GetProfileCmd, InitCtxCmd,
28+
RotateCtxCmd, RotateCtxFlags, SignFlags, SignP384Cmd,
2929
},
3030
context::ContextHandle,
3131
error::DpeErrorCode,
@@ -532,3 +532,62 @@ fn test_certify_key_with_max_contexts() {
532532
);
533533
}
534534
}
535+
536+
#[test]
537+
fn test_invoke_dpe_derive_context_without_svn() {
538+
let mut model = run_rt_test(RuntimeTestArgs::default());
539+
540+
model.step_until(|m| {
541+
m.soc_ifc().cptra_boot_status().read() == u32::from(RtBootStatus::RtReadyForCommands)
542+
});
543+
544+
let derive_ctx_cmd = DeriveContextCmd {
545+
handle: ContextHandle::default(),
546+
data: TciMeasurement([0; TCI_SIZE]),
547+
flags: DeriveContextFlags::EXPORT_CDI | DeriveContextFlags::CREATE_CERTIFICATE,
548+
tci_type: 0,
549+
target_locality: 0,
550+
svn: 0,
551+
};
552+
553+
let mut cmd_data = [0u8; InvokeDpeReq::DATA_MAX_SIZE];
554+
let cmd_hdr = CommandHdr::new(DpeProfile::P384Sha384, Command::DERIVE_CONTEXT);
555+
let cmd_hdr_buf = cmd_hdr.as_bytes();
556+
cmd_data[..cmd_hdr_buf.len()].copy_from_slice(cmd_hdr_buf);
557+
let dpe_cmd_buf = derive_ctx_cmd.as_bytes();
558+
// Strip the last 4 bytes (svn u32 field) to simulate caller without SVN
559+
let dpe_cmd_buf_no_svn = &dpe_cmd_buf[..dpe_cmd_buf.len() - 4];
560+
cmd_data[cmd_hdr_buf.len()..cmd_hdr_buf.len() + dpe_cmd_buf_no_svn.len()]
561+
.copy_from_slice(dpe_cmd_buf_no_svn);
562+
let mut mbox_cmd = MailboxReq::InvokeDpeCommand(InvokeDpeReq {
563+
hdr: MailboxReqHeader { chksum: 0 },
564+
data: cmd_data,
565+
data_size: (cmd_hdr_buf.len() + dpe_cmd_buf_no_svn.len()) as u32,
566+
});
567+
mbox_cmd.populate_chksum().unwrap();
568+
569+
let resp = model.mailbox_execute(
570+
u32::from(CommandId::INVOKE_DPE),
571+
mbox_cmd.as_bytes().unwrap(),
572+
);
573+
let resp = resp.unwrap().expect("We should have received a response");
574+
575+
assert!(resp.len() <= std::mem::size_of::<InvokeDpeResp>());
576+
let mut resp_hdr = InvokeDpeResp::default();
577+
resp_hdr.as_mut_bytes()[..resp.len()].copy_from_slice(&resp);
578+
579+
assert!(caliptra_common::checksum::verify_checksum(
580+
resp_hdr.hdr.chksum,
581+
0x0,
582+
&resp[core::mem::size_of_val(&resp_hdr.hdr.chksum)..],
583+
));
584+
585+
let resp_bytes = &resp_hdr.data[..resp_hdr.data_size as usize];
586+
let parsed_resp =
587+
Response::try_read_from_bytes(&Command::DeriveContext(&derive_ctx_cmd), resp_bytes)
588+
.unwrap();
589+
590+
let Response::DeriveContextExportedCdi(_) = parsed_resp else {
591+
panic!("expected derive context exported cdi resp!");
592+
};
593+
}

0 commit comments

Comments
 (0)