diff --git a/Cargo.lock b/Cargo.lock index 88d6869a1b..c6c3c17d96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -378,6 +378,7 @@ dependencies = [ "caliptra-lms-types", "caliptra-registers", "caliptra-test", + "caliptra_common", "cfg-if 1.0.0", "dpe", "openssl", @@ -950,6 +951,7 @@ dependencies = [ "caliptra-registers", "ufmt", "zerocopy", + "zeroize", ] [[package]] diff --git a/common/Cargo.toml b/common/Cargo.toml index 2264dd310a..a22acdb58d 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -17,6 +17,7 @@ caliptra-api.workspace = true caliptra-registers.workspace = true ufmt.workspace = true zerocopy.workspace = true +zeroize.workspace = true [features] default = ["std"] diff --git a/common/src/crypto.rs b/common/src/crypto.rs index 009f4b4433..c743f3ff9b 100644 --- a/common/src/crypto.rs +++ b/common/src/crypto.rs @@ -11,13 +11,103 @@ Abstract: Crypto helper routines --*/ -use caliptra_drivers::{Ecc384PubKey, KeyId}; -/// DICE Layer Key Pair -#[derive(Debug)] +use caliptra_drivers::{ + Array4x12, Array4x8, CaliptraResult, Ecc384PubKey, Hmac, HmacMode, KeyId, KeyReadArgs, + KeyUsage, KeyWriteArgs, Mldsa87PubKey, Sha256, Sha256Alg, Sha2_512_384, Trng, +}; +use zeroize::Zeroize; + +/// DICE Layer ECC Key Pair +#[derive(Debug, Zeroize)] pub struct Ecc384KeyPair { - /// Private Key + /// Private Key KV Slot Id + #[zeroize(skip)] pub priv_key: KeyId, /// Public Key pub pub_key: Ecc384PubKey, } + +/// DICE Layer MLDSA Key Pair +#[derive(Debug, Zeroize)] +pub struct MlDsaKeyPair { + /// Key Pair Generation KV Slot Id + #[zeroize(skip)] + pub key_pair_seed: KeyId, + + /// Public Key + pub pub_key: Mldsa87PubKey, +} + +#[derive(Debug)] +pub enum PubKey<'a> { + Ecc(&'a Ecc384PubKey), + Mldsa(&'a Mldsa87PubKey), +} + +/// Calculate SHA2-256 Digest +/// +/// # Arguments +/// +/// * `sha256` - SHA256 driver +/// * `data` - Input data to hash +/// +/// # Returns +/// +/// * `Array4x8` - Digest +pub fn sha256_digest(sha256: &mut Sha256, data: &[u8]) -> CaliptraResult { + sha256.digest(data) +} + +/// Calculate SHA2-384 Digest +/// +/// # Arguments +/// +/// * `sha2_512_384` - SHA2-512-384 driver +/// * `data` - Input data to hash +/// +/// # Returns +/// +/// * `Array4x12` - Digest +pub fn sha384_digest(sha2_512_384: &mut Sha2_512_384, data: &[u8]) -> CaliptraResult { + sha2_512_384.sha384_digest(data) +} + +/// Calculate HMAC KDF +/// +/// # Arguments +/// +/// * `hmac` - HMAC driver +/// * `trng` - TRNG driver +/// * `key` - HMAC key slot +/// * `label` - Input label +/// * `context` - Input context +/// * `output` - Key slot to store the output +/// * `mode` - HMAC Mode +#[inline(always)] +pub fn hmac_kdf( + hmac: &mut Hmac, + trng: &mut Trng, + key: KeyId, + label: &[u8], + context: Option<&[u8]>, + output: KeyId, + mode: HmacMode, +) -> CaliptraResult<()> { + caliptra_drivers::hmac_kdf( + hmac, + KeyReadArgs::new(key).into(), + label, + context, + trng, + KeyWriteArgs::new( + output, + KeyUsage::default() + .set_hmac_key_en() + .set_ecc_key_gen_seed_en() + .set_mldsa_key_gen_seed_en(), + ) + .into(), + mode, + ) +} diff --git a/common/src/keyids.rs b/common/src/keyids.rs index eb55d6c150..3c4c693d49 100644 --- a/common/src/keyids.rs +++ b/common/src/keyids.rs @@ -34,10 +34,12 @@ pub const KEY_ID_FMC_MLDSA_KEYPAIR_SEED: KeyId = KeyId::KeyId8; #[cfg(feature = "fmc")] pub const KEY_ID_RT_CDI: KeyId = KeyId::KeyId4; #[cfg(feature = "fmc")] -pub const KEY_ID_RT_PRIV_KEY: KeyId = KeyId::KeyId5; +pub const KEY_ID_RT_ECDSA_PRIV_KEY: KeyId = KeyId::KeyId5; +#[cfg(feature = "fmc")] +pub const KEY_ID_RT_MLDSA_KEYPAIR_SEED: KeyId = KeyId::KeyId9; #[cfg(feature = "runtime")] -pub const KEY_ID_DPE_CDI: KeyId = KeyId::KeyId8; +pub const KEY_ID_DPE_CDI: KeyId = KeyId::KeyId10; #[cfg(feature = "runtime")] -pub const KEY_ID_DPE_PRIV_KEY: KeyId = KeyId::KeyId9; +pub const KEY_ID_DPE_PRIV_KEY: KeyId = KeyId::KeyId11; pub const KEY_ID_TMP: KeyId = KeyId::KeyId3; diff --git a/common/src/lib.rs b/common/src/lib.rs index 71c515490f..c017b6afbf 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -16,6 +16,7 @@ pub mod fips; pub mod keyids; pub mod verifier; pub mod wdt; +pub mod x509; ///merge imports pub use hand_off::{ @@ -38,7 +39,7 @@ pub use fuse::{FuseLogEntry, FuseLogEntryId}; pub use pcr::{PcrLogEntry, PcrLogEntryId, RT_FW_CURRENT_PCR, RT_FW_JOURNEY_PCR}; pub const FMC_ORG: u32 = 0x40000000; -pub const FMC_SIZE: u32 = 20 * 1024; +pub const FMC_SIZE: u32 = 21 * 1024; pub const RUNTIME_ORG: u32 = FMC_ORG + FMC_SIZE; pub const RUNTIME_SIZE: u32 = 98 * 1024; diff --git a/common/src/x509.rs b/common/src/x509.rs new file mode 100644 index 0000000000..68d04df0df --- /dev/null +++ b/common/src/x509.rs @@ -0,0 +1,166 @@ +/*++ + +Licensed under the Apache-2.0 license. + +File Name: + + x509.rs + +Abstract: + + File contains X509 Certificate & CSR related utility functions + +--*/ +use crate::crypto::{self, PubKey}; +use caliptra_drivers::*; +use core::mem::size_of; +use core::usize; +use zerocopy::AsBytes; + +/// X509 API +pub enum X509 {} + +impl X509 { + /// Get device serial number + /// + /// # Arguments + /// + /// * `soc_ifc` - SOC Interface object + /// + /// # Returns + /// + /// `[u8; 17]` - Byte 0 - Ueid Type, Bytes 1-16 Unique Endpoint Identifier + pub fn ueid(soc_ifc: &SocIfc) -> CaliptraResult<[u8; 17]> { + let ueid = soc_ifc.fuse_bank().ueid(); + Ok(ueid) + } + + /// Get public key bytes. Reverses the endianness of each dword in the public key. + /// + /// # Arguments + /// + /// * `pub_key` - ECC or MLDSA Public Key + /// * `pub_key_bytes` - Buffer to hold the public key bytes + /// + /// # Returns + /// + /// `usize` - Number of bytes written to the buffer + #[inline(always)] + #[allow(clippy::cast_ptr_alignment)] + pub fn get_pubkey_bytes(pub_key: &PubKey, pub_key_bytes: &mut [u8]) -> usize { + fn copy_and_swap_endianess(src: &[u8], dst: &mut [u8]) { + for i in (0..src.len()).step_by(4) { + if i + 3 < src.len() && i + 3 < dst.len() { + dst[i] = src[i + 3]; + dst[i + 1] = src[i + 2]; + dst[i + 2] = src[i + 1]; + dst[i + 3] = src[i]; + } + } + } + + match pub_key { + PubKey::Ecc(pub_key) => { + let ecc_pubkey_der = pub_key.to_der(); + pub_key_bytes[..ecc_pubkey_der.len()].copy_from_slice(&ecc_pubkey_der); + ecc_pubkey_der.len() + } + PubKey::Mldsa(pub_key) => { + // pub_key is in Caliptra Hw format (big-endian DWORDs). Convert it to little-endian DWORDs. + copy_and_swap_endianess(pub_key.0.as_bytes(), pub_key_bytes); + pub_key_bytes.len() + } + } + } + + fn pub_key_digest(sha256: &mut Sha256, pub_key: &PubKey) -> CaliptraResult { + // Define an array large enough to hold the largest public key. + let mut pub_key_bytes: [u8; size_of::()] = [0; size_of::()]; + let pub_key_size = Self::get_pubkey_bytes(pub_key, &mut pub_key_bytes); + crypto::sha256_digest(sha256, &pub_key_bytes[..pub_key_size]) + } + + /// Get X509 Subject Serial Number from public key + /// + /// # Arguments + /// + /// * `sha256` - SHA256 Driver + /// * `pub_key` - ECC or MLDSA Public Key + /// + /// # Returns + /// + /// `[u8; 64]` - X509 Subject Identifier serial number + pub fn subj_sn(sha256: &mut Sha256, pub_key: &PubKey) -> CaliptraResult<[u8; 64]> { + let digest = Self::pub_key_digest(sha256, pub_key); + let digest = okref(&digest)?; + Ok(Self::hex(&digest.into())) + } + + /// Get Cert Subject Key Identifier + /// + /// # Arguments + /// + /// * `sha256` - SHA256 Driver + /// * `pub_key` - Public Key + /// + /// # Returns + /// + /// `[u8; 20]` - X509 Subject Key Identifier + pub fn subj_key_id(sha256: &mut Sha256, pub_key: &PubKey) -> CaliptraResult<[u8; 20]> { + let digest = Self::pub_key_digest(sha256, pub_key); + let digest: [u8; 32] = okref(&digest)?.into(); + Ok(digest[..20].try_into().unwrap()) + } + + /// Get Serial Number for ECC certificate. + /// + /// # Arguments + /// + /// * `sha256` - SHA256 Driver + /// * `pub_key` - ECC Public Key + /// + /// # Returns + /// + /// `[u8; 20]` - X509 Serial Number + pub fn ecc_cert_sn(sha256: &mut Sha256, pub_key: &Ecc384PubKey) -> CaliptraResult<[u8; 20]> { + let data = pub_key.to_der(); + let digest = crypto::sha256_digest(sha256, &data); + let mut digest: [u8; 32] = okref(&digest)?.into(); + + // Ensure the encoded integer is positive, and that the first octet + // is non-zero (otherwise it will be considered padding, and the integer + // will fail to parse if the MSB of the second octet is zero). + digest[0] &= !0x80; + digest[0] |= 0x04; + + Ok(digest[..20].try_into().unwrap()) + } + + /// Return the hex representation of the input `buf` + /// + /// # Arguments + /// + /// `buf` - Buffer + /// + /// # Returns + /// + /// `[u8; 64]` - Hex representation of the buffer + fn hex(buf: &[u8; 32]) -> [u8; 64] { + fn ch(byte: u8) -> u8 { + match byte & 0x0F { + b @ 0..=9 => 48 + b, + b @ 10..=15 => 55 + b, + _ => unreachable!(), + } + } + + let mut hex = [0u8; 64]; + + for (index, byte) in buf.iter().enumerate() { + hex[index << 1] = ch((byte & 0xF0) >> 4); + hex[(index << 1) + 1] = ch(byte & 0x0F); + } + + hex + } +} diff --git a/drivers/Cargo.toml b/drivers/Cargo.toml index f04aaeb264..4602772b84 100644 --- a/drivers/Cargo.toml +++ b/drivers/Cargo.toml @@ -45,3 +45,4 @@ caliptra-hw-model-types.workspace = true caliptra-hw-model.workspace = true caliptra-test.workspace = true openssl.workspace = true +caliptra_common.workspace = true diff --git a/drivers/src/data_vault.rs b/drivers/src/data_vault.rs index 613bca4245..2a2e2aee45 100644 --- a/drivers/src/data_vault.rs +++ b/drivers/src/data_vault.rs @@ -130,6 +130,24 @@ impl DataVault { self.cold_reset_entries.fmc_ecc_pk } + /// Set the fmc MLDSA public key. + /// + /// # Arguments + /// * `pub_key` - fmc MLDSA public key + /// + pub fn set_fmc_mldsa_pub_key(&mut self, pub_key: &Mldsa87PubKey) { + self.cold_reset_entries.fmc_mldsa_pk = *pub_key; + } + + /// Get the fmc MLDSA public key. + /// + /// # Returns + /// * fmc MLDSA public key + /// + pub fn fmc_mldsa_pub_key(&self) -> Mldsa87PubKey { + self.cold_reset_entries.fmc_mldsa_pk + } + /// Set the fmc tcb component identifier. /// /// # Arguments diff --git a/drivers/src/hand_off.rs b/drivers/src/hand_off.rs index 7be38b65ac..8a8ac7202e 100644 --- a/drivers/src/hand_off.rs +++ b/drivers/src/hand_off.rs @@ -115,7 +115,7 @@ impl From for HandOffDataHandle { } } -const FHT_RESERVED_SIZE: usize = 1680; +const FHT_RESERVED_SIZE: usize = 1676; /// The Firmware Handoff Table is a data structure that is resident at a well-known /// location in DCCM. It is initially populated by ROM and modified by FMC as a way @@ -147,7 +147,10 @@ pub struct FirmwareHandoffTable { pub fmc_cdi_kv_hdl: HandOffDataHandle, /// Index of FMC Private Alias Key in the Key Vault. - pub fmc_priv_key_kv_hdl: HandOffDataHandle, + pub fmc_ecc_priv_key_kv_hdl: HandOffDataHandle, + + /// Index of FMC Alias MLDSA key pair generation seed in the Key Vault. + pub fmc_mldsa_keypair_seed_kv_hdl: HandOffDataHandle, /// Index of RT CDI value in the Key Vault. pub rt_cdi_kv_hdl: HandOffDataHandle, @@ -219,7 +222,8 @@ impl Default for FirmwareHandoffTable { manifest_load_addr: FHT_INVALID_ADDRESS, fips_fw_load_addr_hdl: FHT_INVALID_HANDLE, fmc_cdi_kv_hdl: FHT_INVALID_HANDLE, - fmc_priv_key_kv_hdl: FHT_INVALID_HANDLE, + fmc_ecc_priv_key_kv_hdl: FHT_INVALID_HANDLE, + fmc_mldsa_keypair_seed_kv_hdl: FHT_INVALID_HANDLE, rt_cdi_kv_hdl: FHT_INVALID_HANDLE, rt_priv_key_kv_hdl: FHT_INVALID_HANDLE, ldevid_tbs_addr: 0, @@ -258,8 +262,12 @@ pub fn print_fht(fht: &FirmwareHandoffTable) { ); crate::cprintln!("FMC CDI KV Handle: 0x{:08x}", fht.fmc_cdi_kv_hdl.0); crate::cprintln!( - "FMC Private Key KV Handle: 0x{:08x}", - fht.fmc_priv_key_kv_hdl.0 + "FMC ECC Private Key KV Handle: 0x{:08x}", + fht.fmc_ecc_priv_key_kv_hdl.0 + ); + crate::cprintln!( + "FMC MLDSA Key Pair Generation Seed KV Handle: 0x{:08x}", + fht.fmc_mldsa_keypair_seed_kv_hdl.0 ); crate::cprintln!("RT CDI KV Handle: 0x{:08x}", fht.rt_cdi_kv_hdl.0); crate::cprintln!( @@ -321,17 +329,31 @@ mod tests { use core::mem; const FHT_SIZE: usize = 2048; const KEY_ID_FMC_ECDSA_PRIV_KEY: KeyId = KeyId::KeyId7; + const KEY_ID_FMC_MLDSA_KEYPAIR_SEED: KeyId = KeyId::KeyId8; - fn fmc_priv_key_store() -> HandOffDataHandle { + fn fmc_ecc_priv_key_store() -> HandOffDataHandle { HandOffDataHandle(((Vault::KeyVault as u32) << 12) | KEY_ID_FMC_ECDSA_PRIV_KEY as u32) } - fn fmc_priv_key(fht: &FirmwareHandoffTable) -> KeyId { - let ds: DataStore = fht.fmc_priv_key_kv_hdl.try_into().unwrap(); + fn fmc_ecc_priv_key(fht: &FirmwareHandoffTable) -> KeyId { + let ds: DataStore = fht.fmc_ecc_priv_key_kv_hdl.try_into().unwrap(); match ds { DataStore::KeyVaultSlot(key_id) => key_id, - _ => panic!("Invalid FMC private key store"), + _ => panic!("Invalid FMC ECC private key store"), + } + } + + fn fmc_mldsa_keypair_seed_store() -> HandOffDataHandle { + HandOffDataHandle(((Vault::KeyVault as u32) << 12) | KEY_ID_FMC_MLDSA_KEYPAIR_SEED as u32) + } + + fn fmc_mldsa_keypair_seed_key(fht: &FirmwareHandoffTable) -> KeyId { + let ds: DataStore = fht.fmc_mldsa_keypair_seed_kv_hdl.try_into().unwrap(); + + match ds { + DataStore::KeyVaultSlot(key_id) => key_id, + _ => panic!("Invalid FMC key pair generation seed store"), } } @@ -358,19 +380,42 @@ mod tests { } #[test] - fn test_fmc_priv_key_store() { + fn test_fmc_ecc_priv_key_store() { let fht = crate::hand_off::FirmwareHandoffTable { - fmc_priv_key_kv_hdl: fmc_priv_key_store(), + fmc_ecc_priv_key_kv_hdl: fmc_ecc_priv_key_store(), ..Default::default() }; // Check that the key is stored in the KeyVault. - assert_eq!(fht.fmc_priv_key_kv_hdl.vault(), Vault::KeyVault as u32); + assert_eq!(fht.fmc_ecc_priv_key_kv_hdl.vault(), Vault::KeyVault as u32); // Check the key slot is correct assert_eq!( - fht.fmc_priv_key_kv_hdl.reg_num(), + fht.fmc_ecc_priv_key_kv_hdl.reg_num(), KEY_ID_FMC_ECDSA_PRIV_KEY.into() ); - assert_eq!(fmc_priv_key(&fht), KEY_ID_FMC_ECDSA_PRIV_KEY); + assert_eq!(fmc_ecc_priv_key(&fht), KEY_ID_FMC_ECDSA_PRIV_KEY); + } + + #[test] + fn test_fmc_mldsa_keypair_seed_store() { + let fht = crate::hand_off::FirmwareHandoffTable { + fmc_mldsa_keypair_seed_kv_hdl: fmc_mldsa_keypair_seed_store(), + ..Default::default() + }; + // Check that the key is stored in the KeyVault. + assert_eq!( + fht.fmc_mldsa_keypair_seed_kv_hdl.vault(), + Vault::KeyVault as u32 + ); + // Check the key slot is correct + assert_eq!( + fht.fmc_mldsa_keypair_seed_kv_hdl.reg_num(), + KEY_ID_FMC_MLDSA_KEYPAIR_SEED.into() + ); + + assert_eq!( + fmc_mldsa_keypair_seed_key(&fht), + KEY_ID_FMC_MLDSA_KEYPAIR_SEED + ); } } diff --git a/drivers/src/key_vault.rs b/drivers/src/key_vault.rs index 72b7db7635..88af938d34 100644 --- a/drivers/src/key_vault.rs +++ b/drivers/src/key_vault.rs @@ -111,16 +111,16 @@ bitfield! { /// Flag indicating if the key can be used as HMAC data pub hmac_data, set_hmac_data: 1; - /// Flag indicating if the key can be used as MLDSA seed - pub mldsa_seed, set_mldsa_seed: 2; + /// Flag indicating if the key can be used as MLDSA Key Generation seed + pub mldsa_seed, set_mldsa_key_gen_seed: 2; - /// Flag indicating if the key can be used aas ECC Private Key + /// Flag indicating if the key can be used as ECC Private Key pub ecc_private_key, set_ecc_private_key: 3; - /// Flag indicating if the key can be used aas ECC Key Generation Seed + /// Flag indicating if the key can be used as ECC Key Generation Seed pub ecc_key_gen_seed, set_ecc_key_gen_seed: 4; - /// Flag indicating if the key can be used aas ECC data part of signature + /// Flag indicating if the key can be used as ECC data part of signature /// generation and verification process pub ecc_data, set_ecc_data:5; } @@ -134,8 +134,8 @@ impl KeyUsage { self.set_hmac_data(true); *self } - pub fn set_mldsa_seed_en(&mut self) -> KeyUsage { - self.set_mldsa_seed(true); + pub fn set_mldsa_key_gen_seed_en(&mut self) -> KeyUsage { + self.set_mldsa_key_gen_seed(true); *self } pub fn set_ecc_private_key_en(&mut self) -> KeyUsage { diff --git a/drivers/test-fw/src/bin/mldsa87_tests.rs b/drivers/test-fw/src/bin/mldsa87_tests.rs index 68d9756970..4c5d285477 100644 --- a/drivers/test-fw/src/bin/mldsa87_tests.rs +++ b/drivers/test-fw/src/bin/mldsa87_tests.rs @@ -414,7 +414,7 @@ fn test_gen_key_pair() { let mut hmac = unsafe { Hmac::new(HmacReg::new()) }; let key_out_1 = KeyWriteArgs { id: KEY_ID, - usage: KeyUsage::default().set_mldsa_seed_en(), + usage: KeyUsage::default().set_mldsa_key_gen_seed_en(), }; hmac.hmac( diff --git a/fmc/src/flow/crypto.rs b/fmc/src/flow/crypto.rs index e59530700b..928e75c713 100644 --- a/fmc/src/flow/crypto.rs +++ b/fmc/src/flow/crypto.rs @@ -7,92 +7,36 @@ Abstract: --*/ use crate::fmc_env::FmcEnv; use caliptra_cfi_derive::cfi_impl_fn; -use caliptra_common::{crypto::Ecc384KeyPair, keyids::KEY_ID_TMP}; +use caliptra_common::{ + crypto::{self, Ecc384KeyPair, MlDsaKeyPair}, + keyids::KEY_ID_TMP, +}; use caliptra_drivers::{ - hmac_kdf, okref, Array4x12, Array4x5, Array4x8, CaliptraResult, Ecc384PrivKeyIn, - Ecc384PrivKeyOut, Ecc384PubKey, Ecc384Result, Ecc384Signature, HmacMode, KeyId, KeyReadArgs, - KeyUsage, KeyWriteArgs, Sha256Alg, + okref, Array4x12, CaliptraResult, Ecc384PrivKeyIn, Ecc384PrivKeyOut, Ecc384PubKey, + Ecc384Result, Ecc384Signature, HmacMode, KeyId, KeyReadArgs, KeyUsage, KeyWriteArgs, }; pub enum Crypto {} impl Crypto { - /// Calculate SHA1 Digest - /// - /// # Arguments - /// - /// * `env` - FMC Environment - /// * `data` - Input data to hash - /// - /// # Returns - /// - /// * `Array4x5` - Digest - pub fn _sha1_digest(env: &mut FmcEnv, data: &[u8]) -> CaliptraResult { - env.sha1.digest(data) - } - - /// Calculate SHA2-256 Digest - /// - /// # Arguments - /// - /// * `env` - Fmc Environment - /// * `data` - Input data to hash - /// - /// # Returns - /// - /// * `Array4x8` - Digest - #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] + /// Version of hmac_kdf() that takes a FmcEnv. #[inline(always)] - pub fn sha256_digest(env: &mut FmcEnv, data: &[u8]) -> CaliptraResult { - env.sha256.digest(data) - } - - /// Calculate SHA2-384 Digest - /// - /// # Arguments - /// - /// * `env` - FMC Environment - /// * `data` - Input data to hash - /// - /// # Returns - /// - /// * `Array4x12` - Digest - #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] - pub fn sha384_digest(env: &mut FmcEnv, data: &[u8]) -> CaliptraResult { - env.sha2_512_384.sha384_digest(data) - } - - /// Calculate HMAC-384 KDF - /// - /// # Arguments - /// - /// * `env` - FMC Environment - /// * `key` - HMAC384 key slot - /// * `label` - Input label - /// * `context` - Input context - /// * `output` - Key slot to store the output - #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] - pub fn hmac384_kdf( + pub fn env_hmac_kdf( env: &mut FmcEnv, key: KeyId, label: &[u8], context: Option<&[u8]>, output: KeyId, + mode: HmacMode, ) -> CaliptraResult<()> { - hmac_kdf( - &mut env.hmac384, - KeyReadArgs::new(key).into(), + crypto::hmac_kdf( + &mut env.hmac, + &mut env.trng, + key, label, context, - &mut env.trng, - KeyWriteArgs::new( - output, - KeyUsage::default() - .set_hmac_key_en() - .set_ecc_key_gen_seed_en(), - ) - .into(), - HmacMode::Hmac384, + output, + mode, ) } @@ -115,7 +59,7 @@ impl Crypto { label: &[u8], priv_key: KeyId, ) -> CaliptraResult { - Crypto::hmac384_kdf(env, cdi, label, None, KEY_ID_TMP)?; + Crypto::env_hmac_kdf(env, cdi, label, None, KEY_ID_TMP, HmacMode::Hmac512)?; let key_out = Ecc384PrivKeyOut::Key(KeyWriteArgs::new( priv_key, @@ -156,7 +100,7 @@ impl Crypto { pub_key: &Ecc384PubKey, data: &[u8], ) -> CaliptraResult { - let digest = Self::sha384_digest(env, data); + let digest = crypto::sha384_digest(&mut env.sha2_512_384, data); let digest = okref(&digest)?; let priv_key_args = KeyReadArgs::new(priv_key); let priv_key = Ecc384PrivKeyIn::Key(priv_key_args); @@ -184,8 +128,42 @@ impl Crypto { data: &[u8], sig: &Ecc384Signature, ) -> CaliptraResult { - let digest = Self::sha384_digest(env, data); + let digest = crypto::sha384_digest(&mut env.sha2_512_384, data); let digest = okref(&digest)?; env.ecc384.verify(pub_key, digest, sig) } + + /// Generate MLDSA Key Pair + /// + /// # Arguments + /// + /// * `env` - FMC Environment + /// * `cdi` - Key slot to retrieve the CDI from + /// * `label` - Diversification label + /// * `key_pair_seed` - Key slot to store the keypair generation seed. + /// + /// # Returns + /// + /// * `MlDsaKeyPair` - Public Key and keypair generation seed + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] + #[inline(always)] + pub fn mldsa_key_gen( + env: &mut FmcEnv, + cdi: KeyId, + label: &[u8], + key_pair_seed: KeyId, + ) -> CaliptraResult { + // Generate the seed for key pair generation. + Crypto::env_hmac_kdf(env, cdi, label, None, key_pair_seed, HmacMode::Hmac512)?; + + // Generate the public key. + let pub_key = env + .mldsa + .key_pair(&KeyReadArgs::new(key_pair_seed), &mut env.trng)?; + + Ok(MlDsaKeyPair { + key_pair_seed, + pub_key, + }) + } } diff --git a/fmc/src/flow/dice.rs b/fmc/src/flow/dice.rs index f57e462ae8..0ba87eee8a 100644 --- a/fmc/src/flow/dice.rs +++ b/fmc/src/flow/dice.rs @@ -15,7 +15,7 @@ Abstract: use caliptra_drivers::KeyId; -use caliptra_common::crypto::Ecc384KeyPair; +use caliptra_common::crypto::{Ecc384KeyPair, MlDsaKeyPair}; /// DICE Layer Input #[derive(Debug)] @@ -28,13 +28,22 @@ pub struct DiceInput { pub cdi: KeyId, /// Authority Key Pair - pub auth_key_pair: Ecc384KeyPair, + pub ecc_auth_key_pair: Ecc384KeyPair, /// Authority Serial Number - pub auth_sn: [u8; 64], + pub ecc_auth_sn: [u8; 64], /// Authority Key Identifier - pub auth_key_id: [u8; 20], + pub ecc_auth_key_id: [u8; 20], + + /// MLDSA Authority Key Pair + pub mldsa_auth_key_pair: MlDsaKeyPair, + + /// MLDSA Authority Serial Number + pub mldsa_auth_sn: [u8; 64], + + /// MLDSA Authority Key Identifier + pub mldsa_auth_key_id: [u8; 20], } /// DICE Layer Output @@ -42,12 +51,22 @@ pub struct DiceInput { pub struct DiceOutput { /// CDI pub cdi: KeyId, + /// Subject key pair for this layer - pub subj_key_pair: Ecc384KeyPair, + pub ecc_subj_key_pair: Ecc384KeyPair, /// Subject Serial Number - pub subj_sn: [u8; 64], + pub ecc_subj_sn: [u8; 64], /// Subject Key Identifier - pub subj_key_id: [u8; 20], + pub ecc_subj_key_id: [u8; 20], + + /// MLDSA Subject key pair for this layer + pub mldsa_subj_key_pair: MlDsaKeyPair, + + /// MLDSA Subject Serial Number + pub mldsa_subj_sn: [u8; 64], + + /// MLDSA Subject Key Identifier + pub mldsa_subj_key_id: [u8; 20], } diff --git a/fmc/src/flow/mod.rs b/fmc/src/flow/mod.rs index 5e5d44712d..86bb74a3e6 100644 --- a/fmc/src/flow/mod.rs +++ b/fmc/src/flow/mod.rs @@ -17,7 +17,6 @@ pub mod dice; mod pcr; mod rt_alias; mod tci; -mod x509; use crate::flow::rt_alias::RtAliasLayer; diff --git a/fmc/src/flow/rt_alias.rs b/fmc/src/flow/rt_alias.rs index 816316b2b7..1dfc557154 100644 --- a/fmc/src/flow/rt_alias.rs +++ b/fmc/src/flow/rt_alias.rs @@ -13,22 +13,24 @@ Abstract: --*/ use caliptra_cfi_derive::cfi_impl_fn; use caliptra_cfi_lib::{cfi_assert, cfi_assert_bool, cfi_assert_eq, cfi_launder}; +use caliptra_common::x509::X509; use crate::flow::crypto::Crypto; use crate::flow::dice::{DiceInput, DiceOutput}; use crate::flow::pcr::extend_pcr_common; use crate::flow::tci::Tci; -use crate::flow::x509::X509; use crate::fmc_env::FmcEnv; use crate::FmcBootStatus; use crate::HandOff; use caliptra_common::cprintln; -use caliptra_common::crypto::Ecc384KeyPair; -use caliptra_common::keyids::{KEY_ID_RT_CDI, KEY_ID_RT_PRIV_KEY, KEY_ID_TMP}; +use caliptra_common::crypto::{Ecc384KeyPair, MlDsaKeyPair, PubKey}; +use caliptra_common::keyids::{ + KEY_ID_RT_CDI, KEY_ID_RT_ECDSA_PRIV_KEY, KEY_ID_RT_MLDSA_KEYPAIR_SEED, KEY_ID_TMP, +}; use caliptra_common::HexBytes; use caliptra_drivers::{ - okref, report_boot_status, CaliptraError, CaliptraResult, Ecc384Result, KeyId, PersistentData, - ResetReason, + okref, report_boot_status, CaliptraError, CaliptraResult, Ecc384Result, HmacMode, KeyId, + PersistentData, ResetReason, }; use caliptra_x509::{NotAfter, NotBefore, RtAliasCertTbs, RtAliasCertTbsParams}; @@ -45,24 +47,32 @@ impl RtAliasLayer { return Err(CaliptraError::FMC_CDI_KV_COLLISION); } - if Self::kv_slot_collides(input.auth_key_pair.priv_key) { + if Self::kv_slot_collides(input.ecc_auth_key_pair.priv_key) + || Self::kv_slot_collides(input.mldsa_auth_key_pair.key_pair_seed) + { return Err(CaliptraError::FMC_ALIAS_KV_COLLISION); } cprintln!("[alias rt] Derive CDI"); - cprintln!("[alias rt] Store in in slot 0x{:x}", KEY_ID_RT_CDI as u8); + cprintln!("[alias rt] Store it in slot 0x{:x}", KEY_ID_RT_CDI as u8); // Derive CDI Self::derive_cdi(env, input.cdi, KEY_ID_RT_CDI)?; report_boot_status(FmcBootStatus::RtAliasDeriveCdiComplete as u32); cprintln!("[alias rt] Derive Key Pair"); cprintln!( - "[alias rt] Store priv key in slot 0x{:x}", - KEY_ID_RT_PRIV_KEY as u8 + "[alias rt] Store ECC priv key in slot 0x{:x} and MLDSA key pair seed in slot 0x{:x}", + KEY_ID_RT_ECDSA_PRIV_KEY as u8, + KEY_ID_RT_MLDSA_KEYPAIR_SEED as u8, ); - // Derive DICE Key Pair from CDI - let key_pair = Self::derive_key_pair(env, KEY_ID_RT_CDI, KEY_ID_RT_PRIV_KEY)?; + // Derive DICE ECC and MLDSA Key Pairs from CDI + let (ecc_key_pair, mldsa_key_pair) = Self::derive_key_pair( + env, + KEY_ID_RT_CDI, + KEY_ID_RT_ECDSA_PRIV_KEY, + KEY_ID_RT_MLDSA_KEYPAIR_SEED, + )?; cprintln!("[alias rt] Derive Key Pair - Done"); report_boot_status(FmcBootStatus::RtAliasKeyPairDerivationComplete as u32); @@ -70,18 +80,26 @@ impl RtAliasLayer { // // This information will be used by next DICE Layer while generating // certificates - let subj_sn = X509::subj_sn(env, &key_pair.pub_key)?; + let ecc_subj_sn = X509::subj_sn(&mut env.sha256, &PubKey::Ecc(&ecc_key_pair.pub_key))?; + let mldsa_subj_sn = + X509::subj_sn(&mut env.sha256, &PubKey::Mldsa(&mldsa_key_pair.pub_key))?; report_boot_status(FmcBootStatus::RtAliasSubjIdSnGenerationComplete.into()); - let subj_key_id = X509::subj_key_id(env, &key_pair.pub_key)?; + let ecc_subj_key_id = + X509::subj_key_id(&mut env.sha256, &PubKey::Ecc(&ecc_key_pair.pub_key))?; + let mldsa_subj_key_id = + X509::subj_key_id(&mut env.sha256, &PubKey::Mldsa(&mldsa_key_pair.pub_key))?; report_boot_status(FmcBootStatus::RtAliasSubjKeyIdGenerationComplete.into()); // Generate the output for next layer let output = DiceOutput { cdi: KEY_ID_RT_CDI, - subj_key_pair: key_pair, - subj_sn, - subj_key_id, + ecc_subj_key_pair: ecc_key_pair, + ecc_subj_sn, + ecc_subj_key_id, + mldsa_subj_key_pair: mldsa_key_pair, + mldsa_subj_sn, + mldsa_subj_key_id, }; let manifest = &env.persistent_data.get().manifest1; @@ -94,7 +112,10 @@ impl RtAliasLayer { } fn kv_slot_collides(slot: KeyId) -> bool { - slot == KEY_ID_RT_CDI || slot == KEY_ID_RT_PRIV_KEY || slot == KEY_ID_TMP + slot == KEY_ID_RT_CDI + || slot == KEY_ID_RT_ECDSA_PRIV_KEY + || slot == KEY_ID_RT_MLDSA_KEYPAIR_SEED + || slot == KEY_ID_TMP } #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] @@ -134,18 +155,30 @@ impl RtAliasLayer { /// /// * `DiceInput` - DICE Layer Input fn dice_input_from_hand_off(env: &mut FmcEnv) -> CaliptraResult { - let auth_pub = HandOff::fmc_pub_key(env); - let auth_serial_number = X509::subj_sn(env, &auth_pub)?; - let auth_key_id = X509::subj_key_id(env, &auth_pub)?; + let ecc_auth_pub = HandOff::fmc_ecc_pub_key(env); + let ecc_auth_sn = X509::subj_sn(&mut env.sha256, &PubKey::Ecc(&ecc_auth_pub))?; + let ecc_auth_key_id = X509::subj_key_id(&mut env.sha256, &PubKey::Ecc(&ecc_auth_pub))?; + + let mldsa_auth_pub = HandOff::fmc_mldsa_pub_key(env); + let mldsa_auth_sn = X509::subj_sn(&mut env.sha256, &PubKey::Mldsa(&mldsa_auth_pub))?; + let mldsa_auth_key_id = + X509::subj_key_id(&mut env.sha256, &PubKey::Mldsa(&mldsa_auth_pub))?; + // Create initial output let input = DiceInput { cdi: HandOff::fmc_cdi(env), - auth_key_pair: Ecc384KeyPair { - priv_key: HandOff::fmc_priv_key(env), - pub_key: auth_pub, + ecc_auth_key_pair: Ecc384KeyPair { + priv_key: HandOff::fmc_ecc_priv_key(env), + pub_key: ecc_auth_pub, }, - auth_sn: auth_serial_number, - auth_key_id, + mldsa_auth_key_pair: MlDsaKeyPair { + key_pair_seed: HandOff::fmc_mldsa_keypair_seed_key(env), + pub_key: mldsa_auth_pub, + }, + ecc_auth_sn, + ecc_auth_key_id, + mldsa_auth_sn, + mldsa_auth_key_id, }; Ok(input) @@ -227,7 +260,14 @@ impl RtAliasLayer { tci[SHA384_HASH_SIZE..2 * SHA384_HASH_SIZE].copy_from_slice(&image_manifest_digest); // Permute CDI from FMC TCI - Crypto::hmac384_kdf(env, fmc_cdi, b"rt_alias_cdi", Some(&tci), rt_cdi)?; + Crypto::env_hmac_kdf( + env, + fmc_cdi, + b"alias_rt_cdi", + Some(&tci), + rt_cdi, + HmacMode::Hmac512, + )?; report_boot_status(FmcBootStatus::RtAliasDeriveCdiComplete as u32); Ok(()) } @@ -236,27 +276,39 @@ impl RtAliasLayer { /// /// # Arguments /// - /// * `env` - Fmc Environment - /// * `cdi` - Composite Device Identity - /// * `priv_key` - Key slot to store the private key into + /// * `env` - Fmc Environment + /// * `cdi` - Composite Device Identity + /// * `ecc_priv_key` - Key slot to store the ECC private key into + /// * `mldsa_keypair_seed` - Key slot to store the MLDSA key pair seed /// /// # Returns /// - /// * `Ecc384KeyPair` - Derive DICE Layer Key Pair + /// * `(Ecc384KeyPair, MlDsaKeyPair)` - DICE Layer ECC and MLDSA Key Pairs #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] fn derive_key_pair( env: &mut FmcEnv, cdi: KeyId, - priv_key: KeyId, - ) -> CaliptraResult { - let result = Crypto::ecc384_key_gen(env, cdi, b"rt_alias_keygen", priv_key); + ecc_priv_key: KeyId, + mldsa_keypair_seed: KeyId, + ) -> CaliptraResult<(Ecc384KeyPair, MlDsaKeyPair)> { + let result = Crypto::ecc384_key_gen(env, cdi, b"alias_rt_ecc_key", ecc_priv_key); if cfi_launder(result.is_ok()) { cfi_assert!(result.is_ok()); } else { cfi_assert!(result.is_err()); } + let ecc_keypair = result?; - result + // Derive the MLDSA Key Pair. + let result = Crypto::mldsa_key_gen(env, cdi, b"alias_rt_mldsa_key", mldsa_keypair_seed); + if cfi_launder(result.is_ok()) { + cfi_assert!(result.is_ok()); + } else { + cfi_assert!(result.is_err()); + } + let mldsa_keypair = result?; + + Ok((ecc_keypair, mldsa_keypair)) } /// Generate Local Device ID Certificate Signature @@ -274,11 +326,27 @@ impl RtAliasLayer { not_before: &[u8; RtAliasCertTbsParams::NOT_BEFORE_LEN], not_after: &[u8; RtAliasCertTbsParams::NOT_AFTER_LEN], ) -> CaliptraResult<()> { - let auth_priv_key = input.auth_key_pair.priv_key; - let auth_pub_key = &input.auth_key_pair.pub_key; - let pub_key = &output.subj_key_pair.pub_key; + Self::generate_ecc_cert_sig(env, input, output, not_before, not_after)?; + Self::generate_mldsa_cert_sig(env, input, output, not_before, not_after)?; + + report_boot_status(FmcBootStatus::RtAliasCertSigGenerationComplete as u32); + + Ok(()) + } + + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] + fn generate_ecc_cert_sig( + env: &mut FmcEnv, + input: &DiceInput, + output: &DiceOutput, + not_before: &[u8; RtAliasCertTbsParams::NOT_BEFORE_LEN], + not_after: &[u8; RtAliasCertTbsParams::NOT_AFTER_LEN], + ) -> CaliptraResult<()> { + let auth_priv_key = input.ecc_auth_key_pair.priv_key; + let auth_pub_key = &input.ecc_auth_key_pair.pub_key; + let pub_key = &output.ecc_subj_key_pair.pub_key; - let serial_number = &X509::cert_sn(env, pub_key)?; + let serial_number = &X509::ecc_cert_sn(&mut env.sha256, pub_key)?; let rt_tci: [u8; 48] = HandOff::rt_tci(env).into(); let rt_svn = HandOff::rt_svn(env) as u8; @@ -286,11 +354,11 @@ impl RtAliasLayer { // Certificate `To Be Signed` Parameters let params = RtAliasCertTbsParams { // Do we need the UEID here? - ueid: &X509::ueid(env)?, - subject_sn: &output.subj_sn, - subject_key_id: &output.subj_key_id, - issuer_sn: &input.auth_sn, - authority_key_id: &input.auth_key_id, + ueid: &X509::ueid(&env.soc_ifc)?, + subject_sn: &output.ecc_subj_sn, + subject_key_id: &output.ecc_subj_key_id, + issuer_sn: &input.ecc_auth_sn, + authority_key_id: &input.ecc_auth_key_id, serial_number, public_key: &pub_key.to_der(), not_before, @@ -305,19 +373,16 @@ impl RtAliasLayer { // Sign the `To Be Signed` portion cprintln!( - "[alias rt] Signing Cert with AUTHO - RITY.KEYID = {}", + "[alias rt] Signing ECC Cert with AUTHORITY.KEYID = {}", auth_priv_key as u8 ); // Sign the AliasRt To Be Signed DER Blob with AliasFMC Private Key in Key Vault Slot 7 - // AliasRtTbsDigest = sha384_digest(AliasRtTbs) AliaRtTbsCertSig = ecc384_sign(KvSlot5, AliasFmcTbsDigest) - let sig = Crypto::ecdsa384_sign(env, auth_priv_key, auth_pub_key, tbs.tbs()); let sig = okref(&sig)?; // Clear the authority private key cprintln!( - "[alias rt] Erasing AUTHORITY.KEYID = {}", + "[alias rt] Erasing ECC AUTHORITY.KEYID = {}", auth_priv_key as u8 ); // FMC ensures that CDIFMC and PrivateKeyFMC are locked to block further usage until the next boot. @@ -326,13 +391,13 @@ impl RtAliasLayer { let _pub_x: [u8; 48] = (&pub_key.x).into(); let _pub_y: [u8; 48] = (&pub_key.y).into(); - cprintln!("[alias rt] PUB.X = {}", HexBytes(&_pub_x)); - cprintln!("[alias rt] PUB.Y = {}", HexBytes(&_pub_y)); + cprintln!("[alias rt] ECC PUB.X = {}", HexBytes(&_pub_x)); + cprintln!("[alias rt] ECC PUB.Y = {}", HexBytes(&_pub_y)); let _sig_r: [u8; 48] = (&sig.r).into(); let _sig_s: [u8; 48] = (&sig.s).into(); - cprintln!("[alias rt] SIG.R = {}", HexBytes(&_sig_r)); - cprintln!("[alias rt] SIG.S = {}", HexBytes(&_sig_s)); + cprintln!("[alias rt] ECC SIG.R = {}", HexBytes(&_sig_r)); + cprintln!("[alias rt] ECC SIG.S = {}", HexBytes(&_sig_s)); // Verify the signature of the `To Be Signed` portion if Crypto::ecdsa384_verify(env, auth_pub_key, tbs.tbs(), sig)? != Ecc384Result::Success { @@ -345,8 +410,18 @@ impl RtAliasLayer { Self::copy_tbs(tbs.tbs(), env.persistent_data.get_mut())?; HandOff::set_rtalias_tbs_size(env, tbs.tbs().len()); - report_boot_status(FmcBootStatus::RtAliasCertSigGenerationComplete as u32); + Ok(()) + } + #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] + fn generate_mldsa_cert_sig( + _env: &mut FmcEnv, + _input: &DiceInput, + _output: &DiceOutput, + _not_before: &[u8; RtAliasCertTbsParams::NOT_BEFORE_LEN], + _not_after: &[u8; RtAliasCertTbsParams::NOT_AFTER_LEN], + ) -> CaliptraResult<()> { + // [TODO][CAP2] Create MLDSA RtAliasCertTbsParams Ok(()) } diff --git a/fmc/src/flow/tci.rs b/fmc/src/flow/tci.rs index f5ac359f5b..be22799e38 100644 --- a/fmc/src/flow/tci.rs +++ b/fmc/src/flow/tci.rs @@ -16,8 +16,8 @@ Environment: --*/ -use crate::flow::crypto::Crypto; use crate::fmc_env::FmcEnv; +use caliptra_common::crypto; use caliptra_drivers::{Array4x12, CaliptraResult}; use zerocopy::AsBytes; @@ -31,6 +31,6 @@ impl Tci { /// * `env` - ROM Environment pub fn image_manifest_digest(env: &mut FmcEnv) -> CaliptraResult { let manifest = env.persistent_data.get().manifest1; - Crypto::sha384_digest(env, manifest.as_bytes()) + crypto::sha384_digest(&mut env.sha2_512_384, manifest.as_bytes()) } } diff --git a/fmc/src/flow/x509.rs b/fmc/src/flow/x509.rs deleted file mode 100644 index 154af1ddd5..0000000000 --- a/fmc/src/flow/x509.rs +++ /dev/null @@ -1,123 +0,0 @@ -/*++ - -Licensed under the Apache-2.0 license. - -File Name: - - x509.rs - -Abstract: - - File contains X509 Certificate & CSR related utility functions - ---*/ -use super::crypto::Crypto; -use crate::fmc_env::FmcEnv; -use caliptra_drivers::*; - -/// X509 API -pub enum X509 {} - -impl X509 { - /// Get X509 Subject Serial Number - /// - /// # Arguments - /// - /// * `env` - FMC Environment - /// * `pub_key` - Public Key - /// - /// # Returns - /// - /// `[u8; 64]` - X509 Subject Identifier serial number - pub fn subj_sn(env: &mut FmcEnv, pub_key: &Ecc384PubKey) -> CaliptraResult<[u8; 64]> { - let data = pub_key.to_der(); - let digest = Crypto::sha256_digest(env, &data); - let digest = okref(&digest)?; - Ok(Self::hex(&digest.into())) - } - - /// Get Cert Subject Key Identifier - /// - /// # Arguments - /// - /// * `env` - FMC Environment - /// * `pub_key` - Public Key - /// - /// # Returns - /// - /// `[u8; 20]` - X509 Subject Key Identifier - pub fn subj_key_id(env: &mut FmcEnv, pub_key: &Ecc384PubKey) -> CaliptraResult<[u8; 20]> { - let data = pub_key.to_der(); - let digest = Crypto::sha256_digest(env, &data); - let digest: [u8; 32] = okref(&digest)?.into(); - let mut out = [0u8; 20]; - out.copy_from_slice(&digest[..20]); - Ok(out) - } - - /// Get Cert Serial Number - /// - /// # Arguments - /// - /// * `env` - ROM Environment - /// * `pub_key` - Public Key - /// - /// # Returns - /// - /// `[u8; 20]` - X509 Serial Number - pub fn cert_sn(env: &mut FmcEnv, pub_key: &Ecc384PubKey) -> CaliptraResult<[u8; 20]> { - let data = pub_key.to_der(); - let digest = Crypto::sha256_digest(env, &data); - let mut digest: [u8; 32] = okref(&digest)?.into(); - - // Ensure the encoded integer is positive, and that the first octet - // is non-zero (otherwise it will be considered padding, and the integer - // will fail to parse if the MSB of the second octet is zero). - digest[0] &= !0x80; - digest[0] |= 0x04; - - Ok(digest[..20].try_into().unwrap()) - } - - /// Get device serial number - /// - /// # Arguments - /// - /// * `env` - ROM Environment - /// - /// # Returns - /// - /// `[u8; 17]` - Byte 0 - Ueid Type, Bytes 1-16 Unique Endpoint Identifier - pub fn ueid(env: &FmcEnv) -> CaliptraResult<[u8; 17]> { - let ueid = env.soc_ifc.fuse_bank().ueid(); - Ok(ueid) - } - - /// Return the hex representation of the input `buf` - /// - /// # Arguments - /// - /// `buf` - Buffer - /// - /// # Returns - /// - /// `[u8; 64]` - Hex representation of the buffer - fn hex(buf: &[u8; 32]) -> [u8; 64] { - fn ch(byte: u8) -> u8 { - match byte & 0x0F { - b @ 0..=9 => 48 + b, - b @ 10..=15 => 55 + b, - _ => unreachable!(), - } - } - - let mut hex = [0u8; 64]; - - for (index, byte) in buf.iter().enumerate() { - hex[index << 1] = ch((byte & 0xF0) >> 4); - hex[(index << 1) + 1] = ch(byte & 0x0F); - } - - hex - } -} diff --git a/fmc/src/fmc_env.rs b/fmc/src/fmc_env.rs index 8f94f5cd06..646e395f59 100644 --- a/fmc/src/fmc_env.rs +++ b/fmc/src/fmc_env.rs @@ -16,13 +16,13 @@ Abstract: --*/ use caliptra_drivers::{ - CaliptraResult, Ecc384, Hmac, KeyVault, Mailbox, PcrBank, PersistentDataAccessor, Sha1, Sha256, - Sha2_512_384, Sha2_512_384Acc, SocIfc, Trng, + CaliptraResult, Ecc384, Hmac, KeyVault, Mailbox, Mldsa87, PcrBank, PersistentDataAccessor, + Sha1, Sha256, Sha2_512_384, Sha2_512_384Acc, SocIfc, Trng, }; use caliptra_registers::{ csrng::CsrngReg, 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, + mbox::MboxCsr, mldsa::MldsaReg, pv::PvReg, sha256::Sha256Reg, sha512::Sha512Reg, + sha512_acc::Sha512AccCsr, soc_ifc::SocIfcReg, soc_ifc_trng::SocIfcTrngReg, }; /// Hardware Context @@ -39,8 +39,8 @@ pub struct FmcEnv { // SHA2-512/384 Accelerator pub sha2_512_384_acc: Sha2_512_384Acc, - /// Hmac384 Engine - pub hmac384: Hmac, + /// Hmac Engine + pub hmac: Hmac, /// Ecc384 Engine pub ecc384: Ecc384, @@ -62,6 +62,9 @@ pub struct FmcEnv { /// Persistent Data pub persistent_data: PersistentDataAccessor, + + /// Mldsa87 Engine + pub mldsa: Mldsa87, } impl FmcEnv { @@ -85,7 +88,7 @@ impl FmcEnv { sha256: Sha256::new(Sha256Reg::new()), sha2_512_384: Sha2_512_384::new(Sha512Reg::new()), sha2_512_384_acc: Sha2_512_384Acc::new(Sha512AccCsr::new()), - hmac384: Hmac::new(HmacReg::new()), + hmac: Hmac::new(HmacReg::new()), ecc384: Ecc384::new(EccReg::new()), key_vault: KeyVault::new(KvReg::new()), soc_ifc: SocIfc::new(SocIfcReg::new()), @@ -93,6 +96,7 @@ impl FmcEnv { pcr_bank: PcrBank::new(PvReg::new()), trng, persistent_data: PersistentDataAccessor::new(), + mldsa: Mldsa87::new(MldsaReg::new()), }) } } diff --git a/fmc/src/hand_off.rs b/fmc/src/hand_off.rs index 8e56298805..ccfaf6ce03 100644 --- a/fmc/src/hand_off.rs +++ b/fmc/src/hand_off.rs @@ -16,8 +16,8 @@ use crate::fmc_env::FmcEnv; use caliptra_cfi_derive::cfi_impl_fn; use caliptra_common::{handle_fatal_error, DataStore::*}; use caliptra_common::{DataStore, FirmwareHandoffTable, HandOffDataHandle, Vault}; -use caliptra_drivers::Ecc384PubKey; use caliptra_drivers::{cprintln, memory_layout, Array4x12, Ecc384Signature, KeyId}; +use caliptra_drivers::{Ecc384PubKey, Mldsa87PubKey}; use caliptra_error::{CaliptraError, CaliptraResult}; #[cfg(feature = "riscv")] @@ -69,25 +69,59 @@ impl HandOff { /// Get the fmc ECC public key. /// /// # Returns - /// * fmc public key + /// * fmc ECC public key /// - pub fn fmc_pub_key(env: &FmcEnv) -> Ecc384PubKey { + pub fn fmc_ecc_pub_key(env: &FmcEnv) -> Ecc384PubKey { env.persistent_data.get().data_vault.fmc_ecc_pub_key() } - /// Retrieve FMC Alias Private Key - pub fn fmc_priv_key(env: &FmcEnv) -> KeyId { + /// Get the fmc MLDSA public key. + /// + /// # Returns + /// * fmc MLDSA public key + /// + pub fn fmc_mldsa_pub_key(env: &FmcEnv) -> Mldsa87PubKey { + env.persistent_data.get().data_vault.fmc_mldsa_pub_key() + } + + /// Retrieve FMC Alias ECC Private Key + pub fn fmc_ecc_priv_key(env: &FmcEnv) -> KeyId { + let ds: DataStore = Self::fht(env) + .fmc_ecc_priv_key_kv_hdl + .try_into() + .unwrap_or_else(|e: CaliptraError| { + cprintln!("[fht] Invalid FMC Alias ECC Private Key KV handle"); + handle_fatal_error(e.into()) + }); + + match ds { + KeyVaultSlot(key_id) => { + cprintln!("[fht] FMC Alias ECC Private Key: {:?}", u32::from(key_id)); + key_id + } + _ => { + cprintln!("[fht] Invalid KeySlot DV Entry"); + handle_fatal_error(CaliptraError::FMC_HANDOFF_INVALID_PARAM.into()) + } + } + } + + /// Retrieve FMC Alias MLDSA KeyPair Seed KV Slot + pub fn fmc_mldsa_keypair_seed_key(env: &FmcEnv) -> KeyId { let ds: DataStore = Self::fht(env) - .fmc_priv_key_kv_hdl + .fmc_mldsa_keypair_seed_kv_hdl .try_into() .unwrap_or_else(|e: CaliptraError| { - cprintln!("[fht] Invalid FMC ALias Private Key KV handle"); + cprintln!("[fht] Invalid FMC Alias MLDSA Key Pair Seed KV handle"); handle_fatal_error(e.into()) }); match ds { KeyVaultSlot(key_id) => { - cprintln!("[fht] FMC Alias Private Key: {:?}", u32::from(key_id)); + cprintln!( + "[fht] FMC Alias MLDSA Key Pair Seed KV Slot: {:?}", + u32::from(key_id) + ); key_id } _ => { @@ -151,8 +185,9 @@ impl HandOff { pub fn update(env: &mut FmcEnv, out: DiceOutput) -> CaliptraResult<()> { // update fht.rt_cdi_kv_hdl Self::fht_mut(env).rt_cdi_kv_hdl = Self::key_id_to_handle(out.cdi); - Self::fht_mut(env).rt_priv_key_kv_hdl = Self::key_id_to_handle(out.subj_key_pair.priv_key); - Self::fht_mut(env).rt_dice_pub_key = out.subj_key_pair.pub_key; + Self::fht_mut(env).rt_priv_key_kv_hdl = + Self::key_id_to_handle(out.ecc_subj_key_pair.priv_key); + Self::fht_mut(env).rt_dice_pub_key = out.ecc_subj_key_pair.pub_key; Ok(()) } diff --git a/fmc/src/main.rs b/fmc/src/main.rs index 5f4a0023a8..318986d313 100644 --- a/fmc/src/main.rs +++ b/fmc/src/main.rs @@ -18,7 +18,7 @@ use core::hint::black_box; use caliptra_cfi_lib::{cfi_assert_eq, CfiCounter}; use caliptra_common::{ cprintln, handle_fatal_error, - keyids::{KEY_ID_RT_CDI, KEY_ID_RT_PRIV_KEY}, + keyids::{KEY_ID_RT_CDI, KEY_ID_RT_ECDSA_PRIV_KEY}, }; use caliptra_cpu::{log_trap_record, TrapRecord}; @@ -79,7 +79,7 @@ pub extern "C" fn entry_point() -> ! { env.persistent_data.get_mut().fht.rt_cdi_kv_hdl = HandOffDataHandle::from(DataStore::KeyVaultSlot(KEY_ID_RT_CDI)); env.persistent_data.get_mut().fht.rt_priv_key_kv_hdl = - HandOffDataHandle::from(DataStore::KeyVaultSlot(KEY_ID_RT_PRIV_KEY)); + HandOffDataHandle::from(DataStore::KeyVaultSlot(KEY_ID_RT_ECDSA_PRIV_KEY)); HandOff::to_rt(&env); } match flow::run(&mut env) { diff --git a/rom/dev/src/crypto.rs b/rom/dev/src/crypto.rs index 13a721e037..1b9f2ef707 100644 --- a/rom/dev/src/crypto.rs +++ b/rom/dev/src/crypto.rs @@ -13,9 +13,10 @@ Abstract: --*/ use crate::rom_env::RomEnv; -#[cfg(not(feature = "no-cfi"))] -use caliptra_cfi_derive::cfi_impl_fn; -use caliptra_common::keyids::KEY_ID_TMP; +use caliptra_common::{ + crypto::{self, Ecc384KeyPair, MlDsaKeyPair}, + keyids::KEY_ID_TMP, +}; use caliptra_drivers::*; use caliptra_x509::Ecdsa384Signature; use zeroize::Zeroize; @@ -37,34 +38,6 @@ impl Ecdsa384SignatureAdapter for Ecc384Signature { } } -/// DICE Layer ECC Key Pair -#[derive(Debug, Zeroize)] -pub struct Ecc384KeyPair { - /// Private Key KV Slot Id - #[zeroize(skip)] - pub priv_key: KeyId, - - /// Public Key - pub pub_key: Ecc384PubKey, -} - -/// DICE Layer MLDSA Key Pair -#[derive(Debug, Zeroize)] -pub struct MlDsaKeyPair { - /// Key Pair Generation KV Slot Id - #[zeroize(skip)] - pub key_pair_seed: KeyId, - - /// Public Key - pub pub_key: Mldsa87PubKey, -} - -#[derive(Debug)] -pub enum PubKey<'a> { - Ecc(&'a Ecc384PubKey), - Mldsa(&'a Mldsa87PubKey), -} - pub enum Crypto {} impl Crypto { @@ -83,36 +56,6 @@ impl Crypto { env.sha1.digest(data) } - /// Calculate SHA2-256 Digest - /// - /// # Arguments - /// - /// * `sha256` - SHA256 driver - /// * `data` - Input data to hash - /// - /// # Returns - /// - /// * `Array4x8` - Digest - #[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)] - pub fn sha256_digest(sha256: &mut Sha256, data: &[u8]) -> CaliptraResult { - sha256.digest(data) - } - - /// Calculate SHA2-384 Digest - /// - /// # Arguments - /// - /// * `env` - ROM Environment - /// * `data` - Input data to hash - /// - /// # Returns - /// - /// * `Array4x12` - Digest - #[inline(always)] - pub fn sha384_digest(env: &mut RomEnv, data: &[u8]) -> CaliptraResult { - env.sha2_512_384.sha384_digest(data) - } - /// Calculate SHA2-512 Digest /// /// # Arguments @@ -154,7 +97,8 @@ impl Crypto { tag, KeyUsage::default() .set_hmac_key_en() - .set_ecc_key_gen_seed_en(), + .set_ecc_key_gen_seed_en() + .set_mldsa_key_gen_seed_en(), ) .into(), mode, @@ -192,7 +136,7 @@ impl Crypto { KeyUsage::default() .set_hmac_key_en() .set_ecc_key_gen_seed_en() - .set_mldsa_seed_en(), + .set_mldsa_key_gen_seed_en(), ) .into(), mode, @@ -281,7 +225,7 @@ impl Crypto { pub_key: &Ecc384PubKey, data: &[u8], ) -> CaliptraResult { - let mut digest = Self::sha384_digest(env, data); + let mut digest = crypto::sha384_digest(&mut env.sha2_512_384, data); let digest = okmutref(&mut digest)?; let priv_key_args = KeyReadArgs::new(priv_key); let priv_key = Ecc384PrivKeyIn::Key(priv_key_args); diff --git a/rom/dev/src/fht.rs b/rom/dev/src/fht.rs index 4d396ebb65..997e675f2c 100644 --- a/rom/dev/src/fht.rs +++ b/rom/dev/src/fht.rs @@ -16,7 +16,7 @@ use crate::{rom_env::RomEnv, CALIPTRA_ROM_INFO}; #[cfg(not(feature = "no-cfi"))] use caliptra_cfi_derive::cfi_mod_fn; use caliptra_common::{ - keyids::{KEY_ID_FMC_ECDSA_PRIV_KEY, KEY_ID_ROM_FMC_CDI}, + keyids::{KEY_ID_FMC_ECDSA_PRIV_KEY, KEY_ID_FMC_MLDSA_KEYPAIR_SEED, KEY_ID_ROM_FMC_CDI}, FirmwareHandoffTable, HandOffDataHandle, Vault, FHT_INVALID_HANDLE, FHT_MARKER, }; use caliptra_drivers::{cprintln, RomAddr}; @@ -32,10 +32,14 @@ impl FhtDataStore { pub const fn fmc_cdi_store() -> HandOffDataHandle { HandOffDataHandle(((Vault::KeyVault as u32) << 12) | KEY_ID_ROM_FMC_CDI as u32) } - /// The FMC private key is stored in a Key Vault slot. - pub const fn fmc_priv_key_store() -> HandOffDataHandle { + /// The FMC ECC private key is stored in a Key Vault slot. + pub const fn fmc_ecc_priv_key_store() -> HandOffDataHandle { HandOffDataHandle(((Vault::KeyVault as u32) << 12) | KEY_ID_FMC_ECDSA_PRIV_KEY as u32) } + /// The FMC MLDSA key pair seed is stored in a Key Vault slot. + pub const fn fmc_mldsa_keypair_seed_store() -> HandOffDataHandle { + HandOffDataHandle(((Vault::KeyVault as u32) << 12) | KEY_ID_FMC_MLDSA_KEYPAIR_SEED as u32) + } } #[cfg_attr(not(feature = "no-cfi"), cfi_mod_fn)] @@ -50,7 +54,8 @@ pub fn initialize_fht(env: &mut RomEnv) { fht_minor_ver: FHT_MINOR_VERSION, fips_fw_load_addr_hdl: FHT_INVALID_HANDLE, fmc_cdi_kv_hdl: FhtDataStore::fmc_cdi_store(), - fmc_priv_key_kv_hdl: FhtDataStore::fmc_priv_key_store(), + fmc_ecc_priv_key_kv_hdl: FhtDataStore::fmc_ecc_priv_key_store(), + fmc_mldsa_keypair_seed_kv_hdl: FhtDataStore::fmc_mldsa_keypair_seed_store(), rt_cdi_kv_hdl: FHT_INVALID_HANDLE, rt_priv_key_kv_hdl: FHT_INVALID_HANDLE, rom_info_addr: RomAddr::from(unsafe { &CALIPTRA_ROM_INFO }), diff --git a/rom/dev/src/flow/cold_reset/dice.rs b/rom/dev/src/flow/cold_reset/dice.rs index 5edbfa1614..98afca43cc 100644 --- a/rom/dev/src/flow/cold_reset/dice.rs +++ b/rom/dev/src/flow/cold_reset/dice.rs @@ -13,7 +13,7 @@ Abstract: --*/ -use crate::crypto::{Ecc384KeyPair, MlDsaKeyPair}; +use caliptra_common::crypto::{Ecc384KeyPair, MlDsaKeyPair}; use zeroize::Zeroize; /// DICE Layer Input diff --git a/rom/dev/src/flow/cold_reset/fmc_alias.rs b/rom/dev/src/flow/cold_reset/fmc_alias.rs index a076e0c211..215bf2aeef 100644 --- a/rom/dev/src/flow/cold_reset/fmc_alias.rs +++ b/rom/dev/src/flow/cold_reset/fmc_alias.rs @@ -15,21 +15,21 @@ Abstract: use super::dice::{DiceInput, DiceOutput}; use super::fw_processor::FwProcInfo; -use super::x509::X509; use crate::cprintln; -use crate::crypto::{Crypto, Ecc384KeyPair, MlDsaKeyPair, PubKey}; +use crate::crypto::Crypto; use crate::flow::cold_reset::{copy_tbs, TbsType}; use crate::print::HexBytes; use crate::rom_env::RomEnv; #[cfg(not(feature = "no-cfi"))] use caliptra_cfi_derive::cfi_impl_fn; use caliptra_cfi_lib::{cfi_assert, cfi_assert_bool, cfi_launder}; -use caliptra_common::dice; +use caliptra_common::crypto::{Ecc384KeyPair, MlDsaKeyPair, PubKey}; use caliptra_common::keyids::{ KEY_ID_FMC_ECDSA_PRIV_KEY, KEY_ID_FMC_MLDSA_KEYPAIR_SEED, KEY_ID_ROM_FMC_CDI, }; use caliptra_common::pcr::PCR_ID_FMC_CURRENT; use caliptra_common::RomBootStatus::*; +use caliptra_common::{dice, x509}; use caliptra_drivers::{ okmutref, report_boot_status, Array4x12, CaliptraResult, HmacMode, KeyId, Lifecycle, }; @@ -85,12 +85,16 @@ impl FmcAliasLayer { // // This information will be used by next DICE Layer while generating // certificates - let ecc_subj_sn = X509::subj_sn(env, &PubKey::Ecc(&ecc_key_pair.pub_key))?; - let mldsa_subj_sn = X509::subj_sn(env, &PubKey::Mldsa(&mldsa_key_pair.pub_key))?; + let ecc_subj_sn = + x509::X509::subj_sn(&mut env.sha256, &PubKey::Ecc(&ecc_key_pair.pub_key))?; + let mldsa_subj_sn = + x509::X509::subj_sn(&mut env.sha256, &PubKey::Mldsa(&mldsa_key_pair.pub_key))?; report_boot_status(FmcAliasSubjIdSnGenerationComplete.into()); - let ecc_subj_key_id = X509::subj_key_id(env, &PubKey::Ecc(&ecc_key_pair.pub_key))?; - let mldsa_subj_key_id = X509::subj_key_id(env, &PubKey::Mldsa(&mldsa_key_pair.pub_key))?; + let ecc_subj_key_id = + x509::X509::subj_key_id(&mut env.sha256, &PubKey::Ecc(&ecc_key_pair.pub_key))?; + let mldsa_subj_key_id = + x509::X509::subj_key_id(&mut env.sha256, &PubKey::Mldsa(&mldsa_key_pair.pub_key))?; report_boot_status(FmcAliasSubjKeyIdGenerationComplete.into()); // Generate the output for next layer @@ -222,12 +226,12 @@ impl FmcAliasLayer { // Certificate `To Be Signed` Parameters let params = FmcAliasCertTbsParams { - ueid: &X509::ueid(soc_ifc)?, + ueid: &x509::X509::ueid(soc_ifc)?, subject_sn: &output.ecc_subj_sn, subject_key_id: &output.ecc_subj_key_id, issuer_sn: input.ecc_auth_sn, authority_key_id: input.ecc_auth_key_id, - serial_number: &X509::ecc_cert_sn(&mut env.sha256, pub_key)?, + serial_number: &x509::X509::ecc_cert_sn(&mut env.sha256, pub_key)?, public_key: &pub_key.to_der(), tcb_info_fmc_tci: &(&data_vault.fmc_tci()).into(), tcb_info_device_info_hash: &fuse_info_digest.into(), diff --git a/rom/dev/src/flow/cold_reset/idev_id.rs b/rom/dev/src/flow/cold_reset/idev_id.rs index 7142868e47..a7102cd3d7 100644 --- a/rom/dev/src/flow/cold_reset/idev_id.rs +++ b/rom/dev/src/flow/cold_reset/idev_id.rs @@ -16,18 +16,21 @@ Abstract: use super::dice::*; use super::x509::*; use crate::cprintln; -use crate::crypto::{Crypto, Ecc384KeyPair, Ecdsa384SignatureAdapter, MlDsaKeyPair, PubKey}; +use crate::crypto::{Crypto, Ecdsa384SignatureAdapter}; use crate::print::HexBytes; use crate::rom_env::RomEnv; #[cfg(not(feature = "no-cfi"))] use caliptra_cfi_derive::cfi_impl_fn; use caliptra_cfi_lib::{cfi_assert, cfi_assert_bool, cfi_launder}; -use caliptra_common::keyids::{ - KEY_ID_FE, KEY_ID_IDEVID_ECDSA_PRIV_KEY, KEY_ID_IDEVID_MLDSA_KEYPAIR_SEED, KEY_ID_ROM_FMC_CDI, - KEY_ID_UDS, +use caliptra_common::{ + crypto::{Ecc384KeyPair, MlDsaKeyPair, PubKey}, + keyids::{ + KEY_ID_FE, KEY_ID_IDEVID_ECDSA_PRIV_KEY, KEY_ID_IDEVID_MLDSA_KEYPAIR_SEED, + KEY_ID_ROM_FMC_CDI, KEY_ID_UDS, + }, + x509, + RomBootStatus::*, }; -use caliptra_common::RomBootStatus::*; -use caliptra_drivers::MAX_CSR_SIZE; use caliptra_drivers::*; use caliptra_x509::*; use zeroize::Zeroize; @@ -88,8 +91,10 @@ impl InitDevIdLayer { // Generate the Subject Serial Number and Subject Key Identifier for ECC. // This information will be used by next DICE Layer while generating // certificates - let ecc_subj_sn = X509::subj_sn(env, &PubKey::Ecc(&ecc_key_pair.pub_key))?; - let mldsa_subj_sn = X509::subj_sn(env, &PubKey::Mldsa(&mldsa_key_pair.pub_key))?; + let ecc_subj_sn = + x509::X509::subj_sn(&mut env.sha256, &PubKey::Ecc(&ecc_key_pair.pub_key))?; + let mldsa_subj_sn = + x509::X509::subj_sn(&mut env.sha256, &PubKey::Mldsa(&mldsa_key_pair.pub_key))?; report_boot_status(IDevIdSubjIdSnGenerationComplete.into()); let ecc_subj_key_id = X509::idev_subj_key_id(env, &PubKey::Ecc(&ecc_key_pair.pub_key))?; @@ -265,7 +270,7 @@ impl InitDevIdLayer { // CSR `To Be Signed` Parameters let params = InitDevIdCsrTbsParams { // Unique Endpoint Identifier - ueid: &X509::ueid(&env.soc_ifc)?, + ueid: &x509::X509::ueid(&env.soc_ifc)?, // Subject Name subject_sn: &output.ecc_subj_sn, diff --git a/rom/dev/src/flow/cold_reset/ldev_id.rs b/rom/dev/src/flow/cold_reset/ldev_id.rs index 5ce5291b9c..499743c44f 100644 --- a/rom/dev/src/flow/cold_reset/ldev_id.rs +++ b/rom/dev/src/flow/cold_reset/ldev_id.rs @@ -14,18 +14,23 @@ Abstract: --*/ use super::dice::*; -use super::x509::*; use crate::cprintln; -use crate::crypto::{Crypto, Ecc384KeyPair, MlDsaKeyPair, PubKey}; +use crate::crypto::Crypto; use crate::flow::cold_reset::{copy_tbs, TbsType}; use crate::print::HexBytes; use crate::rom_env::RomEnv; #[cfg(not(feature = "no-cfi"))] use caliptra_cfi_derive::cfi_impl_fn; use caliptra_cfi_lib::{cfi_assert, cfi_assert_bool, cfi_launder}; -use caliptra_common::keyids::KEY_ID_LDEVID_MLDSA_KEYPAIR_SEED; -use caliptra_common::keyids::{KEY_ID_FE, KEY_ID_LDEVID_ECDSA_PRIV_KEY, KEY_ID_ROM_FMC_CDI}; -use caliptra_common::RomBootStatus::*; +use caliptra_common::{ + crypto::{Ecc384KeyPair, MlDsaKeyPair, PubKey}, + keyids::{ + KEY_ID_FE, KEY_ID_LDEVID_ECDSA_PRIV_KEY, KEY_ID_LDEVID_MLDSA_KEYPAIR_SEED, + KEY_ID_ROM_FMC_CDI, + }, + x509, + RomBootStatus::*, +}; use caliptra_drivers::*; use caliptra_x509::*; use zeroize::Zeroize; @@ -79,12 +84,16 @@ impl LocalDevIdLayer { // // This information will be used by the next DICE Layer while generating // certificates - let ecc_subj_sn = X509::subj_sn(env, &PubKey::Ecc(&ecc_key_pair.pub_key))?; - let mldsa_subj_sn = X509::subj_sn(env, &PubKey::Mldsa(&mldsa_key_pair.pub_key))?; + let ecc_subj_sn = + x509::X509::subj_sn(&mut env.sha256, &PubKey::Ecc(&ecc_key_pair.pub_key))?; + let mldsa_subj_sn = + x509::X509::subj_sn(&mut env.sha256, &PubKey::Mldsa(&mldsa_key_pair.pub_key))?; report_boot_status(LDevIdSubjIdSnGenerationComplete.into()); - let ecc_subj_key_id = X509::subj_key_id(env, &PubKey::Ecc(&ecc_key_pair.pub_key))?; - let mldsa_subj_key_id = X509::subj_key_id(env, &PubKey::Mldsa(&mldsa_key_pair.pub_key))?; + let ecc_subj_key_id = + x509::X509::subj_key_id(&mut env.sha256, &PubKey::Ecc(&ecc_key_pair.pub_key))?; + let mldsa_subj_key_id = + x509::X509::subj_key_id(&mut env.sha256, &PubKey::Mldsa(&mldsa_key_pair.pub_key))?; report_boot_status(LDevIdSubjKeyIdGenerationComplete.into()); // Generate the output for next layer @@ -186,12 +195,12 @@ impl LocalDevIdLayer { let ecc_auth_pub_key = &input.ecc_auth_key_pair.pub_key; let ecc_pub_key = &output.ecc_subj_key_pair.pub_key; - let ecc_serial_number = X509::ecc_cert_sn(&mut env.sha256, ecc_pub_key); + let ecc_serial_number = x509::X509::ecc_cert_sn(&mut env.sha256, ecc_pub_key); let ecc_serial_number = okref(&ecc_serial_number)?; // CSR `To Be Signed` Parameters let ecc_tbs_params = LocalDevIdCertTbsParams { - ueid: &X509::ueid(&env.soc_ifc)?, + ueid: &x509::X509::ueid(&env.soc_ifc)?, subject_sn: &output.ecc_subj_sn, subject_key_id: &output.ecc_subj_key_id, issuer_sn: input.ecc_auth_sn, diff --git a/rom/dev/src/flow/cold_reset/x509.rs b/rom/dev/src/flow/cold_reset/x509.rs index 93ec773b5b..798524a39f 100644 --- a/rom/dev/src/flow/cold_reset/x509.rs +++ b/rom/dev/src/flow/cold_reset/x509.rs @@ -12,80 +12,19 @@ Abstract: --*/ use crate::cprintln; -use crate::crypto::{Crypto, PubKey}; +use crate::crypto::Crypto; use crate::rom_env::RomEnv; +use caliptra_common::{ + crypto::{self, PubKey}, + x509, +}; use caliptra_drivers::*; use core::mem::size_of; -use core::usize; -use zerocopy::AsBytes; /// X509 API pub enum X509 {} impl X509 { - /// Get device serial number - /// - /// # Arguments - /// - /// * `soc_ifc` - SOC Interface object - /// - /// # Returns - /// - /// `[u8; 17]` - Byte 0 - Ueid Type, Bytes 1-16 Unique Endpoint Identifier - pub fn ueid(soc_ifc: &SocIfc) -> CaliptraResult<[u8; 17]> { - let ueid = soc_ifc.fuse_bank().ueid(); - Ok(ueid) - } - - fn get_pubkey_bytes(pub_key: &PubKey, pub_key_bytes: &mut [u8]) -> usize { - fn copy_and_swap_endianess(src: &[u8], dst: &mut [u8]) { - for i in (0..src.len()).step_by(4) { - if i + 3 < src.len() && i + 3 < dst.len() { - dst[i] = src[i + 3]; - dst[i + 1] = src[i + 2]; - dst[i + 2] = src[i + 1]; - dst[i + 3] = src[i]; - } - } - } - - match pub_key { - PubKey::Ecc(pub_key) => { - let ecc_pubkey_der = pub_key.to_der(); - pub_key_bytes[..ecc_pubkey_der.len()].copy_from_slice(&ecc_pubkey_der); - ecc_pubkey_der.len() - } - PubKey::Mldsa(pub_key) => { - // pub_key is in Caliptra Hw format (big-endian DWORDs). Convert it to little-endian DWORDs. - copy_and_swap_endianess(pub_key.0.as_bytes(), pub_key_bytes); - pub_key_bytes.len() - } - } - } - - fn pub_key_digest(env: &mut RomEnv, pub_key: &PubKey) -> CaliptraResult { - // Define an array large enough to hold the largest public key. - let mut pub_key_bytes: [u8; size_of::()] = [0; size_of::()]; - let pub_key_size = Self::get_pubkey_bytes(pub_key, &mut pub_key_bytes); - Crypto::sha256_digest(&mut env.sha256, &pub_key_bytes[..pub_key_size]) - } - - /// Get X509 Subject Serial Number from public key - /// - /// # Arguments - /// - /// * `env` - ROM Environment - /// * `pub_key` - ECC or MLDSA Public Key - /// - /// # Returns - /// - /// `[u8; 64]` - X509 Subject Identifier serial number - pub fn subj_sn(env: &mut RomEnv, pub_key: &PubKey) -> CaliptraResult<[u8; 64]> { - let digest = Self::pub_key_digest(env, pub_key); - let digest = okref(&digest)?; - Ok(Self::hex(&digest.into())) - } - /// Get Initial Device ID Cert Subject Key Identifier /// /// # Arguments @@ -98,7 +37,7 @@ impl X509 { /// `[u8; 20]` - X509 Subject Key Identifier pub fn idev_subj_key_id(env: &mut RomEnv, pub_key: &PubKey) -> CaliptraResult<[u8; 20]> { let mut pub_key_bytes: [u8; size_of::()] = [0; size_of::()]; - let pub_key_size = Self::get_pubkey_bytes(pub_key, &mut pub_key_bytes); + let pub_key_size = x509::X509::get_pubkey_bytes(pub_key, &mut pub_key_bytes); let data: &[u8] = &pub_key_bytes[..pub_key_size]; // [CAP2][TODO] Get the hash algorithm if the key is MLDSA. @@ -111,13 +50,13 @@ impl X509 { } X509KeyIdAlgo::Sha256 => { cprintln!("[idev] Sha256 KeyId Algorithm"); - let digest = Crypto::sha256_digest(&mut env.sha256, data); + let digest = crypto::sha256_digest(&mut env.sha256, data); let digest: [u8; 32] = okref(&digest)?.into(); digest[..20].try_into().unwrap() } X509KeyIdAlgo::Sha384 => { cprintln!("[idev] Sha384 KeyId Algorithm"); - let digest = Crypto::sha384_digest(env, data); + let digest = crypto::sha384_digest(&mut env.sha2_512_384, data); let digest: [u8; 48] = okref(&digest)?.into(); digest[..20].try_into().unwrap() } @@ -129,72 +68,4 @@ impl X509 { Ok(digest) } - - /// Get Cert Subject Key Identifier - /// - /// # Arguments - /// - /// * `env` - ROM Environment - /// * `pub_key` - Public Key - /// - /// # Returns - /// - /// `[u8; 20]` - X509 Subject Key Identifier - pub fn subj_key_id(env: &mut RomEnv, pub_key: &PubKey) -> CaliptraResult<[u8; 20]> { - let digest = Self::pub_key_digest(env, pub_key); - let digest: [u8; 32] = okref(&digest)?.into(); - Ok(digest[..20].try_into().unwrap()) - } - - /// Get Serial Number for ECC certificate. - /// - /// # Arguments - /// - /// * `sha256` - SHA256 Driver - /// * `pub_key` - ECC Public Key - /// - /// # Returns - /// - /// `[u8; 20]` - X509 Serial Number - pub fn ecc_cert_sn(sha256: &mut Sha256, pub_key: &Ecc384PubKey) -> CaliptraResult<[u8; 20]> { - let data = pub_key.to_der(); - let digest = Crypto::sha256_digest(sha256, &data); - let mut digest: [u8; 32] = okref(&digest)?.into(); - - // Ensure the encoded integer is positive, and that the first octet - // is non-zero (otherwise it will be considered padding, and the integer - // will fail to parse if the MSB of the second octet is zero). - digest[0] &= !0x80; - digest[0] |= 0x04; - - Ok(digest[..20].try_into().unwrap()) - } - - /// Return the hex representation of the input `buf` - /// - /// # Arguments - /// - /// `buf` - Buffer - /// - /// # Returns - /// - /// `[u8; 64]` - Hex representation of the buffer - fn hex(buf: &[u8; 32]) -> [u8; 64] { - fn ch(byte: u8) -> u8 { - match byte & 0x0F { - b @ 0..=9 => 48 + b, - b @ 10..=15 => 55 + b, - _ => unreachable!(), - } - } - - let mut hex = [0u8; 64]; - - for (index, byte) in buf.iter().enumerate() { - hex[index << 1] = ch((byte & 0xF0) >> 4); - hex[(index << 1) + 1] = ch(byte & 0x0F); - } - - hex - } } diff --git a/runtime/src/disable.rs b/runtime/src/disable.rs index 9d889049aa..3d46845164 100644 --- a/runtime/src/disable.rs +++ b/runtime/src/disable.rs @@ -64,7 +64,8 @@ impl DisableAttestationCmd { key_id_rt_cdi, KeyUsage::default() .set_hmac_key_en() - .set_ecc_key_gen_seed_en(), + .set_ecc_key_gen_seed_en() + .set_mldsa_key_gen_seed_en(), ) .into(), HmacMode::Hmac384, diff --git a/runtime/src/dpe_crypto.rs b/runtime/src/dpe_crypto.rs index 01d8e32994..b8ba9cc78d 100644 --- a/runtime/src/dpe_crypto.rs +++ b/runtime/src/dpe_crypto.rs @@ -154,7 +154,8 @@ impl<'a> Crypto for DpeCrypto<'a> { KEY_ID_DPE_CDI, KeyUsage::default() .set_hmac_key_en() - .set_ecc_key_gen_seed_en(), + .set_ecc_key_gen_seed_en() + .set_mldsa_key_gen_seed_en(), ) .into(), HmacMode::Hmac384, diff --git a/runtime/src/hmac.rs b/runtime/src/hmac.rs index 88e01b9257..d7fb561b34 100644 --- a/runtime/src/hmac.rs +++ b/runtime/src/hmac.rs @@ -54,7 +54,8 @@ fn ecc384_key_gen( KEY_ID_TMP, KeyUsage::default() .set_hmac_key_en() - .set_ecc_key_gen_seed_en(), + .set_ecc_key_gen_seed_en() + .set_mldsa_key_gen_seed_en(), ) .into(), HmacMode::Hmac384, @@ -110,7 +111,8 @@ impl Hmac { output, KeyUsage::default() .set_hmac_key_en() - .set_ecc_key_gen_seed_en(), + .set_ecc_key_gen_seed_en() + .set_mldsa_key_gen_seed_en(), ) .into(), mode, diff --git a/sw-emulator/lib/periph/src/key_vault.rs b/sw-emulator/lib/periph/src/key_vault.rs index 2ac77073fe..fa0fc793cf 100644 --- a/sw-emulator/lib/periph/src/key_vault.rs +++ b/sw-emulator/lib/periph/src/key_vault.rs @@ -247,7 +247,7 @@ bitfield! { pub hmac_data, set_hmac_data: 1; /// Flag indicating if the key can be used as MLDSA seed - pub mldsa_seed, set_mldsa_seed: 2; + pub mldsa_seed, set_mldsa_key_gen_seed: 2; /// Flag indicating if the key can be used aas ECC Private Key pub ecc_private_key, set_ecc_private_key: 3; diff --git a/sw-emulator/lib/periph/src/ml_dsa87.rs b/sw-emulator/lib/periph/src/ml_dsa87.rs index 74f09843a1..7b8bbfbfec 100644 --- a/sw-emulator/lib/periph/src/ml_dsa87.rs +++ b/sw-emulator/lib/periph/src/ml_dsa87.rs @@ -384,7 +384,7 @@ impl Mldsa87 { let key_id = self.kv_rd_seed_ctrl.reg.read(KvRdSeedCtrl::READ_ENTRY); let mut key_usage = KeyUsage::default(); - key_usage.set_mldsa_seed(true); + key_usage.set_mldsa_key_gen_seed(true); let result = self.key_vault.read_key(key_id, key_usage); let (seed_read_result, seed) = match result.err() { @@ -766,7 +766,7 @@ mod tests { let mut key_vault = KeyVault::new(); let mut key_usage = KeyUsage::default(); - key_usage.set_mldsa_seed(true); + key_usage.set_mldsa_key_gen_seed(true); key_vault .write_key(key_id, &seed, u32::from(key_usage)) diff --git a/test/src/derive.rs b/test/src/derive.rs index 2722133d5a..c085fd6512 100644 --- a/test/src/derive.rs +++ b/test/src/derive.rs @@ -16,7 +16,7 @@ use zerocopy::{transmute, AsBytes}; use caliptra_api_types::DeviceLifecycle; use crate::{ - crypto::{self, derive_ecdsa_key, hmac384_drbg_keygen, hmac384_kdf, hmac512, hmac512_kdf}, + crypto::{self, derive_ecdsa_key, hmac384_drbg_keygen, hmac512, hmac512_kdf}, swap_word_bytes, swap_word_bytes_inplace, }; @@ -457,10 +457,10 @@ impl FmcAliasKey { #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct RtAliasKey { - pub cdi: [u32; 12], + pub cdi: [u32; 16], - // The FMC alias private key as stored in the key-vault - pub priv_key: [u32; 12], + // The FMC alias ECC private key as stored in the key-vault + pub ecc_priv_key: [u32; 12], } impl RtAliasKey { pub fn derive(tci_input: &PcrRtCurrentInput, fmc_key: &FmcAliasKey) -> Self { @@ -473,30 +473,30 @@ impl RtAliasKey { .as_bytes_mut() .copy_from_slice(&sha384(tci_input.manifest.as_bytes())); - let mut cdi: [u32; 12] = transmute!(hmac384_kdf( - &swap_word_bytes(&fmc_key.cdi).as_bytes()[..48], - b"rt_alias_cdi", + let mut cdi: [u32; 16] = transmute!(hmac512_kdf( + swap_word_bytes(&fmc_key.cdi).as_bytes(), + b"alias_rt_cdi", Some(&tci), )); swap_word_bytes_inplace(&mut cdi); - let mut priv_key_seed: [u32; 12] = transmute!(hmac384_kdf( - &swap_word_bytes(&cdi).as_bytes()[..48], - b"rt_alias_keygen", + let mut priv_key_seed: [u32; 16] = transmute!(hmac512_kdf( + swap_word_bytes(&cdi).as_bytes(), + b"alias_rt_ecc_key", None )); swap_word_bytes_inplace(&mut priv_key_seed); - let mut priv_key: [u32; 12] = transmute!(hmac384_drbg_keygen( + let mut ecc_priv_key: [u32; 12] = transmute!(hmac384_drbg_keygen( &swap_word_bytes(&priv_key_seed).as_bytes()[..48], swap_word_bytes(&ECDSA_KEYGEN_NONCE).as_bytes() )); - swap_word_bytes_inplace(&mut priv_key); - Self { priv_key, cdi } + swap_word_bytes_inplace(&mut ecc_priv_key); + Self { ecc_priv_key, cdi } } pub fn derive_public_key(&self) -> PKey { derive_ecdsa_key( - swap_word_bytes(&self.priv_key) + swap_word_bytes(&self.ecc_priv_key) .as_bytes() .try_into() .unwrap(),