Skip to content

Commit

Permalink
Add certificate generation code to DeriveContext
Browse files Browse the repository at this point in the history
  • Loading branch information
clundin25 committed Jan 21, 2025
1 parent 8b54c17 commit fdd83b8
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 24 deletions.
1 change: 1 addition & 0 deletions dpe/fuzz/src/fuzz_target_1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ fn harness(data: &[u8]) {
Response::GetProfile(ref res) => res.resp_hdr.status,
Response::InitCtx(ref res) => res.resp_hdr.status,
Response::DeriveContext(ref res) => res.resp_hdr.status,
Response::DeriveContextExportedCdi(ref res) => res.resp_hdr.status,
Response::RotateCtx(ref res) => res.resp_hdr.status,
Response::CertifyKey(ref res) => res.resp_hdr.status,
Response::Sign(ref res) => res.resp_hdr.status,
Expand Down
139 changes: 132 additions & 7 deletions dpe/src/commands/derive_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ use super::CommandExecution;
use crate::{
context::{ActiveContextArgs, Context, ContextHandle, ContextState, ContextType},
dpe_instance::{DpeEnv, DpeInstance, DpeTypes},
response::{DeriveContextResp, DpeErrorCode, Response, ResponseHdr},
response::{
DeriveContextExportedCdiResp, DeriveContextResp, DpeErrorCode, Response, ResponseHdr,
},
tci::TciMeasurement,
DPE_PROFILE,
x509::{create_exported_dpe_cert, CreateDpeCertArgs, CreateDpeCertResult},
DPE_PROFILE, MAX_CERT_SIZE, MAX_EXPORTED_CDI_SIZE,
};
use bitflags::bitflags;
#[cfg(not(feature = "no-cfi"))]
use caliptra_cfi_derive_git::cfi_impl_fn;
#[cfg(not(feature = "no-cfi"))]
use caliptra_cfi_lib_git::{cfi_assert, cfi_assert_eq};
use cfg_if::cfg_if;
use crypto::Crypto;

#[repr(C)]
#[derive(
Expand Down Expand Up @@ -284,7 +288,39 @@ impl CommandExecution for DeriveContextCmd {
}
}
} else if self.creates_certificate() && self.exports_cdi() {
todo!("(clundin): Generate ECA certificiate / export random CDI")
cfg_if! {
if #[cfg(not(feature = "disable_export_cdi"))] {
let mut exported_cdi_handle = [0; MAX_EXPORTED_CDI_SIZE];
env.crypto
.rand_bytes(&mut exported_cdi_handle)
.map_err(DpeErrorCode::Crypto)?;
let args = CreateDpeCertArgs {
handle: &self.handle,
locality,
cdi_label: b"Exported CDI",
key_label: b"Exported ECC",
context: &exported_cdi_handle,
};
let mut cert = [0; MAX_CERT_SIZE];
let CreateDpeCertResult { cert_size, .. } = create_exported_dpe_cert(
&args,
dpe,
env,
&mut cert,
)?;

Ok(Response::DeriveContextExportedCdi(DeriveContextExportedCdiResp {
handle: ContextHandle::new_invalid(),
parent_handle: dpe.contexts[parent_idx].handle,
resp_hdr: ResponseHdr::new(DpeErrorCode::NoError),
exported_cdi: exported_cdi_handle,
certificate_size: cert_size,
new_certificate: cert,
}))
} else {
Err(DpeErrorCode::ArgumentNotSupported)?
}
}
} else {
let child_idx = dpe
.get_next_inactive_context_pos()
Expand Down Expand Up @@ -381,13 +417,18 @@ mod tests {
context::ContextType,
dpe_instance::tests::{TestTypes, RANDOM_HANDLE, SIMULATION_HANDLE, TEST_LOCALITIES},
support::Support,
MAX_HANDLES,
DpeProfile, MAX_HANDLES,
};
use caliptra_cfi_lib_git::CfiCounter;
use crypto::{Crypto, Hasher, OpensslCrypto};
use openssl::x509::X509;
use openssl::{bn::BigNum, ecdsa::EcdsaSig};
use platform::default::DefaultPlatform;
use openssl::{
bn::BigNum,
ecdsa::EcdsaSig,
hash::{Hasher as OpenSSLHasher, MessageDigest},
x509::X509,
};
use platform::{default::DefaultPlatform, Platform, MAX_KEY_IDENTIFIER_SIZE};
use x509_parser::{nom::Parser, oid_registry::asn1_rs::oid, prelude::*};
use zerocopy::IntoBytes;

const TEST_DERIVE_CONTEXT_CMD: DeriveContextCmd = DeriveContextCmd {
Expand Down Expand Up @@ -1155,4 +1196,88 @@ mod tests {
.execute(&mut dpe, &mut env, TEST_LOCALITIES[0])
);
}
#[test]
fn test_create_ca() {
CfiCounter::reset_for_test();
let mut env = DpeEnv::<TestTypes> {
crypto: OpensslCrypto::new(),
platform: DefaultPlatform,
};
let mut dpe = DpeInstance::new(&mut env, Support::X509 | Support::CDI_EXPORT).unwrap();
let init_resp = match InitCtxCmd::new_use_default()
.execute(&mut dpe, &mut env, TEST_LOCALITIES[0])
.unwrap()
{
Response::InitCtx(resp) => resp,
_ => panic!("Incorrect return type."),
};
let derive_cmd = DeriveContextCmd {
handle: init_resp.handle,
flags: DeriveContextFlags::EXPORT_CDI | DeriveContextFlags::CREATE_CERTIFICATE,
data: [0; DPE_PROFILE.get_tci_size()],
tci_type: 0,
target_locality: TEST_LOCALITIES[0],
};
let derive_resp = match derive_cmd
.execute(&mut dpe, &mut env, TEST_LOCALITIES[0])
.unwrap()
{
Response::DeriveContextExportedCdi(resp) => resp,
_ => panic!("Wrong response type."),
};
assert_eq!(ContextHandle::new_invalid(), derive_resp.handle);
let mut parser = X509CertificateParser::new().with_deep_parse_extensions(true);
match parser
.parse(&derive_resp.new_certificate[..derive_resp.certificate_size.try_into().unwrap()])
{
Ok((_, cert)) => {
match cert.basic_constraints() {
Ok(Some(basic_constraints)) => {
assert!(basic_constraints.value.ca);
}
Ok(None) => panic!("basic constraints extension not found"),
Err(_) => panic!("multiple basic constraints extensions found"),
}
let pub_key = &cert.tbs_certificate.subject_pki.subject_public_key.data;
let mut hasher = match DPE_PROFILE {
DpeProfile::P256Sha256 => OpenSSLHasher::new(MessageDigest::sha256()).unwrap(),
DpeProfile::P384Sha384 => OpenSSLHasher::new(MessageDigest::sha384()).unwrap(),
};
hasher.update(pub_key).unwrap();
let expected_ski: &[u8] = &hasher.finish().unwrap();
match cert.get_extension_unique(&oid!(2.5.29 .14)) {
Ok(Some(subject_key_identifier_ext)) => {
if let ParsedExtension::SubjectKeyIdentifier(key_identifier) =
subject_key_identifier_ext.parsed_extension()
{
assert_eq!(key_identifier.0, &expected_ski[..MAX_KEY_IDENTIFIER_SIZE]);
} else {
panic!("Extension has wrong type");
}
}
Ok(None) => panic!("subject key identifier extension not found"),
Err(_) => panic!("multiple subject key identifier extensions found"),
}
let mut expected_aki = [0u8; MAX_KEY_IDENTIFIER_SIZE];
env.platform
.get_issuer_key_identifier(&mut expected_aki)
.unwrap();
match cert.get_extension_unique(&oid!(2.5.29 .35)) {
Ok(Some(extension)) => {
if let ParsedExtension::AuthorityKeyIdentifier(aki) =
extension.parsed_extension()
{
let key_identifier = aki.key_identifier.clone().unwrap();
assert_eq!(&key_identifier.0, &expected_aki,);
} else {
panic!("Extension has wrong type");
}
}
Ok(None) => panic!("authority key identifier extension not found"),
Err(_) => panic!("multiple authority key identifier extensions found"),
}
}
Err(e) => panic!("x509 parsing failed: {:?}", e),
};
}
}
12 changes: 12 additions & 0 deletions dpe/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ pub struct Context {
pub reserved: [u8; 1],
}

impl Default for Context {
fn default() -> Self {
Self::new()
}
}

impl Context {
pub const ROOT_INDEX: u8 = 0xff;

Expand Down Expand Up @@ -116,12 +122,18 @@ pub struct ContextHandle(pub [u8; ContextHandle::SIZE]);
impl ContextHandle {
pub const SIZE: usize = 16;
const DEFAULT: ContextHandle = ContextHandle([0; Self::SIZE]);
const INVALID: ContextHandle = ContextHandle([0xFF; Self::SIZE]);

/// Returns the default context handle.
pub const fn default() -> ContextHandle {
Self::DEFAULT
}

/// Returns an invalid context handle.
pub const fn new_invalid() -> ContextHandle {
Self::INVALID
}

/// Whether the handle is the default context handle.
pub fn is_default(&self) -> bool {
self.equals(&Self::DEFAULT)
Expand Down
39 changes: 22 additions & 17 deletions dpe/src/x509.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2245,25 +2245,16 @@ enum CertificateType {
Exported,
}

/// Arguments for DPE cert or CSR creation.
pub(crate) struct CreateDpeCertArgs<'a> {
/// Used by DPE to compute measurement digest
pub handle: &'a ContextHandle,
/// The locality of the caller
pub locality: u32,
/// Info string used in the CDI derivation
pub cdi_label: &'a [u8],
/// Label string used in the key derivation
pub key_label: &'a [u8],
/// Additional info string used in the key derivation
pub context: &'a [u8],
}

/// Results for DPE cert or CSR creation.
pub(crate) struct CreateDpeCertResult {
/// Size of certificate or CSR in bytes.
pub cert_size: u32,
/// Public key embedded in Cert or CSR.
pub pub_key: EcdsaPub,
}

Expand Down Expand Up @@ -2329,8 +2320,6 @@ fn get_subject_key_identifier(
Ok(())
}

// TODO(clundin): Remove this lint when adding the DeriveContext certificate generation code.
#[allow(unused)]
pub(crate) fn create_exported_dpe_cert(
args: &CreateDpeCertArgs,
dpe: &mut DpeInstance,
Expand Down Expand Up @@ -2474,9 +2463,17 @@ fn create_dpe_cert_or_csr(
return Err(DpeErrorCode::InternalError);
}
let tbs_digest = env.crypto.hash(algs, &scratch_buf[..bytes_written])?;
let sig = env
.crypto
.ecdsa_sign_with_alias(DPE_PROFILE.alg_len(), &tbs_digest)?;
let sig = match cert_type {
CertificateType::Leaf => env
.crypto
.ecdsa_sign_with_alias(DPE_PROFILE.alg_len(), &tbs_digest),
CertificateType::Exported => env.crypto.ecdsa_sign_with_derived(
DPE_PROFILE.alg_len(),
&tbs_digest,
&priv_key,
&pub_key,
),
}?;
let mut cert_writer = CertWriter::new(output_cert_or_csr, true);
bytes_written =
cert_writer.encode_ecdsa_certificate(&scratch_buf[..bytes_written], &sig)?;
Expand Down Expand Up @@ -2510,9 +2507,17 @@ fn create_dpe_cert_or_csr(
}

let csr_digest = env.crypto.hash(algs, &csr_buffer[..bytes_written])?;
let csr_sig = env
.crypto
.ecdsa_sign_with_alias(DPE_PROFILE.alg_len(), &csr_digest)?;
let csr_sig = match cert_type {
CertificateType::Leaf => env
.crypto
.ecdsa_sign_with_alias(DPE_PROFILE.alg_len(), &csr_digest),
CertificateType::Exported => env.crypto.ecdsa_sign_with_derived(
DPE_PROFILE.alg_len(),
&csr_digest,
&priv_key,
&pub_key,
),
}?;
let sid = env.platform.get_signer_identifier()?;

let mut cms_writer = CertWriter::new(output_cert_or_csr, true);
Expand Down

0 comments on commit fdd83b8

Please sign in to comment.