Skip to content

Commit

Permalink
Validate tags upon warm/update reset
Browse files Browse the repository at this point in the history
Also, ensure that tags are cleared for retired contexts.
  • Loading branch information
sree-revoori1 authored and jhand2 committed Dec 5, 2023
1 parent eb3f429 commit 66532a9
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 13 deletions.
2 changes: 2 additions & 0 deletions error/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,8 @@ impl CaliptraError {
CaliptraError::new_const(0x000E0027);
pub const RUNTIME_LDEVID_CERT_HANDOFF_FAILED: CaliptraError =
CaliptraError::new_const(0x000E0028);
pub const RUNTIME_CONTEXT_TAG_VALIDATION_FAILED: CaliptraError =
CaliptraError::new_const(0x000E0029);

/// FMC Errors
pub const FMC_GLOBAL_NMI: CaliptraError = CaliptraError::new_const(0x000F0001);
Expand Down
1 change: 1 addition & 0 deletions runtime/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,7 @@ this case, the new Runtime Firmware must:
Runtime Journey PCR (TYPE = RTJM, “Internal TCI” flag is set) matches the
“Latest” Runtime PCR value from PCRX
1. Ensure `SHA384_HASH(0x00..00, TCI from SRAM) == RT_FW_JOURNEY_PCR`
1. Check that retired and inactive contexts do not have tags
1. If any validations fail, runtime firmware will execute the
`DISABLE_ATTESTATION` command.

Expand Down
4 changes: 3 additions & 1 deletion runtime/doc/test-coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ Attempts to add a duplicate tag and verifies that it fails | **test_duplicate_ta
Calls the dpe_get_tagged_tci mailbox command with a tag that does not exist and checks that it fails | **test_get_tagged_tci_on_non_existent_tag** | RUNTIME_TAGGING_FAILURE
Attempts to tag an inactive context and verifies that it fails | **test_tagging_inactive_context** | RUNTIME_TAGGING_FAILURE
Tags the default context, destroys the default context, and checks that the dpe_get_tagged_tci mailbox command fails on the default context | **test_tagging_destroyed_context** | RUNTIME_TAGGING_FAILURE
Tags the default context, retires the default context, and checks that the dpe_get_tagged_tci mailbox command fails on the default context | **test_tagging_retired_context** | RUNTIME_TAGGING_FAILURE

<br><br>
# **DPE Verification Tests**
Expand Down Expand Up @@ -147,4 +148,5 @@ Test PL1 pauser active context limits | N/A | N/A
Check that measurements are stored in DPE when StashMeasurement is called | N/A | N/A
Verify that DPE attestation flow fails after DisableAttestation is called | N/A | N/A
Check that mailbox valid pausers are measured into DPE upon RT startup | N/A | N/A
Check that the RT alias key is different from the key signing DPE certs | N/A | N/A
Check that the RT alias key is different from the key signing DPE certs | N/A | N/A
Test context tag validity upon warm/update reset | N/A | N/A
19 changes: 19 additions & 0 deletions runtime/src/drivers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use caliptra_registers::{
};
use dpe::context::{Context, ContextState};
use dpe::tci::TciMeasurement;
use dpe::MAX_HANDLES;
use dpe::{
commands::{CommandExecution, DeriveChildCmd, DeriveChildFlags},
context::ContextHandle,
Expand Down Expand Up @@ -94,10 +95,12 @@ impl Drivers {
}
ResetReason::UpdateReset => {
Self::validate_dpe_structure(&mut drivers)?;
Self::validate_context_tags(&mut drivers)?;
Self::update_dpe_rt_journey(&mut drivers)?;
}
ResetReason::WarmReset => {
Self::validate_dpe_structure(&mut drivers)?;
Self::validate_context_tags(&mut drivers)?;
Self::check_dpe_rt_journey_unchanged(&mut drivers)?;
}
ResetReason::Unknown => {
Expand Down Expand Up @@ -229,6 +232,22 @@ impl Drivers {
Ok(())
}

fn validate_context_tags(mut drivers: &mut Drivers) -> CaliptraResult<()> {
let pdata = drivers.persistent_data.get();
let context_has_tag = pdata.context_has_tag;
let context_tags = pdata.context_tags;
let dpe = &pdata.dpe;

for i in (0..MAX_HANDLES) {
if dpe.contexts[i].state != ContextState::Active
&& (context_has_tag[i].get() || context_tags[i] != 0)
{
return Err(CaliptraError::RUNTIME_CONTEXT_TAG_VALIDATION_FAILED);
}
}
Ok(())
}

// Caliptra Name serialNumber fields are sha256 digests
pub fn compute_rt_alias_sn(&mut self) -> CaliptraResult<CryptoBuf> {
let key = self.persistent_data.get().fht.rt_dice_pub_key.to_der();
Expand Down
33 changes: 22 additions & 11 deletions runtime/src/invoke_dpe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ impl InvokeDpeCmd {
{
return Err(CaliptraError::RUNTIME_INCORRECT_PAUSER_PRIVILEGE_LEVEL);
}
cmd.execute(dpe, &mut env, locality)
let derive_child_resp = cmd.execute(dpe, &mut env, locality);
// clear tags for retired contexts
Self::clear_tags_for_non_active_contexts(dpe, context_has_tag, context_tags);
derive_child_resp
}
Command::CertifyKey(cmd) => {
// PL1 cannot request X509
Expand All @@ -93,16 +96,7 @@ impl InvokeDpeCmd {
Command::DestroyCtx(cmd) => {
let destroy_ctx_resp = cmd.execute(dpe, &mut env, locality);
// clear tags for destroyed contexts
(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;
}
});
Self::clear_tags_for_non_active_contexts(dpe, context_has_tag, context_tags);
destroy_ctx_resp
}
Command::Sign(cmd) => cmd.execute(dpe, &mut env, locality),
Expand Down Expand Up @@ -172,4 +166,21 @@ impl InvokeDpeCmd {
fn is_caller_pl1(pl0_pauser: u32, flags: u32, locality: u32) -> bool {
flags & PL0_PAUSER_FLAG == 0 && locality != pl0_pauser
}

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;
}
});
}
}
55 changes: 54 additions & 1 deletion runtime/tests/runtime_integration_tests/test_tagging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ use caliptra_common::mailbox_api::{
};
use caliptra_hw_model::HwModel;
use dpe::{
commands::{Command, DestroyCtxCmd},
commands::{Command, DeriveChildCmd, DeriveChildFlags, DestroyCtxCmd},
context::ContextHandle,
response::Response,
DPE_PROFILE,
};
use zerocopy::FromBytes;

Expand Down Expand Up @@ -206,3 +207,55 @@ fn test_tagging_destroyed_context() {
resp,
);
}

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

// Tag default context
let mut cmd = MailboxReq::TagTci(TagTciReq {
hdr: MailboxReqHeader { chksum: 0 },
handle: DEFAULT_HANDLE,
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
let derive_child_cmd = DeriveChildCmd {
handle: ContextHandle::default(),
data: [0u8; DPE_PROFILE.get_hash_size()],
flags: DeriveChildFlags::MAKE_DEFAULT,
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(_)) = resp else {
panic!("Wrong response type!");
};

// check that we cannot get tagged tci for a retired context
let mut cmd = MailboxReq::GetTaggedTci(GetTaggedTciReq {
hdr: MailboxReqHeader { chksum: 0 },
tag: TAG,
});
cmd.populate_chksum().unwrap();
let resp = model
.mailbox_execute(
u32::from(CommandId::DPE_GET_TAGGED_TCI),
cmd.as_bytes().unwrap(),
)
.unwrap_err();
assert_error(
&mut model,
caliptra_drivers::CaliptraError::RUNTIME_TAGGING_FAILURE,
resp,
);
}

0 comments on commit 66532a9

Please sign in to comment.