diff --git a/error/src/lib.rs b/error/src/lib.rs index ec3922edd1..b00dcc6778 100644 --- a/error/src/lib.rs +++ b/error/src/lib.rs @@ -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_SELF_TEST_IN_PROGREESS: CaliptraError = CaliptraError::new_const(0x000E0013); /// FMC Errors pub const FMC_GLOBAL_NMI: CaliptraError = CaliptraError::new_const(0x000F0001); diff --git a/runtime/src/fips.rs b/runtime/src/fips.rs index 226d80df9e..a6cdb57234 100644 --- a/runtime/src/fips.rs +++ b/runtime/src/fips.rs @@ -62,12 +62,21 @@ impl FipsVersionCmd { #[cfg(feature = "fips_self_test")] pub mod fips_self_test_cmd { use super::*; + use crate::RtBootStatus::{RtFipSelfTestComplete, RtFipSelfTestStarted}; use caliptra_common::{verifier::FirmwareImageVerificationEnv, FMC_ORG, RUNTIME_ORG}; use caliptra_drivers::ResetReason; use caliptra_image_verify::ImageVerifier; use zerocopy::AsBytes; + pub enum SelfTestStatus { + Idle, + InProgress(fn(&mut Drivers) -> CaliptraResult<()>), + Done, + } + fn copy_and_verify_image(env: &mut Drivers) -> CaliptraResult<()> { + cprintln!("write dummy cmd"); + env.mbox.write_cmd(0)?; cprintln!("set dlen"); env.mbox .set_dlen(env.manifest.size + env.manifest.fmc.size + env.manifest.runtime.size); @@ -93,23 +102,24 @@ pub mod fips_self_test_cmd { }; let mut verifier = ImageVerifier::new(&mut venv); - cprintln!("verify"); + cprintln!("Verify started"); let _info = verifier.verify( &env.manifest, env.manifest.size + env.manifest.fmc.size + env.manifest.runtime.size, ResetReason::UpdateReset, )?; - cprintln!("verify done"); + env.mbox.unlock(); + cprintln!("[rt] Verify complete"); Ok(()) } - pub(crate) fn execute(env: &mut Drivers) -> CaliptraResult { + pub(crate) fn execute(env: &mut Drivers) -> CaliptraResult<()> { + caliptra_drivers::report_boot_status(RtFipSelfTestStarted.into()); cprintln!("[rt] FIPS self test"); - caliptra_common::wdt::stop_wdt(&mut env.soc_ifc); - execute_kats(env)?; copy_and_verify_image(env)?; - - Ok(MailboxResp::default()) + execute_kats(env)?; + caliptra_drivers::report_boot_status(RtFipSelfTestComplete.into()); + Ok(()) } /// Execute KAT for cryptographic algorithms implemented in H/W. diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 4ec65364cc..a95b474557 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1,6 +1,7 @@ // Licensed under the Apache-2.0 license #![no_std] +#![cfg_attr(not(feature = "fip-self-test"), allow(unused))] pub mod dice; mod disable; @@ -24,7 +25,8 @@ pub use disable::DisableAttestationCmd; use dpe_crypto::DpeCrypto; pub use dpe_platform::{DpePlatform, VENDOR_ID, VENDOR_SKU}; #[cfg(feature = "fips_self_test")] -pub use fips::fips_self_test_cmd; +pub use fips::{fips_self_test_cmd, fips_self_test_cmd::SelfTestStatus}; + pub use fips::{FipsShutdownCmd, FipsVersionCmd}; pub use info::FwInfoCmd; @@ -32,15 +34,18 @@ pub use invoke_dpe::InvokeDpeCmd; pub use stash_measurement::StashMeasurementCmd; pub use verify::EcdsaVerifyCmd; pub mod packet; +use caliptra_common::mailbox_api::CommandId; use packet::Packet; -use caliptra_common::mailbox_api::CommandId; +#[cfg(feature = "fips_self_test")] +use caliptra_common::mailbox_api::MailboxResp; use caliptra_common::memory_layout::{ FHT_ORG, FHT_SIZE, FMCALIAS_TBS_ORG, FMCALIAS_TBS_SIZE, FUSE_LOG_ORG, FUSE_LOG_SIZE, LDEVID_TBS_ORG, LDEVID_TBS_SIZE, MAN1_ORG, MAN1_SIZE, MAN2_ORG, MAN2_SIZE, PCR_LOG_ORG, PCR_LOG_SIZE, }; use caliptra_common::{cprintln, FirmwareHandoffTable}; + use caliptra_drivers::{ CaliptraError, CaliptraResult, DataVault, Ecc384, KeyVault, Lms, Sha1, SocIfc, }; @@ -72,6 +77,8 @@ const RUNTIME_BOOT_STATUS_BASE: u32 = 0x600; pub enum RtBootStatus { // RtAlias Statuses RtReadyForCommands = RUNTIME_BOOT_STATUS_BASE, + RtFipSelfTestStarted = RUNTIME_BOOT_STATUS_BASE + 1, + RtFipSelfTestComplete = RUNTIME_BOOT_STATUS_BASE + 2, } impl From for u32 { @@ -119,6 +126,9 @@ pub struct Drivers<'a> { pub dpe: DpeInstance, pub pcr_bank: PcrBank, + + #[cfg(feature = "fips_self_test")] + pub self_test_status: SelfTestStatus, } pub struct CptraDpeTypes; @@ -190,6 +200,8 @@ impl<'a> Drivers<'a> { manifest, dpe, pcr_bank, + #[cfg(feature = "fips_self_test")] + self_test_status: SelfTestStatus::Idle, }) } @@ -217,7 +229,19 @@ impl<'a> Drivers<'a> { } } -fn wait_for_cmd(_mbox: &mut Mailbox) { +/// Run pending jobs and enter low power mode. +fn goto_idle(drivers: &mut Drivers) { + // Run pending jobs before entering low power mode. + #[cfg(feature = "fips_self_test")] + if let SelfTestStatus::InProgress(execute) = drivers.self_test_status { + if drivers.mbox.lock() == false { + match execute(drivers) { + Ok(_) => drivers.self_test_status = SelfTestStatus::Done, + Err(e) => caliptra_drivers::report_fw_error_non_fatal(e.into()), + } + } + } + // TODO: Enable interrupts? //#[cfg(feature = "riscv")] //unsafe { @@ -268,7 +292,17 @@ fn handle_command(drivers: &mut Drivers) -> CaliptraResult { CommandId::TEST_ONLY_HMAC384_VERIFY => HmacVerifyCmd::execute(drivers, cmd_bytes), CommandId::VERSION => FipsVersionCmd::execute(drivers), #[cfg(feature = "fips_self_test")] - CommandId::SELF_TEST => fips_self_test_cmd::execute(drivers), + CommandId::SELF_TEST => match drivers.self_test_status { + SelfTestStatus::Idle => { + drivers.self_test_status = SelfTestStatus::InProgress(fips_self_test_cmd::execute); + Ok(MailboxResp::default()) + } + SelfTestStatus::Done => { + drivers.self_test_status = SelfTestStatus::Idle; + Ok(MailboxResp::default()) + } + _ => Err(CaliptraError::RUNTIME_SELF_TEST_IN_PROGREESS), + }, CommandId::SHUTDOWN => FipsShutdownCmd::execute(drivers), _ => Err(CaliptraError::RUNTIME_UNIMPLEMENTED_COMMAND), }?; @@ -284,7 +318,7 @@ pub fn handle_mailbox_commands(drivers: &mut Drivers) -> ! { drivers.soc_ifc.assert_ready_for_runtime(); caliptra_drivers::report_boot_status(RtBootStatus::RtReadyForCommands.into()); loop { - wait_for_cmd(&mut drivers.mbox); + goto_idle(drivers); if drivers.mbox.is_cmd_ready() { // TODO : Move start/stop WDT to wait_for_cmd when NMI is implemented. caliptra_common::wdt::start_wdt( @@ -301,6 +335,7 @@ pub fn handle_mailbox_commands(drivers: &mut Drivers) -> ! { } } caliptra_common::wdt::stop_wdt(&mut drivers.soc_ifc); + } else { } } } diff --git a/runtime/src/mailbox.rs b/runtime/src/mailbox.rs index ece978dbd1..0250f0e3c4 100644 --- a/runtime/src/mailbox.rs +++ b/runtime/src/mailbox.rs @@ -1,7 +1,11 @@ // Licensed under the Apache-2.0 license use caliptra_drivers::CaliptraResult; -use caliptra_registers::mbox::{enums::MboxStatusE, MboxCsr}; +use caliptra_error::CaliptraError; +use caliptra_registers::mbox::{ + enums::{MboxFsmE, MboxStatusE}, + MboxCsr, +}; use zerocopy::{AsBytes, LayoutVerified, Unalign}; use crate::CommandId; @@ -45,6 +49,26 @@ impl Mailbox { CommandId(cmd_code) } + pub fn lock(&mut self) -> bool { + let mbox = self.mbox.regs(); + mbox.lock().read().lock() + } + pub fn unlock(&mut self) { + let mbox = self.mbox.regs_mut(); + mbox.unlock().write(|_| 1.into()); + } + + pub fn write_cmd(&mut self, cmd: u32) -> CaliptraResult<()> { + let mbox = self.mbox.regs_mut(); + match mbox.status().read().mbox_fsm_ps() { + MboxFsmE::MboxRdyForCmd => { + mbox.cmd().write(|_| cmd); + Ok(()) + } + _ => Err(CaliptraError::RUNTIME_INTERNAL), + } + } + pub fn user(&self) -> u32 { let mbox = self.mbox.regs(); mbox.user().read() diff --git a/test/tests/smoke_test.rs b/test/tests/smoke_test.rs index 5c00d3dfd7..2d2348df32 100644 --- a/test/tests/smoke_test.rs +++ b/test/tests/smoke_test.rs @@ -412,4 +412,32 @@ fn fips_self_test() { &resp.as_bytes()[core::mem::size_of_val(&resp.chksum)..], )); assert_eq!(resp.fips_status, MailboxRespHeader::FIPS_STATUS_APPROVED); + + // Confirm we can't re-start the FIPS self test. + hw.step_until_boot_status( + caliptra_runtime::RtBootStatus::RtFipSelfTestStarted.into(), + true, + ); + let _resp = hw + .mailbox_execute(u32::from(CommandId::SELF_TEST), payload.as_bytes()) + .unwrap_err(); + + hw.step_until_boot_status( + caliptra_runtime::RtBootStatus::RtFipSelfTestComplete.into(), + true, + ); + + let resp = hw + .mailbox_execute(u32::from(CommandId::SELF_TEST), payload.as_bytes()) + .unwrap() + .unwrap(); + + let resp = MailboxRespHeader::read_from(resp.as_slice()).unwrap(); + // Verify checksum and FIPS status + assert!(caliptra_common::checksum::verify_checksum( + resp.chksum, + 0x0, + &resp.as_bytes()[core::mem::size_of_val(&resp.chksum)..], + )); + assert_eq!(resp.fips_status, MailboxRespHeader::FIPS_STATUS_APPROVED); }