Skip to content

Commit

Permalink
[feat] FMC DICE changes for adding MLDSA support
Browse files Browse the repository at this point in the history
  • Loading branch information
mhatrevi committed Dec 13, 2024
1 parent e0d80da commit 5f8147a
Show file tree
Hide file tree
Showing 26 changed files with 697 additions and 548 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ caliptra-api.workspace = true
caliptra-registers.workspace = true
ufmt.workspace = true
zerocopy.workspace = true
zeroize.workspace = true

[features]
default = ["std"]
Expand Down
97 changes: 93 additions & 4 deletions common/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,102 @@ 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<Array4x8> {
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<Array4x12> {
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(),
)
.into(),
mode,
)
}
8 changes: 5 additions & 3 deletions common/src/keyids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
3 changes: 2 additions & 1 deletion common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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 = 97 * 1024;

Expand Down
166 changes: 166 additions & 0 deletions common/src/x509.rs
Original file line number Diff line number Diff line change
@@ -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<Array4x8> {
// Define an array large enough to hold the largest public key.
let mut pub_key_bytes: [u8; size_of::<Mldsa87PubKey>()] = [0; size_of::<Mldsa87PubKey>()];
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
}
}
1 change: 1 addition & 0 deletions drivers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
18 changes: 18 additions & 0 deletions drivers/src/data_vault.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,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
Expand Down
Loading

0 comments on commit 5f8147a

Please sign in to comment.