Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] FMC DICE changes for adding MLDSA support #1850

Open
wants to merge 1 commit into
base: main-2.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
98 changes: 94 additions & 4 deletions common/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Array4x8> {
sha256.digest(data)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why we need this function, which just wraps a simple method call? (ditto for sha384)

}

/// 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()
.set_mldsa_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 = 98 * 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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since these are already in a separate mod, it feels redundant to have an empty enum to contain. We could just have these be functions in this file without the enum and impl.

That way later we don't have to have the triply redundant caliptra_x509::x509::X509::method_name().

/// 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 @@ -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
Expand Down
Loading