Skip to content

Commit

Permalink
Auto-initialize DPE with the RT Journey PCR
Browse files Browse the repository at this point in the history
  • Loading branch information
sree-revoori1 committed Dec 8, 2023
1 parent dd36931 commit 220218b
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 72 deletions.
2 changes: 1 addition & 1 deletion dpe
Submodule dpe updated 1 files
+58 −0 dpe/src/dpe_instance.rs
44 changes: 10 additions & 34 deletions runtime/src/drivers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ use caliptra_registers::{
};
use dpe::context::{Context, ContextState};
use dpe::tci::TciMeasurement;
use dpe::MAX_HANDLES;
use dpe::{
commands::{CommandExecution, DeriveChildCmd, DeriveChildFlags},
context::ContextHandle,
dpe_instance::{DpeEnv, DpeInstance, DpeTypes},
support::Support,
DPE_PROFILE,
};
use dpe::{U8Bool, MAX_HANDLES};

use crypto::{AlgLen, Crypto, CryptoBuf, Hasher};
use zerocopy::AsBytes;
Expand Down Expand Up @@ -240,7 +240,7 @@ impl Drivers {
let dpe = &pdata.dpe;

for i in (0..MAX_HANDLES) {
if dpe.contexts[i].state != ContextState::Active
if dpe.contexts[i].state == ContextState::Inactive
&& (context_has_tag[i].get() || context_tags[i] != 0)
{
return Err(CaliptraError::RUNTIME_CONTEXT_TAG_VALIDATION_FAILED);
Expand Down Expand Up @@ -295,24 +295,17 @@ impl Drivers {
&mut drivers.cert_chain,
),
};
let mut dpe = DpeInstance::new(&mut env, DPE_SUPPORT)
.map_err(|_| CaliptraError::RUNTIME_INITIALIZE_DPE_FAILED)?;

let data = <[u8; DPE_PROFILE.get_hash_size()]>::from(
// Initialize DPE with the RT journey PCR
let rt_journey_measurement = <[u8; DPE_PROFILE.get_hash_size()]>::from(
&drivers.pcr_bank.read_pcr(RT_FW_JOURNEY_PCR),
);
// Call DeriveChild to create root context.
DeriveChildCmd {
handle: ContextHandle::default(),
data,
flags: DeriveChildFlags::MAKE_DEFAULT
| DeriveChildFlags::CHANGE_LOCALITY
| DeriveChildFlags::INPUT_ALLOW_CA
| DeriveChildFlags::INPUT_ALLOW_X509,
tci_type: u32::from_be_bytes(*b"RTJM"),
target_locality: caliptra_locality,
}
.execute(&mut dpe, &mut env, caliptra_locality)
let mut dpe = DpeInstance::new_auto_init(
&mut env,
DPE_SUPPORT,
u32::from_be_bytes(*b"RTJM"),
rt_journey_measurement,
)
.map_err(|_| CaliptraError::RUNTIME_INITIALIZE_DPE_FAILED)?;

// Call DeriveChild to create a measurement for the mailbox valid pausers and change locality to the pl0 pauser locality
Expand Down Expand Up @@ -460,21 +453,4 @@ impl Drivers {
pub fn is_caller_pl1(pl0_pauser: u32, flags: u32, locality: u32) -> bool {
flags & PL0_PAUSER_FLAG == 0 && locality != pl0_pauser
}

pub fn clear_tags_for_non_active_contexts(
dpe: &mut DpeInstance,
context_has_tag: &mut [U8Bool; MAX_HANDLES],
context_tags: &mut [u32; MAX_HANDLES],
) {
(0..MAX_HANDLES).for_each(|i| {
if i < dpe.contexts.len()
&& i < context_has_tag.len()
&& i < context_tags.len()
&& dpe.contexts[i].state != ContextState::Active
{
context_has_tag[i] = U8Bool::new(false);
context_tags[i] = 0;
}
});
}
}
26 changes: 20 additions & 6 deletions runtime/src/invoke_dpe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use dpe::{
},
context::{Context, ContextState},
response::{Response, ResponseHdr},
DpeInstance, MAX_HANDLES,
DpeInstance, U8Bool, MAX_HANDLES,
};
use zerocopy::{AsBytes, FromBytes};

Expand Down Expand Up @@ -78,10 +78,7 @@ impl InvokeDpeCmd {
{
return Err(CaliptraError::RUNTIME_INCORRECT_PAUSER_PRIVILEGE_LEVEL);
}
let derive_child_resp = cmd.execute(dpe, &mut env, locality);
// clear tags for retired contexts
Drivers::clear_tags_for_non_active_contexts(dpe, context_has_tag, context_tags);
derive_child_resp
cmd.execute(dpe, &mut env, locality)
}
Command::CertifyKey(cmd) => {
// PL1 cannot request X509
Expand All @@ -95,7 +92,7 @@ impl InvokeDpeCmd {
Command::DestroyCtx(cmd) => {
let destroy_ctx_resp = cmd.execute(dpe, &mut env, locality);
// clear tags for destroyed contexts
Drivers::clear_tags_for_non_active_contexts(dpe, context_has_tag, context_tags);
Self::clear_tags_for_inactive_contexts(dpe, context_has_tag, context_tags);
destroy_ctx_resp
}
Command::Sign(cmd) => cmd.execute(dpe, &mut env, locality),
Expand Down Expand Up @@ -131,4 +128,21 @@ impl InvokeDpeCmd {
Err(CaliptraError::RUNTIME_INSUFFICIENT_MEMORY)
}
}

pub fn clear_tags_for_inactive_contexts(
dpe: &mut DpeInstance,
context_has_tag: &mut [U8Bool; MAX_HANDLES],
context_tags: &mut [u32; MAX_HANDLES],
) {
(0..MAX_HANDLES).for_each(|i| {
if i < dpe.contexts.len()
&& i < context_has_tag.len()
&& i < context_tags.len()
&& dpe.contexts[i].state != ContextState::Active
{
context_has_tag[i] = U8Bool::new(false);
context_tags[i] = 0;
}
});
}
}
6 changes: 0 additions & 6 deletions runtime/src/stash_measurement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,6 @@ impl StashMeasurementCmd {
target_locality: locality,
}
.execute(&mut pdata_mut.dpe, &mut env, locality);
// clear tags for retired contexts
Drivers::clear_tags_for_non_active_contexts(
&mut pdata_mut.dpe,
&mut pdata_mut.context_has_tag,
&mut pdata_mut.context_tags,
);

match derive_child_resp {
Ok(_) => DpeErrorCode::NoError,
Expand Down
7 changes: 5 additions & 2 deletions runtime/test-fw/src/mbox_responder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
#![no_std]

use caliptra_common::mailbox_api::CommandId;
use caliptra_drivers::{pcr_log::RT_FW_JOURNEY_PCR, Array4x12};
use caliptra_registers::mbox::enums::MboxStatusE;
use caliptra_drivers::{
pcr_log::{PCR_ID_STASH_MEASUREMENT, RT_FW_JOURNEY_PCR},
Array4x12,
};
use caliptra_registers::{mbox::enums::MboxStatusE, soc_ifc::SocIfcReg};
use caliptra_runtime::{ContextState, Drivers};
use caliptra_test_harness::{runtime_handlers, test_suite};
use zerocopy::AsBytes;
Expand Down
5 changes: 2 additions & 3 deletions runtime/tests/runtime_integration_tests/test_boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ fn test_boot_tci_data() {
let valid_pauser_hash: [u8; 48] = valid_pauser_hash_resp.as_bytes().try_into().unwrap();

// hash expected DPE measurements in order
let measurements_to_be_hashed = [[0u8; 48], rt_journey_pcr, valid_pauser_hash].concat();
let measurements_to_be_hashed = [rt_journey_pcr, valid_pauser_hash].concat();
let expected_measurement_hash = model
.mailbox_execute(0x4000_0000, measurements_to_be_hashed.as_bytes())
.unwrap()
Expand Down Expand Up @@ -151,8 +151,7 @@ fn test_measurement_in_measurement_log_added_to_dpe() {
let valid_pauser_hash: [u8; 48] = valid_pauser_hash_resp.as_bytes().try_into().unwrap();

// hash expected DPE measurements in order
let measurements_to_be_hashed =
[[0u8; 48], rt_journey_pcr, valid_pauser_hash, measurement].concat();
let measurements_to_be_hashed = [rt_journey_pcr, valid_pauser_hash, measurement].concat();
let expected_measurement_hash = model
.mailbox_execute(0x4000_0000, measurements_to_be_hashed.as_bytes())
.unwrap()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,11 @@ fn test_pl1_derive_child_dpe_context_thresholds() {
let mut handle = init_ctx_resp.handle;

// Call DeriveChild with PL1 enough times to breach the threshold on the last iteration.
// Note that this loop runs exactly PL1_DPE_ACTIVE_CONTEXT_THRESHOLD - 2 times. When we initialize
// DPE, we measure the RT journey PCR and the mailbox valid pausers in Caliptra's locality: 0xFFFFFFFF,
// which counts as a PL1 locality. Then, we initialize a simulation context in locality 1. Thus, we can call derive child
// from PL1 exactly 16 - 3 = 13 times, and the last iteration of this loop, is expected to throw a threshold breached error.
let num_iterations = InvokeDpeCmd::PL1_DPE_ACTIVE_CONTEXT_THRESHOLD - 2;
// Note that this loop runs exactly PL1_DPE_ACTIVE_CONTEXT_THRESHOLD - 1 times. When we initialize
// DPE, we measure the RT journey PCR in Caliptra's locality: 0xFFFFFFFF, which counts as a PL1 locality.
// Then, we initialize a simulation context in locality 1. Thus, we can call derive child
// from PL1 exactly 16 - 2 = 14 times, and the last iteration of this loop, is expected to throw a threshold breached error.
let num_iterations = InvokeDpeCmd::PL1_DPE_ACTIVE_CONTEXT_THRESHOLD - 1;
for i in 0..num_iterations {
let derive_child_cmd = DeriveChildCmd {
handle,
Expand Down Expand Up @@ -194,12 +194,13 @@ fn test_pl1_init_ctx_dpe_context_thresholds() {
m.soc_ifc().cptra_boot_status().read() == u32::from(RtBootStatus::RtReadyForCommands)
});

let num_iterations = InvokeDpeCmd::PL1_DPE_ACTIVE_CONTEXT_THRESHOLD - 1;
let num_iterations = InvokeDpeCmd::PL1_DPE_ACTIVE_CONTEXT_THRESHOLD;
for i in 0..num_iterations {
let init_ctx_cmd = InitCtxCmd::new_simulation();

// InitCtx should fail on the PL1_DPE_ACTIVE_CONTEXT_THRESHOLD - 2nd iteration since
// RT initialization creates two contexts in Caliptra's locality, which is PL1.
// InitCtx should fail on the PL1_DPE_ACTIVE_CONTEXT_THRESHOLD - 1st iteration since
// RT initialization creates the RT journey measurement context in Caliptra's locality,
// which is PL1.
if i == num_iterations - 1 {
let resp = execute_dpe_cmd(
&mut model,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
// Licensed under the Apache-2.0 license

use caliptra_builder::{
firmware::{self, APP_WITH_UART, FMC_WITH_UART},
ImageOptions,
};
use caliptra_common::mailbox_api::{
CommandId, MailboxReq, MailboxReqHeader, StashMeasurementReq, StashMeasurementResp,
};
Expand All @@ -17,10 +21,11 @@ fn test_stash_measurement() {
m.soc_ifc().cptra_boot_status().read() == u32::from(RtBootStatus::RtReadyForCommands)
});

let measurement = [1u8; 48];
let mut cmd = MailboxReq::StashMeasurement(StashMeasurementReq {
hdr: MailboxReqHeader { chksum: 0 },
metadata: [0u8; 4],
measurement: [0u8; 48],
measurement,
context: [0u8; 48],
svn: 0,
});
Expand All @@ -40,4 +45,35 @@ fn test_stash_measurement() {
.into_ref();

assert_eq!(resp_hdr.dpe_result, 0);

// create a new fw image with the runtime replaced by the mbox responder
let updated_fw_image = caliptra_builder::build_and_sign_image(
&FMC_WITH_UART,
&firmware::runtime_tests::MBOX,
ImageOptions::default(),
)
.unwrap()
.to_bytes()
.unwrap();

// trigger an update reset so we can use commands in mbox responder
model
.mailbox_execute(u32::from(CommandId::FIRMWARE_LOAD), &updated_fw_image)
.unwrap();

let rt_journey_pcr_resp = model.mailbox_execute(0x1000_0000, &[]).unwrap().unwrap();
let rt_journey_pcr: [u8; 48] = rt_journey_pcr_resp.as_bytes().try_into().unwrap();

let valid_pauser_hash_resp = model.mailbox_execute(0x2000_0000, &[]).unwrap().unwrap();
let valid_pauser_hash: [u8; 48] = valid_pauser_hash_resp.as_bytes().try_into().unwrap();

// hash expected DPE measurements in order to check that stashed measurement was added to DPE
let measurements_to_be_hashed = [rt_journey_pcr, valid_pauser_hash, measurement].concat();
let expected_measurement_hash = model
.mailbox_execute(0x4000_0000, measurements_to_be_hashed.as_bytes())
.unwrap()
.unwrap();

let dpe_measurement_hash = model.mailbox_execute(0x3000_0000, &[]).unwrap().unwrap();
assert_eq!(expected_measurement_hash, dpe_measurement_hash);
}
53 changes: 42 additions & 11 deletions runtime/tests/runtime_integration_tests/test_tagging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,23 +212,57 @@ fn test_tagging_destroyed_context() {
fn test_tagging_retired_context() {
let mut model = run_rt_test(None, None, None);

// Tag default context
// retire context via DeriveChild
let derive_child_cmd = DeriveChildCmd {
handle: ContextHandle::default(),
data: [0u8; DPE_PROFILE.get_hash_size()],
flags: DeriveChildFlags::empty(),
tci_type: 0,
target_locality: 0,
};
let resp = execute_dpe_cmd(
&mut model,
&mut Command::DeriveChild(derive_child_cmd),
DpeResult::Success,
);
let Some(Response::DeriveChild(derive_child_resp)) = resp else {
panic!("Wrong response type!");
};
let new_handle = derive_child_resp.handle;

// check that we cannot tag retired context
let mut cmd = MailboxReq::TagTci(TagTciReq {
hdr: MailboxReqHeader { chksum: 0 },
handle: DEFAULT_HANDLE,
tag: TAG,
});
cmd.populate_chksum().unwrap();
let resp = model
.mailbox_execute(u32::from(CommandId::DPE_TAG_TCI), cmd.as_bytes().unwrap())
.unwrap_err();
assert_error(
&mut model,
caliptra_drivers::CaliptraError::RUNTIME_TAGGING_FAILURE,
resp,
);

// tag new context
let mut cmd = MailboxReq::TagTci(TagTciReq {
hdr: MailboxReqHeader { chksum: 0 },
handle: new_handle.0,
tag: TAG,
});
cmd.populate_chksum().unwrap();
let _ = model
.mailbox_execute(u32::from(CommandId::DPE_TAG_TCI), cmd.as_bytes().unwrap())
.unwrap()
.expect("We expected a response");

// retire tagged context via DeriveChild
// retire tagged context via derive child
let derive_child_cmd = DeriveChildCmd {
handle: ContextHandle::default(),
handle: new_handle,
data: [0u8; DPE_PROFILE.get_hash_size()],
flags: DeriveChildFlags::MAKE_DEFAULT,
flags: DeriveChildFlags::empty(),
tci_type: 0,
target_locality: 0,
};
Expand All @@ -241,7 +275,7 @@ fn test_tagging_retired_context() {
panic!("Wrong response type!");
};

// check that we cannot get tagged tci for a retired context
// check that we can get tagged tci for a retired context
let mut cmd = MailboxReq::GetTaggedTci(GetTaggedTciReq {
hdr: MailboxReqHeader { chksum: 0 },
tag: TAG,
Expand All @@ -252,10 +286,7 @@ fn test_tagging_retired_context() {
u32::from(CommandId::DPE_GET_TAGGED_TCI),
cmd.as_bytes().unwrap(),
)
.unwrap_err();
assert_error(
&mut model,
caliptra_drivers::CaliptraError::RUNTIME_TAGGING_FAILURE,
resp,
);
.unwrap()
.expect("We expected a response");
let _ = GetTaggedTciResp::read_from(resp.as_slice()).unwrap();
}

0 comments on commit 220218b

Please sign in to comment.