Repository: chipsalliance/caliptra-sw
Pull request #174 (2023-04-13 17:52:56)

[feat] IDEVID and FMCAlias ROM derivations Integration tests
This change contains tests for IDEVID and FMCAlias derivations.


Patch:
diff --git a/drivers/src/fuse_bank.rs b/drivers/src/fuse_bank.rs
index 4eb32349..6226483d 100644
--- a/drivers/src/fuse_bank.rs
+++ b/drivers/src/fuse_bank.rs
@@ -36,7 +36,7 @@ bitflags::bitflags! {
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
-enum IdevidCertAttr {
+pub enum IdevidCertAttr {
     Flags = 0,
     SubjectKeyId1 = 1,
     SubjectKeyId2 = 2,
diff --git a/drivers/src/lib.rs b/drivers/src/lib.rs
index bc5fb399..47305f38 100644
--- a/drivers/src/lib.rs
+++ b/drivers/src/lib.rs
@@ -34,7 +34,7 @@ mod sha1;
 mod sha256;
 mod sha384;
 mod sha384acc;
-mod state;
+pub mod state;
 mod status_reporter;
 
 pub type CaliptraResult<T> = Result<T, u32>;
@@ -53,7 +53,7 @@ pub use error_reporter::{
     report_hw_error_non_fatal,
 };
 pub use exit_ctrl::ExitCtrl;
-pub use fuse_bank::{FuseBank, VendorPubKeyRevocation, X509KeyIdAlgo};
+pub use fuse_bank::{FuseBank, IdevidCertAttr, VendorPubKeyRevocation, X509KeyIdAlgo};
 pub use hmac384::{Hmac384, Hmac384Data, Hmac384Key, Hmac384Op, Hmac384Tag};
 pub use key_vault::{KeyId, KeyUsage, KeyVault};
 pub use kv_access::{KeyReadArgs, KeyWriteArgs};
diff --git a/drivers/src/state.rs b/drivers/src/state.rs
index 97042308..b80d5016 100644
--- a/drivers/src/state.rs
+++ b/drivers/src/state.rs
@@ -67,7 +67,7 @@ impl DeviceState {
 
 bitflags::bitflags! {
     /// Manufacturing State
-    struct MfgFlags : u32 {
+    pub struct MfgFlags : u32 {
         /// Generate Initial Device Id Certificate Signing Request
        const GENERATE_IDEVID_CSR = 0x01;
     }
diff --git a/rom/dev/Cargo.toml b/rom/dev/Cargo.toml
index 1621df25..2907eb25 100644
--- a/rom/dev/Cargo.toml
+++ b/rom/dev/Cargo.toml
@@ -25,6 +25,7 @@ caliptra-image-gen = { path = "../../image/gen" }
 caliptra-image-openssl = { path = "../../image/openssl" }
 caliptra-image-elf = { path = "../../image/elf" }
 caliptra-image-fake-keys = { path = "../../image/fake-keys" }
+caliptra-image-types = { path = "../../image/types" }
 
 [features]
 riscv = []
diff --git a/rom/dev/src/flow/cold_reset/fmc_alias.rs b/rom/dev/src/flow/cold_reset/fmc_alias.rs
index bbd85ee8..e6fd6c8f 100644
--- a/rom/dev/src/flow/cold_reset/fmc_alias.rs
+++ b/rom/dev/src/flow/cold_reset/fmc_alias.rs
@@ -23,7 +23,7 @@ use caliptra_drivers::{
     Array4x12, CaliptraResult, ColdResetEntry4, ColdResetEntry48, Hmac384Data, Hmac384Key, KeyId,
     KeyReadArgs, MailboxRecvTxn, ResetReason, WarmResetEntry4, WarmResetEntry48,
 };
-use caliptra_image_types::ImageManifest;
+use caliptra_image_types::{ImageManifest, IMAGE_BYTE_SIZE};
 use caliptra_image_verify::{ImageVerificationInfo, ImageVerifier};
 use caliptra_x509::{FmcAliasCertTbs, FmcAliasCertTbsParams};
 use zerocopy::{AsBytes, FromBytes};
@@ -37,7 +37,8 @@ rom_err_def! {
     FmcAliasErr
     {
         CertVerify = 0x1,
-     ManifestReadFailure = 0x2,
+        ManifestReadFailure = 0x2,
+        InvalidImageSize = 0x3,
     }
 }
 
@@ -130,8 +131,11 @@ impl FmcAliasLayer {
                     continue;
                 }
 
-                // TODO: Add a check the image is not zero bytes and must be less
-                // than or equal to 128 KB
+                if txn.dlen() == 0 || txn.dlen() > IMAGE_BYTE_SIZE as u32 {
+                    cprintln!("Invalid Image of size {} bytes" txn.dlen());
+                    txn.complete(false)?;
+                    raise_err!(InvalidImageSize);
+                }
 
                 cprintln!("");
                 cprintln!("[afmc] Received Image of size {} bytes" txn.dlen());


Test patch:
diff --git a/rom/dev/tests/helpers.rs b/rom/dev/tests/helpers.rs
new file mode 100644
index 00000000..31f9d7e7
--- /dev/null
+++ b/rom/dev/tests/helpers.rs
@@ -0,0 +1,29 @@
+// Licensed under the Apache-2.0 license
+
+use caliptra_builder::{ImageOptions, APP_WITH_UART, FMC_WITH_UART, ROM_WITH_UART};
+use caliptra_hw_model::DefaultHwModel;
+use caliptra_hw_model::{BootParams, Fuses, InitParams, SecurityState};
+use caliptra_image_types::ImageBundle;
+
+pub fn build_hw_model_and_image_bundle(fuses: Fuses) -> (DefaultHwModel, ImageBundle) {
+    let rom = caliptra_builder::build_firmware_rom(&ROM_WITH_UART).unwrap();
+    let hw = caliptra_hw_model::new(BootParams {
+        init_params: InitParams {
+            rom: &rom,
+            security_state: SecurityState::from(fuses.life_cycle as u32),
+            ..Default::default()
+        },
+        fuses,
+        fw_image: None,
+    })
+    .unwrap();
+
+    let image_bundle = caliptra_builder::build_and_sign_image(
+        &FMC_WITH_UART,
+        &APP_WITH_UART,
+        ImageOptions::default(),
+    )
+    .unwrap();
+
+    (hw, image_bundle)
+}
diff --git a/rom/dev/tests/test_fmcalias_derivation.rs b/rom/dev/tests/test_fmcalias_derivation.rs
new file mode 100644
index 00000000..52aa6997
--- /dev/null
+++ b/rom/dev/tests/test_fmcalias_derivation.rs
@@ -0,0 +1,30 @@
+// Licensed under the Apache-2.0 license
+use caliptra_hw_model::{Fuses, HwModel};
+use caliptra_image_types::IMAGE_BYTE_SIZE;
+
+mod helpers;
+
+// [TODO] Use the error codes from the common library.
+const INVALID_IMAGE_SIZE: u32 = 0x02000003;
+
+#[test]
+fn test_zero_firmware_size() {
+    let (mut hw, _image_bundle) = helpers::build_hw_model_and_image_bundle(Fuses::default());
+    let mut output = vec![];
+
+    // Zero-sized firmware.
+    hw.upload_firmware(&[]).unwrap();
+    let result = hw.copy_output_until_non_fatal_error(INVALID_IMAGE_SIZE, &mut output);
+    assert!(result.is_ok());
+}
+
+#[test]
+fn test_firmware_gt_max_size() {
+    let (mut hw, _image_bundle) = helpers::build_hw_model_and_image_bundle(Fuses::default());
+    let mut output = vec![];
+
+    // Firmware size > 128 KB.
+    hw.upload_firmware(&vec![0u8; IMAGE_BYTE_SIZE + 1]).unwrap();
+    let result = hw.copy_output_until_non_fatal_error(INVALID_IMAGE_SIZE, &mut output);
+    assert!(result.is_ok());
+}
diff --git a/rom/dev/tests/test_idevid_derivation.rs b/rom/dev/tests/test_idevid_derivation.rs
new file mode 100644
index 00000000..2cf645ee
--- /dev/null
+++ b/rom/dev/tests/test_idevid_derivation.rs
@@ -0,0 +1,58 @@
+// Licensed under the Apache-2.0 license
+
+use caliptra_drivers::{state::MfgFlags, IdevidCertAttr, X509KeyIdAlgo};
+//use caliptra_drivers::{state::MfgFlags, IdevidCertAttr, X509KeyIdAlgo};
+use caliptra_hw_model::{Fuses, HwModel};
+
+mod helpers;
+
+#[track_caller]
+fn assert_output_contains(haystack: &str, needle: &str) {
+    assert!(
+        haystack.contains(needle),
+        "Expected substring in output not found: {needle}"
+    );
+}
+
+#[test]
+fn test_generate_csr() {
+    let mut output = vec![];
+    let (mut hw, image_bundle) = helpers::build_hw_model_and_image_bundle(Fuses::default());
+
+    // Set gen_idev_id_csr to generate CSR.
+    let flags = MfgFlags::GENERATE_IDEVID_CSR;
+    hw.soc_ifc()
+        .cptra_dbg_manuf_service_reg()
+        .write(|_| flags.bits());
+
+    #[cfg(feature = "verilator")]
+    {
+        // [TODO] Download the CSR from the mailbox and set the gen_idev_id_csr bit 0.
+    }
+
+    hw.step_until(|m| m.soc_ifc().cptra_flow_status().read().ready_for_fw());
+    hw.upload_firmware(&image_bundle.to_bytes().unwrap())
+        .unwrap();
+
+    let result = hw.copy_output_until_exit_success(&mut output);
+    assert!(result.is_ok());
+
+    let output = String::from_utf8_lossy(&output);
+    assert_output_contains(&output, "[idev] CSR uploaded");
+}
+
+#[test]
+fn test_idev_subj_key_id_algo() {
+    let mut output = vec![];
+    for algo in 0..(X509KeyIdAlgo::Fuse as u32 + 1) {
+        let mut fuses = Fuses::default();
+        fuses.idevid_cert_attr[IdevidCertAttr::Flags as usize] = algo;
+
+        let (mut hw, image_bundle) = helpers::build_hw_model_and_image_bundle(fuses);
+        hw.upload_firmware(&image_bundle.to_bytes().unwrap())
+            .unwrap();
+
+        let result = hw.copy_output_until_exit_success(&mut output);
+        assert!(result.is_ok());
+    }
+}
diff --git a/rom/dev/tests/test_image_validation.rs b/rom/dev/tests/test_image_validation.rs
index 14a9d3d1..8e1ab539 100644
--- a/rom/dev/tests/test_image_validation.rs
+++ b/rom/dev/tests/test_image_validation.rs
@@ -3,7 +3,7 @@
 use caliptra_builder::{ImageOptions, APP_WITH_UART, FMC_WITH_UART, ROM_WITH_UART};
 use caliptra_drivers::Array4x12;
 use caliptra_hw_model::{
-    BootParams, DefaultHwModel, DeviceLifecycle, Fuses, HwModel, InitParams, SecurityState, U4,
+    BootParams, DeviceLifecycle, Fuses, HwModel, InitParams, SecurityState, U4,
 };
 use caliptra_image_elf::ElfExecutable;
 use caliptra_image_fake_keys::{
@@ -14,6 +14,8 @@ use caliptra_image_openssl::OsslCrypto;
 use caliptra_image_types::{ImageBundle, ImageManifest, VENDOR_ECC_KEY_COUNT};
 use zerocopy::AsBytes;
 
+mod helpers;
+
 // [TODO] Use the error codes from the common library.
 const MANIFEST_MARKER_MISMATCH: u32 = 0x0B000001;
 const MANIFEST_SIZE_MISMATCH: u32 = 0x0B000002;
@@ -61,7 +63,7 @@ const SIGNATURE_S: [u8; 48] = [
 
 #[test]
 fn test_invalid_manifest_marker() {
-    let (mut hw, mut image_bundle) = build_hw_model_and_image_bundle(Fuses::default());
+    let (mut hw, mut image_bundle) = helpers::build_hw_model_and_image_bundle(Fuses::default());
     image_bundle.manifest.marker = 0xDEADBEEF;
     hw.upload_firmware(&image_bundle.to_bytes().unwrap())
         .unwrap();
@@ -72,7 +74,7 @@ fn test_invalid_manifest_marker() {
 
 #[test]
 fn test_invalid_manifest_size() {
-    let (mut hw, mut image_bundle) = build_hw_model_and_image_bundle(Fuses::default());
+    let (mut hw, mut image_bundle) = helpers::build_hw_model_and_image_bundle(Fuses::default());
     image_bundle.manifest.size = (core::mem::size_of::<ImageManifest>() - 1) as u32;
     hw.upload_firmware(&image_bundle.to_bytes().unwrap())
         .unwrap();
@@ -88,7 +90,7 @@ fn test_preamble_zero_vendor_pubkey_digest() {
         key_manifest_pk_hash: [0u32; 12],
         ..Default::default()
     };
-    let (mut hw, image_bundle) = build_hw_model_and_image_bundle(fuses);
+    let (mut hw, image_bundle) = helpers::build_hw_model_and_image_bundle(fuses);
     hw.upload_firmware(&image_bundle.to_bytes().unwrap())
         .unwrap();
     let mut output = vec![];
@@ -104,7 +106,7 @@ fn test_preamble_vendor_pubkey_digest_mismatch() {
         ..Default::default()
     };
 
-    let (mut hw, image_bundle) = build_hw_model_and_image_bundle(fuses);
+    let (mut hw, image_bundle) = helpers::build_hw_model_and_image_bundle(fuses);
     hw.upload_firmware(&image_bundle.to_bytes().unwrap())
         .unwrap();
     let mut output = vec![];
@@ -119,7 +121,7 @@ fn test_preamble_owner_pubkey_digest_mismatch() {
         ..Default::default()
     };
 
-    let (mut hw, image_bundle) = build_hw_model_and_image_bundle(fuses);
+    let (mut hw, image_bundle) = helpers::build_hw_model_and_image_bundle(fuses);
     hw.upload_firmware(&image_bundle.to_bytes().unwrap())
         .unwrap();
     let mut output = vec![];
@@ -183,7 +185,7 @@ fn test_preamble_vendor_pubkey_revocation() {
 #[test]
 fn test_preamble_vendor_pubkey_out_of_bounds() {
     let mut output = vec![];
-    let (mut hw, mut image_bundle) = build_hw_model_and_image_bundle(Fuses::default());
+    let (mut hw, mut image_bundle) = helpers::build_hw_model_and_image_bundle(Fuses::default());
     image_bundle.manifest.preamble.vendor_ecc_pub_key_idx = VENDOR_ECC_KEY_COUNT;
     hw.upload_firmware(&image_bundle.to_bytes().unwrap())
         .unwrap();
@@ -195,7 +197,7 @@ fn test_preamble_vendor_pubkey_out_of_bounds() {
 
 #[test]
 fn test_header_verify_vendor_sig_zero_pubkey() {
-    let (mut hw, mut image_bundle) = build_hw_model_and_image_bundle(Fuses::default());
+    let (mut hw, mut image_bundle) = helpers::build_hw_model_and_image_bundle(Fuses::default());
     let vendor_ecc_pub_key_idx = image_bundle.manifest.preamble.vendor_ecc_pub_key_idx as usize;
     let mut output = vec![];
 
@@ -230,7 +232,7 @@ fn test_header_verify_vendor_sig_zero_pubkey() {
 #[test]
 fn test_header_verify_vendor_sig_zero_signature() {
     let mut output = vec![];
-    let (mut hw, mut image_bundle) = build_hw_model_and_image_bundle(Fuses::default());
+    let (mut hw, mut image_bundle) = helpers::build_hw_model_and_image_bundle(Fuses::default());
 
     // Set vendor_sig.r to zero.
     let vendor_sig_r_backup = image_bundle.manifest.preamble.vendor_sigs.ecc_sig.r;
@@ -255,7 +257,7 @@ fn test_header_verify_vendor_sig_zero_signature() {
 
 #[test]
 fn test_header_verify_vendor_sig_mismatch() {
-    let (mut hw, mut image_bundle) = build_hw_model_and_image_bundle(Fuses::default());
+    let (mut hw, mut image_bundle) = helpers::build_hw_model_and_image_bundle(Fuses::default());
     let vendor_ecc_pub_key_idx = image_bundle.manifest.preamble.vendor_ecc_pub_key_idx as usize;
     let mut output = vec![];
 
@@ -301,7 +303,7 @@ fn test_header_verify_vendor_sig_mismatch() {
 
 #[test]
 fn test_header_verify_vendor_pub_key_in_preamble_and_header() {
-    let (mut hw, mut image_bundle) = build_hw_model_and_image_bundle(Fuses::default());
+    let (mut hw, mut image_bundle) = helpers::build_hw_model_and_image_bundle(Fuses::default());
     let mut output = vec![];
 
     // Change vendor pubkey index.
@@ -500,7 +502,7 @@ fn test_header_verify_owner_sig_zero_signature_s() {
 
 #[test]
 fn test_toc_invalid_entry_count() {
-    let (mut hw, mut image_bundle) = build_hw_model_and_image_bundle(Fuses::default());
+    let (mut hw, mut image_bundle) = helpers::build_hw_model_and_image_bundle(Fuses::default());
     let mut output = vec![];
 
     // Change the TOC length.
@@ -515,7 +517,7 @@ fn test_toc_invalid_entry_count() {
 
 #[test]
 fn test_toc_invalid_toc_digest() {
-    let (mut hw, mut image_bundle) = build_hw_model_and_image_bundle(Fuses::default());
+    let (mut hw, mut image_bundle) = helpers::build_hw_model_and_image_bundle(Fuses::default());
     let mut output = vec![];
 
     // Change the TOC digest.
@@ -533,7 +535,7 @@ fn test_toc_fmc_range_overlap() {
     let mut output = vec![];
 
     // Case 1: FMC offset == Runtime offset
-    let (mut hw, mut image_bundle) = build_hw_model_and_image_bundle(Fuses::default());
+    let (mut hw, mut image_bundle) = helpers::build_hw_model_and_image_bundle(Fuses::default());
     let fmc_new_offset = image_bundle.manifest.runtime.offset;
     // These are unchanged.
     let fmc_new_size = image_bundle.manifest.fmc.size;
@@ -552,7 +554,7 @@ fn test_toc_fmc_range_overlap() {
     assert!(result.is_ok());
 
     // Case 2: FMC offset > Runtime offset
-    let (mut hw, mut image_bundle) = build_hw_model_and_image_bundle(Fuses::default());
+    let (mut hw, mut image_bundle) = helpers::build_hw_model_and_image_bundle(Fuses::default());
     let fmc_new_offset = image_bundle.manifest.runtime.offset + 1;
     // These are unchanged.
     let fmc_new_size = image_bundle.manifest.fmc.size;
@@ -570,7 +572,7 @@ fn test_toc_fmc_range_overlap() {
     assert!(result.is_ok());
 
     // // Case 3: FMC start offset < Runtime offset < FMC end offset
-    let (mut hw, mut image_bundle) = build_hw_model_and_image_bundle(Fuses::default());
+    let (mut hw, mut image_bundle) = helpers::build_hw_model_and_image_bundle(Fuses::default());
     let runtime_new_offset = image_bundle.manifest.fmc.offset + 1;
     // These are unchanged.
     let fmc_new_offset = image_bundle.manifest.fmc.offset;
@@ -590,7 +592,7 @@ fn test_toc_fmc_range_overlap() {
 
 #[test]
 fn test_toc_fmc_range_incorrect_order() {
-    let (mut hw, mut image_bundle) = build_hw_model_and_image_bundle(Fuses::default());
+    let (mut hw, mut image_bundle) = helpers::build_hw_model_and_image_bundle(Fuses::default());
     let mut output = vec![];
     let fmc_new_offset = image_bundle.manifest.runtime.offset;
     let fmc_new_size = image_bundle.manifest.runtime.size;
@@ -611,7 +613,7 @@ fn test_toc_fmc_range_incorrect_order() {
 
 #[test]
 fn test_fmc_digest_mismatch() {
-    let (mut hw, mut image_bundle) = build_hw_model_and_image_bundle(Fuses::default());
+    let (mut hw, mut image_bundle) = helpers::build_hw_model_and_image_bundle(Fuses::default());
     let mut output = vec![];
 
     // Change the FMC image.
@@ -625,7 +627,7 @@ fn test_fmc_digest_mismatch() {
 
 #[test]
 fn test_runtime_digest_mismatch() {
-    let (mut hw, mut image_bundle) = build_hw_model_and_image_bundle(Fuses::default());
+    let (mut hw, mut image_bundle) = helpers::build_hw_model_and_image_bundle(Fuses::default());
     let mut output = vec![];
 
     // Change the FMC image.
@@ -686,26 +688,3 @@ fn update_fmc_runtime_ranges(
     image.extend_from_slice(&image_bundle.runtime);
     image
 }
-
-fn build_hw_model_and_image_bundle(fuses: Fuses) -> (DefaultHwModel, ImageBundle) {
-    let rom = caliptra_builder::build_firmware_rom(&ROM_WITH_UART).unwrap();
-    let hw = caliptra_hw_model::new(BootParams {
-        init_params: InitParams {
-            rom: &rom,
-            security_state: SecurityState::from(fuses.life_cycle as u32),
-            ..Default::default()
-        },
-        fuses,
-        fw_image: None,
-    })
-    .unwrap();
-
-    let image_bundle = caliptra_builder::build_and_sign_image(
-        &FMC_WITH_UART,
-        &APP_WITH_UART,
-        ImageOptions::default(),
-    )
-    .unwrap();
-
-    (hw, image_bundle)
-}