Repository: chipsalliance/caliptra-sw
Pull request #645 (2023-08-15 22:32:48)

Add disable attestation mailbox command


Patch:
diff --git a/error/src/lib.rs b/error/src/lib.rs
index bae903a1..426d627c 100644
--- a/error/src/lib.rs
+++ b/error/src/lib.rs
@@ -291,6 +291,8 @@ impl CaliptraError {
     pub const RUNTIME_HMAC_VERIFY_FAILED: CaliptraError = CaliptraError::new_const(0x000E000E);
     pub const RUNTIME_INVOKE_DPE_FAILED: CaliptraError = CaliptraError::new_const(0x000E000F);
     pub const RUNTIME_INITIALIZE_DPE_FAILED: CaliptraError = CaliptraError::new_const(0x000E0010);
+    pub const RUNTIME_DISABLE_ATTESTATION_FAILED: CaliptraError =
+        CaliptraError::new_const(0x000E0011);
 
     /// FMC Errors
     pub const FMC_GLOBAL_NMI: CaliptraError = CaliptraError::new_const(0x000F0001);
diff --git a/runtime/src/disable.rs b/runtime/src/disable.rs
new file mode 100644
index 00000000..2b1cb3e1
--- /dev/null
+++ b/runtime/src/disable.rs
@@ -0,0 +1,44 @@
+// Licensed under the Apache-2.0 license
+
+use crate::{Drivers, MailboxResp};
+use caliptra_common::keyids::{KEY_ID_RT_CDI, KEY_ID_RT_PRIV_KEY};
+use caliptra_drivers::{
+    hmac384_kdf, CaliptraError, CaliptraResult, KeyReadArgs, KeyUsage, KeyWriteArgs,
+};
+
+pub struct DisableAttestationCmd;
+impl DisableAttestationCmd {
+    pub(crate) fn execute(drivers: &mut Drivers) -> CaliptraResult<MailboxResp> {
+        drivers
+            .key_vault
+            .erase_key(KEY_ID_RT_CDI)
+            .map_err(|_| CaliptraError::RUNTIME_DISABLE_ATTESTATION_FAILED)?;
+        drivers
+            .key_vault
+            .erase_key(KEY_ID_RT_PRIV_KEY)
+            .map_err(|_| CaliptraError::RUNTIME_DISABLE_ATTESTATION_FAILED)?;
+
+        Self::generate_dice_key(drivers)?;
+        Ok(MailboxResp::default())
+    }
+
+    // Dice key is derived from an empty CDI slot so it will not match the key that was certified in the rt_alias cert.
+    fn generate_dice_key(drivers: &mut Drivers) -> CaliptraResult<()> {
+        hmac384_kdf(
+            &mut drivers.hmac384,
+            KeyReadArgs::new(KEY_ID_RT_CDI).into(),
+            b"dice_keygen",
+            None,
+            &mut drivers.trng,
+            KeyWriteArgs::new(
+                KEY_ID_RT_PRIV_KEY,
+                KeyUsage::default()
+                    .set_hmac_key_en()
+                    .set_ecc_key_gen_seed_en(),
+            )
+            .into(),
+        )?;
+
+        Ok(())
+    }
+}
diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index c526937b..5351d5d2 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -3,6 +3,7 @@
 #![no_std]
 
 pub mod dice;
+mod disable;
 mod dpe_crypto;
 mod dpe_platform;
 pub mod fips;
@@ -27,6 +28,7 @@ pub use dpe_platform::{DpePlatform, VENDOR_ID, VENDOR_SKU};
 
 #[cfg(feature = "test_only_commands")]
 pub use dice::{GetLdevCertCmd, TestGetFmcAliasCertCmd};
+pub use disable::DisableAttestationCmd;
 pub use fips::{FipsSelfTestCmd, FipsShutdownCmd, FipsVersionCmd};
 pub use info::FwInfoCmd;
 pub use invoke_dpe::InvokeDpeCmd;
@@ -40,12 +42,12 @@ use caliptra_common::memory_layout::{
     PCR_LOG_SIZE,
 };
 use caliptra_common::{cprintln, FirmwareHandoffTable};
-use caliptra_drivers::{CaliptraError, CaliptraResult, DataVault, Ecc384, SocIfc};
+use caliptra_drivers::{CaliptraError, CaliptraResult, DataVault, Ecc384, KeyVault, SocIfc};
 use caliptra_drivers::{Hmac384, PcrBank, PcrId, Sha256, Sha384, Sha384Acc, Trng};
 use caliptra_image_types::ImageManifest;
 use caliptra_registers::mbox::enums::MboxStatusE;
 use caliptra_registers::{
-    csrng::CsrngReg, dv::DvReg, ecc::EccReg, entropy_src::EntropySrcReg, hmac::HmacReg,
+    csrng::CsrngReg, dv::DvReg, ecc::EccReg, entropy_src::EntropySrcReg, hmac::HmacReg, kv::KvReg,
     mbox::MboxCsr, pv::PvReg, sha256::Sha256Reg, sha512::Sha512Reg, sha512_acc::Sha512AccCsr,
     soc_ifc::SocIfcReg, soc_ifc_trng::SocIfcTrngReg,
 };
@@ -98,6 +100,7 @@ pub struct Drivers<'a> {
     pub mbox: Mailbox,
     pub sha_acc: Sha512AccCsr,
     pub data_vault: DataVault,
+    pub key_vault: KeyVault,
     pub soc_ifc: SocIfc,
     pub regions: MemoryRegions,
     pub sha256: Sha256,
@@ -167,6 +170,7 @@ impl<'a> Drivers<'a> {
             mbox: Mailbox::new(MboxCsr::new()),
             sha_acc: Sha512AccCsr::new(),
             data_vault: DataVault::new(DvReg::new()),
+            key_vault: KeyVault::new(KvReg::new()),
             soc_ifc: SocIfc::new(SocIfcReg::new()),
             regions: MemoryRegions::new(),
             sha256: Sha256::new(Sha256Reg::new()),
@@ -252,6 +256,7 @@ fn handle_command(drivers: &mut Drivers) -> CaliptraResult<MboxStatusE> {
         }
         CommandId::ECDSA384_VERIFY => EcdsaVerifyCmd::execute(drivers, cmd_bytes),
         CommandId::STASH_MEASUREMENT => Err(CaliptraError::RUNTIME_UNIMPLEMENTED_COMMAND),
+        CommandId::DISABLE_ATTESTATION => DisableAttestationCmd::execute(drivers),
         CommandId::FW_INFO => FwInfoCmd::execute(drivers),
         #[cfg(feature = "test_only_commands")]
         CommandId::TEST_ONLY_GET_LDEV_CERT => GetLdevCertCmd::execute(&drivers.data_vault),
diff --git a/runtime/src/mailbox_api.rs b/runtime/src/mailbox_api.rs
index d443f0e6..7fed9a1d 100644
--- a/runtime/src/mailbox_api.rs
+++ b/runtime/src/mailbox_api.rs
@@ -15,6 +15,7 @@ impl CommandId {
     pub const ECDSA384_VERIFY: Self = Self(0x53494756); // "SIGV"
     pub const STASH_MEASUREMENT: Self = Self(0x4D454153); // "MEAS"
     pub const INVOKE_DPE: Self = Self(0x44504543); // "DPEC"
+    pub const DISABLE_ATTESTATION: Self = Self(0x4453424C); // "DSBL"
     pub const FW_INFO: Self = Self(0x494E464F); // "INFO"
 
     // TODO: Remove this and merge with GET_LDEV_CERT once that is implemented


Test patch:
diff --git a/runtime/test-fw/Cargo.toml b/runtime/test-fw/Cargo.toml
index 33331a0e..0e80f606 100644
--- a/runtime/test-fw/Cargo.toml
+++ b/runtime/test-fw/Cargo.toml
@@ -38,6 +38,11 @@ name = "wdt"
 path = "src/wdt_timeout_tests.rs"
 required-features = ["riscv"]
 
+[[bin]]
+name = "keyvault"
+path = "src/keyvault_tests.rs"
+required-features = ["riscv"]
+
 [build-dependencies]
 caliptra_common = { workspace = true, default-features = false }
 caliptra-gen-linker-scripts.workspace = true
diff --git a/runtime/test-fw/src/keyvault_tests.rs b/runtime/test-fw/src/keyvault_tests.rs
new file mode 100644
index 00000000..1cd7918f
--- /dev/null
+++ b/runtime/test-fw/src/keyvault_tests.rs
@@ -0,0 +1,58 @@
+/*++
+
+Licensed under the Apache-2.0 license.
+
+File Name:
+
+    keyvault_tests.rs
+
+Abstract:
+
+    File contains test cases for booting runtime firmware
+
+--*/
+
+#![no_std]
+#![no_main]
+
+use caliptra_common::keyids::{KEY_ID_RT_CDI, KEY_ID_RT_PRIV_KEY};
+use caliptra_drivers::{hmac384_kdf, Hmac384, KeyReadArgs, KeyUsage, KeyVault, KeyWriteArgs, Trng};
+use caliptra_registers::{
+    csrng::CsrngReg, entropy_src::EntropySrcReg, hmac::HmacReg, kv::KvReg, soc_ifc::SocIfcReg,
+    soc_ifc_trng::SocIfcTrngReg,
+};
+use caliptra_test_harness::{runtime_handlers, test_suite};
+
+fn test_derive_ecc_key_from_cdi_in_erased_kv_slot() {
+    let mut vault = unsafe { KeyVault::new(KvReg::new()) };
+    let mut hmac384 = unsafe { Hmac384::new(HmacReg::new()) };
+    let mut trng = unsafe {
+        Trng::new(
+            CsrngReg::new(),
+            EntropySrcReg::new(),
+            SocIfcTrngReg::new(),
+            &SocIfcReg::new(),
+        )
+        .unwrap()
+    };
+    vault.erase_key(KEY_ID_RT_CDI).unwrap();
+    hmac384_kdf(
+        &mut hmac384,
+        KeyReadArgs::new(KEY_ID_RT_CDI).into(),
+        b"dice_keygen",
+        None,
+        &mut trng,
+        KeyWriteArgs::new(
+            KEY_ID_RT_PRIV_KEY,
+            KeyUsage::default()
+                .set_hmac_key_en()
+                .set_ecc_key_gen_seed_en(),
+        )
+        .into(),
+    )
+    .unwrap();
+}
+
+test_suite! {
+    test_derive_ecc_key_from_cdi_in_erased_kv_slot,
+}
diff --git a/runtime/tests/integration_tests.rs b/runtime/tests/integration_tests.rs
index c0365af3..b5ead07a 100644
--- a/runtime/tests/integration_tests.rs
+++ b/runtime/tests/integration_tests.rs
@@ -77,6 +77,13 @@ fn test_boot() {
     model.step_until_exit_success().unwrap();
 }
 
+#[test]
+fn test_keyvault() {
+    let mut model = run_rt_test(Some("keyvault"));
+
+    model.step_until_exit_success().unwrap();
+}
+
 #[test]
 fn test_rom_certs() {
     let mut model = run_rt_test(Some("cert"));
@@ -186,6 +193,32 @@ fn test_invoke_dpe_get_profile_cmd() {
     assert_eq!(profile.flags, DPE_SUPPORT.get_flags());
 }
 
+#[test]
+fn test_disable_attestation_cmd() {
+    let mut model = run_rt_test(None);
+
+    let payload = MailboxReqHeader {
+        chksum: caliptra_common::checksum::calc_checksum(
+            u32::from(CommandId::DISABLE_ATTESTATION),
+            &[],
+        ),
+    };
+    // once DPE APIs are enabled, ensure that the RT alias key in the cert is different from the key that signs DPE certs
+    let resp = model
+        .mailbox_execute(
+            u32::from(CommandId::DISABLE_ATTESTATION),
+            payload.as_bytes(),
+        )
+        .unwrap()
+        .unwrap();
+
+    let resp_hdr = MailboxRespHeader::read_from(resp.as_bytes()).unwrap();
+    assert_eq!(
+        resp_hdr.fips_status,
+        MailboxRespHeader::FIPS_STATUS_APPROVED
+    );
+}
+
 #[test]
 fn test_ecdsa_verify_cmd() {
     let mut model = run_rom_test("mbox");