Skip to content

Commit

Permalink
Exchange CDI for CDI handle via DPE::Crypto trait
Browse files Browse the repository at this point in the history
  • Loading branch information
clundin25 committed Jan 22, 2025
1 parent 27b8300 commit cab66ad
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 23 deletions.
39 changes: 34 additions & 5 deletions crypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ pub use rand::*;
mod hkdf;
mod signer;

pub const MAX_EXPORTED_CDI_SIZE: usize = 32;

#[derive(Debug, Clone, Copy)]
#[cfg_attr(test, derive(strum_macros::EnumIter))]
pub enum AlgLen {
Expand Down Expand Up @@ -54,6 +56,7 @@ pub enum CryptoError {
Size = 0x3,
NotImplemented = 0x4,
HashError(u32) = 0x5,
ExportedCdiHandleLimitExceeded = 0x6,
}

impl CryptoError {
Expand All @@ -66,11 +69,12 @@ impl CryptoError {

pub fn get_error_detail(&self) -> Option<u32> {
match self {
CryptoError::AbstractionLayer(code) => Some(*code),
CryptoError::CryptoLibError(code) => Some(*code),
CryptoError::Size => None,
CryptoError::NotImplemented => None,
CryptoError::HashError(code) => Some(*code),
CryptoError::AbstractionLayer(code)
| CryptoError::CryptoLibError(code)
| CryptoError::HashError(code) => Some(*code),
CryptoError::Size
| CryptoError::ExportedCdiHandleLimitExceeded
| CryptoError::NotImplemented => None,
}
}
}
Expand Down Expand Up @@ -208,6 +212,31 @@ pub trait Crypto {
info: &[u8],
) -> Result<Self::Cdi, CryptoError>;

/// Retrieve an exported CDI Handle from a CDI.
/// If the CDI has already been exported, the same handle is returned.
/// If the number of CDIs that can be exported has reached its limit,
/// a `CryptoError` is returned.
///
/// # Arguments
///
/// * `cdi` - The CDI to request a handle for.
fn get_exported_cdi_handle(
&mut self,
cdi: &Self::Cdi,
) -> Result<[u8; MAX_EXPORTED_CDI_SIZE], CryptoError>;

/// Retrieve a CDI from an exported CDI Handle.
///
/// If the handle is not associated with a CDI, `None` is returned.
///
/// # Arguments
///
/// * `exported_cdi_handle` - The handle to the CDI.
fn get_cdi_from_exported_handle(
&mut self,
exported_cdi_handle: &[u8; MAX_EXPORTED_CDI_SIZE],
) -> Option<Self::Cdi>;

/// Derives a key pair using a cryptographically secure KDF
///
/// # Arguments
Expand Down
63 changes: 57 additions & 6 deletions crypto/src/openssl.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Licensed under the Apache-2.0 license

use crate::{hkdf::*, AlgLen, Crypto, CryptoBuf, CryptoError, Digest, EcdsaPub, Hasher};
use crate::{
hkdf::*, AlgLen, Crypto, CryptoBuf, CryptoError, Digest, EcdsaPub, Hasher,
MAX_EXPORTED_CDI_SIZE,
};
#[cfg(not(feature = "no-cfi"))]
use caliptra_cfi_derive_git::cfi_impl_fn;
use openssl::{
Expand Down Expand Up @@ -41,23 +44,37 @@ impl Hasher for OpensslHasher {
}
}

// Currently only supports one CDI handle but in the future we may want to support multiple.
const MAX_CDI_HANDLES: usize = 1;
type ExportedCdiHandle = [u8; MAX_EXPORTED_CDI_SIZE];

#[cfg(feature = "deterministic_rand")]
pub struct OpensslCrypto(StdRng);
pub struct OpensslCrypto {
rng: StdRng,
export_cdi_slots: Vec<(<OpensslCrypto as Crypto>::Cdi, ExportedCdiHandle)>,
}

#[cfg(not(feature = "deterministic_rand"))]
pub struct OpensslCrypto;
pub struct OpensslCrypto {
export_cdi_slots: Vec<ExportedCdiHandle>,
}

impl OpensslCrypto {
#[cfg(feature = "deterministic_rand")]
pub fn new() -> Self {
const SEED: [u8; 32] = [1; 32];
let seeded_rng = StdRng::from_seed(SEED);
OpensslCrypto(seeded_rng)
Self {
rng: seeded_rng,
export_cdi_slots: Vec::new(),
}
}

#[cfg(not(feature = "deterministic_rand"))]
pub fn new() -> Self {
Self {}
Self {
export_cdi_slots: Vec::new(),
}
}

fn get_digest(algs: AlgLen) -> MessageDigest {
Expand Down Expand Up @@ -141,7 +158,7 @@ impl Crypto for OpensslCrypto {

#[cfg(feature = "deterministic_rand")]
fn rand_bytes(&mut self, dst: &mut [u8]) -> Result<(), CryptoError> {
StdRng::fill_bytes(&mut self.0, dst);
StdRng::fill_bytes(&mut self.rng, dst);
Ok(())
}

Expand Down Expand Up @@ -177,6 +194,40 @@ impl Crypto for OpensslCrypto {
Ok(cdi)
}

fn get_exported_cdi_handle(
&mut self,
cdi: &Self::Cdi,
) -> Result<ExportedCdiHandle, CryptoError> {
for (stored_cdi, stored_handle) in self.export_cdi_slots.iter() {
if stored_cdi == cdi {
return Ok(stored_handle.to_owned());
}
}

if self.export_cdi_slots.len() >= MAX_CDI_HANDLES {
return Err(CryptoError::ExportedCdiHandleLimitExceeded);
}

let mut exported_cdi_handle = [0; MAX_EXPORTED_CDI_SIZE];
self.rand_bytes(&mut exported_cdi_handle)?;
self.export_cdi_slots
.push((cdi.clone(), exported_cdi_handle));

Ok(exported_cdi_handle)
}

fn get_cdi_from_exported_handle(
&mut self,
exported_cdi_handle: &ExportedCdiHandle,
) -> Option<Self::Cdi> {
for (cdi, handle) in self.export_cdi_slots.iter() {
if handle == exported_cdi_handle {
return Some(cdi.to_owned());
}
}
None
}

#[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)]
fn derive_key_pair(
&mut self,
Expand Down
53 changes: 50 additions & 3 deletions crypto/src/rustcrypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,31 @@ impl Hasher for RustCryptoHasher {
}
}

pub struct RustCryptoImpl(StdRng);
// Currently only supports one CDI handle but in the future we may want to support multiple.
const MAX_CDI_HANDLES: usize = 1;
type ExportedCdiHandle = [u8; MAX_EXPORTED_CDI_SIZE];

pub struct RustCryptoImpl {
rng: StdRng,
export_cdi_slots: Vec<(<RustCryptoImpl as Crypto>::Cdi, ExportedCdiHandle)>,
}

impl RustCryptoImpl {
#[cfg(not(feature = "deterministic_rand"))]
pub fn new() -> Self {
RustCryptoImpl(StdRng::from_entropy())
Self {
export_cdi_slots: Vec::new(),
}
}

#[cfg(feature = "deterministic_rand")]
pub fn new() -> Self {
const SEED: [u8; 32] = [1; 32];
let seeded_rng = StdRng::from_seed(SEED);
RustCryptoImpl(seeded_rng)
Self {
rng: seeded_rng,
export_cdi_slots: Vec::new(),
}
}

fn derive_key_pair_inner(
Expand Down Expand Up @@ -139,6 +152,40 @@ impl Crypto for RustCryptoImpl {
Ok(cdi)
}

fn get_exported_cdi_handle(
&mut self,
cdi: &Self::Cdi,
) -> Result<ExportedCdiHandle, CryptoError> {
for (stored_cdi, stored_handle) in self.export_cdi_slots.iter() {
if stored_cdi == cdi {
return Ok(stored_handle.to_owned());
}
}

if self.export_cdi_slots.len() >= MAX_CDI_HANDLES {
return Err(CryptoError::ExportedCdiHandleLimitExceeded);
}

let mut exported_cdi_handle = [0; MAX_EXPORTED_CDI_SIZE];
self.rand_bytes(&mut exported_cdi_handle)?;
self.export_cdi_slots
.push((cdi.clone(), exported_cdi_handle));

Ok(exported_cdi_handle)
}

fn get_cdi_from_exported_handle(
&mut self,
exported_cdi_handle: &ExportedCdiHandle,
) -> Option<Self::Cdi> {
for (cdi, handle) in self.export_cdi_slots.iter() {
if handle == exported_cdi_handle {
return Some(cdi.to_owned());
}
}
None
}

#[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)]
fn derive_key_pair(
&mut self,
Expand Down
4 changes: 3 additions & 1 deletion dpe/src/commands/certify_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ impl CommandExecution for CertifyKeyCmd {
};
let mut cert = [0; MAX_CERT_SIZE];

let CreateDpeCertResult { cert_size, pub_key } = match self.format {
let CreateDpeCertResult {
cert_size, pub_key, ..
} = match self.format {
Self::FORMAT_X509 => {
cfg_if! {
if #[cfg(not(feature = "disable_x509"))] {
Expand Down
2 changes: 1 addition & 1 deletion dpe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub mod x509;

use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};

const MAX_EXPORTED_CDI_SIZE: usize = 32;
pub use crypto::MAX_EXPORTED_CDI_SIZE;

// Max cert size returned by CertifyKey
const MAX_CERT_SIZE: usize = 6144;
Expand Down
39 changes: 32 additions & 7 deletions dpe/src/x509.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use bitflags::bitflags;
use caliptra_cfi_lib_git::cfi_launder;
#[cfg(not(feature = "no-cfi"))]
use caliptra_cfi_lib_git::{cfi_assert, cfi_assert_eq};
use crypto::{Crypto, Digest, EcdsaPub, EcdsaSig, Hasher};
use crypto::{Crypto, Digest, EcdsaPub, EcdsaSig, Hasher, MAX_EXPORTED_CDI_SIZE};
#[cfg(not(feature = "disable_x509"))]
use platform::CertValidity;
#[cfg(not(feature = "disable_csr"))]
Expand Down Expand Up @@ -2265,6 +2265,11 @@ pub(crate) struct CreateDpeCertResult {
pub cert_size: u32,
/// Public key embedded in Cert or CSR.
pub pub_key: EcdsaPub,
//TODO(clundin): Remove once https://github.com/chipsalliance/caliptra-dpe/pull/376 is merged.
/// If the cert_type is `CertificateType::Exported` the CDI is exchanged for a handle, and
/// returned via `exported_cdi_handle`.
#[allow(unused)]
pub exported_cdi_handle: [u8; MAX_EXPORTED_CDI_SIZE],
}

fn get_dpe_measurement_digest(
Expand Down Expand Up @@ -2390,18 +2395,22 @@ fn create_dpe_cert_or_csr(
let algs = DPE_PROFILE.alg_len();
let digest = get_dpe_measurement_digest(dpe, env, args.handle, args.locality)?;

let key_pair = match cert_type {
let (key_pair, cdi) = match cert_type {
CertificateType::Exported => {
let cdi = env
.crypto
.derive_exported_cdi(algs, &digest, args.cdi_label)?;
env.crypto
.derive_key_pair_exported(algs, &cdi, args.key_label, args.context)
let key_pair =
env.crypto
.derive_key_pair_exported(algs, &cdi, args.key_label, args.context);
(key_pair, cdi)
}
CertificateType::Leaf => {
let cdi = env.crypto.derive_cdi(algs, &digest, args.cdi_label)?;
env.crypto
.derive_key_pair(algs, &cdi, args.key_label, args.context)
let key_pair = env
.crypto
.derive_key_pair(algs, &cdi, args.key_label, args.context);
(key_pair, cdi)
}
};
if cfi_launder(key_pair.is_ok()) {
Expand Down Expand Up @@ -2521,7 +2530,23 @@ fn create_dpe_cert_or_csr(
}
};

Ok(CreateDpeCertResult { cert_size, pub_key })
let result = match cert_type {
CertificateType::Exported => {
let exported_cdi_handle = env.crypto.get_exported_cdi_handle(&cdi)?;
CreateDpeCertResult {
cert_size,
pub_key,
exported_cdi_handle,
}
}
_ => CreateDpeCertResult {
cert_size,
pub_key,
exported_cdi_handle: [0; MAX_EXPORTED_CDI_SIZE],
},
};

Ok(result)
}

#[cfg(test)]
Expand Down

0 comments on commit cab66ad

Please sign in to comment.