Repository: chipsalliance/caliptra-sw
Pull request #421 (2023-06-23 21:02:32)

Pass IDevID pub from ROM to RT
The IDevID public key is needed by the SoC to populate an IDevID cert template. Pass this from ROM so that runtime can expose it.


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index bcdb1e9e..2a0980a7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -548,7 +548,9 @@ dependencies = [
  "caliptra-registers",
  "caliptra-runtime",
  "caliptra-test-harness",
+ "caliptra_common",
  "cfg-if",
+ "zerocopy",
 ]
 
 [[package]]
diff --git a/common/src/hand_off.rs b/common/src/hand_off.rs
index 55ac6aea..f7a174df 100644
--- a/common/src/hand_off.rs
+++ b/common/src/hand_off.rs
@@ -271,8 +271,11 @@ pub struct FirmwareHandoffTable {
 
     pub rt_dice_sign: Ecc384Signature,
 
+    /// IDevID public key
+    pub idev_dice_pub_key: Ecc384PubKey,
+
     /// Reserved for future use.
-    pub reserved: [u8; 228],
+    pub reserved: [u8; 132],
 }
 
 impl Default for FirmwareHandoffTable {
@@ -299,13 +302,14 @@ impl Default for FirmwareHandoffTable {
             rt_svn_dv_hdl: FHT_INVALID_HANDLE,
             ldevid_tbs_size: 0,
             fmcalias_tbs_size: 0,
-            reserved: [0u8; 228],
+            reserved: [0u8; 132],
             ldevid_tbs_addr: 0,
             fmcalias_tbs_addr: 0,
             pcr_log_addr: 0,
             fuse_log_addr: 0,
             rt_dice_sign: Ecc384Signature::default(),
             rt_dice_pub_key: Ecc384PubKey::default(),
+            idev_dice_pub_key: Ecc384PubKey::default(),
         }
     }
 }
diff --git a/rom/dev/src/fht.rs b/rom/dev/src/fht.rs
index 191857ac..f8b74519 100644
--- a/rom/dev/src/fht.rs
+++ b/rom/dev/src/fht.rs
@@ -16,7 +16,9 @@ use caliptra_common::{
     DataVaultRegister, FirmwareHandoffTable, HandOffDataHandle, Vault, FHT_INVALID_HANDLE,
     FHT_MARKER,
 };
-use caliptra_drivers::{ColdResetEntry4, ColdResetEntry48, WarmResetEntry4, WarmResetEntry48};
+use caliptra_drivers::{
+    ColdResetEntry4, ColdResetEntry48, Ecc384PubKey, WarmResetEntry4, WarmResetEntry48,
+};
 use zerocopy::AsBytes;
 
 use crate::{
@@ -42,6 +44,9 @@ pub struct FhtDataStore {
 
     /// FmcAlias TBS size
     pub fmcalias_tbs_size: u16,
+
+    /// IDevID public key
+    pub idev_pub: Ecc384PubKey,
 }
 
 impl FhtDataStore {
@@ -173,6 +178,7 @@ pub fn make_fht(env: &RomEnv) -> FirmwareHandoffTable {
         fmcalias_tbs_addr,
         pcr_log_addr,
         fuse_log_addr,
+        idev_dice_pub_key: env.fht_data_store.idev_pub,
         ..Default::default()
     }
 }
diff --git a/rom/dev/src/flow/cold_reset/idev_id.rs b/rom/dev/src/flow/cold_reset/idev_id.rs
index 2f2d2e36..81abd7ee 100644
--- a/rom/dev/src/flow/cold_reset/idev_id.rs
+++ b/rom/dev/src/flow/cold_reset/idev_id.rs
@@ -94,6 +94,9 @@ impl InitDevIdLayer {
         // Generate the Initial DevID Certificate Signing Request (CSR)
         Self::generate_csr(env, &output)?;
 
+        // Write IDevID pub to FHT
+        env.fht_data_store.idev_pub = output.subj_key_pair.pub_key;
+
         cprintln!("[idev] --");
         report_boot_status(IDevIdDerivationComplete.into());
 
diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index 20f0dfcd..df148761 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -13,7 +13,7 @@ use mailbox::Mailbox;
 pub mod packet;
 use packet::Packet;
 
-use caliptra_common::cprintln;
+use caliptra_common::{cprintln, FirmwareHandoffTable};
 use caliptra_drivers::{CaliptraError, CaliptraResult, DataVault, Ecc384};
 use caliptra_registers::{
     dv::DvReg,
@@ -45,24 +45,26 @@ impl From<CommandId> for u32 {
     }
 }
 
-pub struct Drivers {
+pub struct Drivers<'a> {
     pub mbox: Mailbox,
     pub sha_acc: Sha512AccCsr,
     pub ecdsa: Ecc384,
     pub data_vault: DataVault,
+    pub fht: &'a mut FirmwareHandoffTable,
 }
-impl Drivers {
+impl<'a> Drivers<'a> {
     /// # Safety
     ///
     /// Callers must ensure that this function is called only once, and that
     /// any concurrent access to these register blocks does not conflict with
     /// these drivers.
-    pub unsafe fn new_from_registers() -> Self {
+    pub unsafe fn new_from_registers(fht: &'a mut FirmwareHandoffTable) -> Self {
         Self {
             mbox: Mailbox::new(MboxCsr::new()),
             sha_acc: Sha512AccCsr::new(),
             ecdsa: Ecc384::new(EccReg::new()),
             data_vault: DataVault::new(DvReg::new()),
+            fht,
         }
     }
 }
diff --git a/runtime/src/main.rs b/runtime/src/main.rs
index ae31fc06..3a204c48 100644
--- a/runtime/src/main.rs
+++ b/runtime/src/main.rs
@@ -35,9 +35,8 @@ const BANNER: &str = r#"
 #[no_mangle]
 pub extern "C" fn entry_point() -> ! {
     cprintln!("{}", BANNER);
-    let mut drivers = unsafe { Drivers::new_from_registers() };
-
-    if let Some(_fht) = caliptra_common::FirmwareHandoffTable::try_load() {
+    if let Some(mut fht) = caliptra_common::FirmwareHandoffTable::try_load() {
+        let mut drivers = unsafe { Drivers::new_from_registers(&mut fht) };
         cprintln!("Caliptra RT listening for mailbox commands...");
         caliptra_runtime::handle_mailbox_commands(&mut drivers);
 


Test patch:
diff --git a/runtime/test-fw/Cargo.toml b/runtime/test-fw/Cargo.toml
index 81b6b646..ab2a0195 100644
--- a/runtime/test-fw/Cargo.toml
+++ b/runtime/test-fw/Cargo.toml
@@ -42,4 +42,6 @@ caliptra-cpu = { version = "0.1.0", path = "../../cpu" }
 caliptra-registers = { path = "../../registers" }
 caliptra-runtime = { path = "..", default-features = false }
 caliptra-drivers = { path = "../../drivers" }
+caliptra_common = { path = "../../common", default-features = false }
 cfg-if = "1.0.0"
+zerocopy = "0.6.1"
diff --git a/runtime/test-fw/src/cert_tests.rs b/runtime/test-fw/src/cert_tests.rs
index 1fc21b20..1854d093 100644
--- a/runtime/test-fw/src/cert_tests.rs
+++ b/runtime/test-fw/src/cert_tests.rs
@@ -8,9 +8,11 @@
 use caliptra_registers::mbox::enums::MboxStatusE;
 use caliptra_runtime::{dice, Drivers};
 use caliptra_test_harness::{runtime_handlers, test_suite};
+use zerocopy::AsBytes;
 
 fn mbox_responder() {
-    let drivers = unsafe { Drivers::new_from_registers() };
+    let mut fht = caliptra_common::FirmwareHandoffTable::try_load().unwrap();
+    let drivers = unsafe { Drivers::new_from_registers(&mut fht) };
     let mut mbox = drivers.mbox;
 
     loop {
@@ -34,6 +36,12 @@ fn mbox_responder() {
                 mbox.write_response(&fmc).unwrap();
                 mbox.set_status(MboxStatusE::DataReady);
             }
+            // Send IDevID Public Key
+            0x3000_0000 => {
+                mbox.write_response(drivers.fht.idev_dice_pub_key.as_bytes())
+                    .unwrap();
+                mbox.set_status(MboxStatusE::DataReady);
+            }
             _ => {
                 mbox.set_status(MboxStatusE::CmdFailure);
             }
diff --git a/runtime/test-fw/src/mbox_tests.rs b/runtime/test-fw/src/mbox_tests.rs
index e7e55083..0f371bee 100644
--- a/runtime/test-fw/src/mbox_tests.rs
+++ b/runtime/test-fw/src/mbox_tests.rs
@@ -19,7 +19,8 @@ use caliptra_runtime::Drivers;
 use caliptra_test_harness::test_suite;
 
 fn test_mbox_cmd() {
-    let mut drivers = unsafe { Drivers::new_from_registers() };
+    let mut fht = caliptra_common::FirmwareHandoffTable::default();
+    let mut drivers = unsafe { Drivers::new_from_registers(&mut fht) };
     caliptra_runtime::handle_mailbox_commands(&mut drivers);
 }
 
diff --git a/runtime/tests/integration_tests.rs b/runtime/tests/integration_tests.rs
index 05137425..ff33162e 100644
--- a/runtime/tests/integration_tests.rs
+++ b/runtime/tests/integration_tests.rs
@@ -1,10 +1,17 @@
 // Licensed under the Apache-2.0 license.
 
 use caliptra_builder::{FwId, ImageOptions, APP_WITH_UART, FMC_WITH_UART, ROM_WITH_UART};
+use caliptra_drivers::Ecc384PubKey;
 use caliptra_hw_model::{BootParams, DefaultHwModel, HwModel, InitParams, ModelError, ShaAccMode};
 use caliptra_runtime::{CommandId, EcdsaVerifyCmd};
-use openssl::x509::X509;
-use zerocopy::AsBytes;
+use openssl::{
+    bn::BigNum,
+    ec::{EcGroup, EcKey},
+    nid::Nid,
+    pkey::PKey,
+    x509::X509,
+};
+use zerocopy::{AsBytes, FromBytes};
 
 // Run test_bin as a ROM image. The is used for faster tests that can run
 // against verilator
@@ -101,11 +108,23 @@ fn test_rom_certs() {
     let ldev_cert: X509 = X509::from_der(ldevid).unwrap();
     let fmc_cert: X509 = X509::from_der(fmc).unwrap();
 
+    let idev_resp = model.mailbox_execute(0x3000_0000, &[]).unwrap().unwrap();
+    let idev_pub = Ecc384PubKey::read_from(idev_resp.as_bytes()).unwrap();
+
     // Check the FMC is signed by LDevID
     assert!(fmc_cert.verify(&ldev_cert.public_key().unwrap()).unwrap());
 
-    // TODO: Check that LDevID is signed by IDevID
-    // Runtime does not currently have access to the IDevID public key.
+    // Check the LDevID is signed by IDevID
+    let group = EcGroup::from_curve_name(Nid::SECP384R1).unwrap();
+    let x_bytes: [u8; 48] = idev_pub.x.into();
+    let y_bytes: [u8; 48] = idev_pub.y.into();
+    let idev_x = &BigNum::from_slice(&x_bytes).unwrap();
+    let idev_y = &BigNum::from_slice(&y_bytes).unwrap();
+
+    let idev_ec_key = EcKey::from_public_key_affine_coordinates(&group, idev_x, idev_y).unwrap();
+    assert!(ldev_cert
+        .verify(&PKey::from_ec_key(idev_ec_key).unwrap())
+        .unwrap());
 }
 
 #[test]