diff --git a/dpe b/dpe index d5bb8644d2..74ba3f3e4c 160000 --- a/dpe +++ b/dpe @@ -1 +1 @@ -Subproject commit d5bb8644d21e4114534ef2aaa242436aecc7743d +Subproject commit 74ba3f3e4c8a06a0928c909c5ffef552414c6ac4 diff --git a/runtime/src/drivers.rs b/runtime/src/drivers.rs index 8851ec57f0..c31aaf0c65 100644 --- a/runtime/src/drivers.rs +++ b/runtime/src/drivers.rs @@ -25,6 +25,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, @@ -32,7 +33,6 @@ use dpe::{ support::Support, DPE_PROFILE, }; -use dpe::{U8Bool, MAX_HANDLES}; use crypto::{AlgLen, Crypto, CryptoBuf, Hasher}; use zerocopy::AsBytes; @@ -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); @@ -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 @@ -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; - } - }); - } } diff --git a/runtime/src/invoke_dpe.rs b/runtime/src/invoke_dpe.rs index 3839704adf..78930cfcbf 100644 --- a/runtime/src/invoke_dpe.rs +++ b/runtime/src/invoke_dpe.rs @@ -10,7 +10,7 @@ use dpe::{ }, context::{Context, ContextState}, response::{Response, ResponseHdr}, - DpeInstance, MAX_HANDLES, + DpeInstance, U8Bool, MAX_HANDLES, }; use zerocopy::{AsBytes, FromBytes}; @@ -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 @@ -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), @@ -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; + } + }); + } } diff --git a/runtime/src/stash_measurement.rs b/runtime/src/stash_measurement.rs index b9b39a1f85..8c8262dbe2 100644 --- a/runtime/src/stash_measurement.rs +++ b/runtime/src/stash_measurement.rs @@ -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, diff --git a/runtime/test-fw/src/mbox_responder.rs b/runtime/test-fw/src/mbox_responder.rs index 6bc315bf07..aed7ac3308 100644 --- a/runtime/test-fw/src/mbox_responder.rs +++ b/runtime/test-fw/src/mbox_responder.rs @@ -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; diff --git a/runtime/tests/runtime_integration_tests/test_boot.rs b/runtime/tests/runtime_integration_tests/test_boot.rs index 2b63251c85..28f9364b15 100644 --- a/runtime/tests/runtime_integration_tests/test_boot.rs +++ b/runtime/tests/runtime_integration_tests/test_boot.rs @@ -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() @@ -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() diff --git a/runtime/tests/runtime_integration_tests/test_pauser_privilege_levels.rs b/runtime/tests/runtime_integration_tests/test_pauser_privilege_levels.rs index e1edc0ee37..2d2d2479e9 100644 --- a/runtime/tests/runtime_integration_tests/test_pauser_privilege_levels.rs +++ b/runtime/tests/runtime_integration_tests/test_pauser_privilege_levels.rs @@ -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, @@ -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, diff --git a/runtime/tests/runtime_integration_tests/test_stash_measurement.rs b/runtime/tests/runtime_integration_tests/test_stash_measurement.rs index ce9c6fe3ba..8446572571 100644 --- a/runtime/tests/runtime_integration_tests/test_stash_measurement.rs +++ b/runtime/tests/runtime_integration_tests/test_stash_measurement.rs @@ -1,5 +1,9 @@ // Licensed under the Apache-2.0 license +use caliptra_builder::{ + firmware::{self, FMC_WITH_UART}, + ImageOptions, +}; use caliptra_common::mailbox_api::{ CommandId, MailboxReq, MailboxReqHeader, StashMeasurementReq, StashMeasurementResp, }; @@ -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, }); @@ -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); } diff --git a/runtime/tests/runtime_integration_tests/test_tagging.rs b/runtime/tests/runtime_integration_tests/test_tagging.rs index 6653ad974c..2a7ae6e302 100644 --- a/runtime/tests/runtime_integration_tests/test_tagging.rs +++ b/runtime/tests/runtime_integration_tests/test_tagging.rs @@ -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, }; @@ -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, @@ -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(); }