diff --git a/Cargo.lock b/Cargo.lock index b9d7d82c..be9e03cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -801,6 +801,7 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" name = "platform" version = "0.1.0" dependencies = [ + "arrayvec", "cfg-if", "openssl", "ufmt", diff --git a/dpe/fuzz/Cargo.lock b/dpe/fuzz/Cargo.lock index f4b163fc..44e1d6d8 100644 --- a/dpe/fuzz/Cargo.lock +++ b/dpe/fuzz/Cargo.lock @@ -478,6 +478,7 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" name = "platform" version = "0.1.0" dependencies = [ + "arrayvec", "cfg-if", "openssl", "ufmt", diff --git a/dpe/src/commands/certify_key.rs b/dpe/src/commands/certify_key.rs index 39a92b7b..279bd9b9 100644 --- a/dpe/src/commands/certify_key.rs +++ b/dpe/src/commands/certify_key.rs @@ -10,7 +10,7 @@ use crate::{ }; use bitflags::bitflags; use crypto::Crypto; -use platform::{Platform, MAX_CHUNK_SIZE, MAX_SN_SIZE}; +use platform::{Platform, MAX_CHUNK_SIZE}; #[repr(C)] #[derive(Debug, PartialEq, Eq, zerocopy::FromBytes, zerocopy::AsBytes)] @@ -114,6 +114,7 @@ impl CommandExecution for CertifyKeyCmd { if issuer_len > MAX_CHUNK_SIZE { return Err(DpeErrorCode::InternalError); } + let cert_validity = env.platform.get_cert_validity()?; let mut bytes_written = tbs_writer.encode_ecdsa_tbs( /*serial=*/ &subject_name.serial.bytes()[..20], // Serial number must be truncated to 20 bytes @@ -121,6 +122,7 @@ impl CommandExecution for CertifyKeyCmd { &subject_name, &pub_key, &measurements, + cert_validity, )?; if bytes_written > MAX_CERT_SIZE { return Err(DpeErrorCode::InternalError); @@ -183,16 +185,11 @@ impl CommandExecution for CertifyKeyCmd { let csr_sig = env .crypto .ecdsa_sign_with_alias(DPE_PROFILE.alg_len(), &csr_digest)?; - let mut issuer_sn = [0u8; MAX_SN_SIZE]; - let sn_len = env.platform.get_issuer_sn(&mut issuer_sn)?; + let sid = env.platform.get_signer_identifier()?; let mut cms_writer = CertWriter::new(&mut cert, true); - bytes_written = cms_writer.encode_cms( - &csr_buffer[..bytes_written], - &issuer_sn[..sn_len], // Serial number must be truncated to 20 bytes - &issuer_name[..issuer_len], - &csr_sig, - )?; + bytes_written = + cms_writer.encode_cms(&csr_buffer[..bytes_written], &csr_sig, &sid)?; u32::try_from(bytes_written).map_err(|_| DpeErrorCode::InternalError)? } _ => return Err(DpeErrorCode::InvalidArgument), @@ -473,27 +470,17 @@ mod tests { // validate signer identifier let sid = &signer_info.sid; - let mut subj_serial = [0u8; DPE_PROFILE.get_hash_size() * 2]; - let mut issuer_serial = [0u8; MAX_SN_SIZE]; - let pub_key = EcdsaPub { - x: CryptoBuf::new(&certify_resp.derived_pubkey_x).unwrap(), - y: CryptoBuf::new(&certify_resp.derived_pubkey_y).unwrap(), - }; - env.crypto - .get_pubkey_serial(DPE_PROFILE.alg_len(), &pub_key, &mut subj_serial) - .unwrap(); - env.platform.get_issuer_sn(&mut issuer_serial).unwrap(); match sid { SignerIdentifier::IssuerAndSerialNumber(issuer_and_serial_number) => { let cert_serial_number = &issuer_and_serial_number.serial_number; - assert_eq!(&issuer_serial, cert_serial_number.as_bytes()); + let cert_issuer_name = &issuer_and_serial_number.issuer.to_der().unwrap(); - let mut issuer_name = [0u8; MAX_CHUNK_SIZE]; - let issuer_len = env.platform.get_issuer_name(&mut issuer_name).unwrap(); - assert_eq!( - &issuer_name[..issuer_len], - &issuer_and_serial_number.issuer.to_der().unwrap() - ) + let platform::SignerIdentifier::IssuerAndSerialNumber {issuer_name, serial_number} = env.platform.get_signer_identifier().unwrap() else { + panic!("Error: Signer Identifier is not IssuerAndSerialNumber in default platform!") + }; + + assert_eq!(serial_number.as_bytes(), cert_serial_number.as_bytes()); + assert_eq!(issuer_name.as_bytes(), cert_issuer_name.as_bytes()) } _ => panic!("Error: Signer Identifier is not IssuerAndSerialNumber!"), }; @@ -553,6 +540,14 @@ mod tests { assert!(cri_sig.verify(cri_digest.bytes(), &pub_key).unwrap()); // validate subject_name + let mut subj_serial = [0u8; DPE_PROFILE.get_hash_size() * 2]; + let pub_key = EcdsaPub { + x: CryptoBuf::new(&certify_resp.derived_pubkey_x).unwrap(), + y: CryptoBuf::new(&certify_resp.derived_pubkey_y).unwrap(), + }; + env.crypto + .get_pubkey_serial(DPE_PROFILE.alg_len(), &pub_key, &mut subj_serial) + .unwrap(); let subject_name = Name { cn: DirectoryString::PrintableString(b"DPE Leaf"), serial: DirectoryString::PrintableString(&subj_serial), diff --git a/dpe/src/x509.rs b/dpe/src/x509.rs index cfd8265a..5305b83b 100644 --- a/dpe/src/x509.rs +++ b/dpe/src/x509.rs @@ -12,6 +12,7 @@ use crate::{ }; use bitflags::bitflags; use crypto::{EcdsaPub, EcdsaSig}; +use platform::{CertValidity, SignerIdentifier}; pub enum DirectoryString<'a> { PrintableString(&'a [u8]), @@ -86,6 +87,7 @@ impl CertWriter<'_> { const X509_V3: u64 = 2; const CMS_V1: u64 = 1; + const CMS_V3: u64 = 3; const CSR_V0: u64 = 0; const ECDSA_OID: &[u8] = match DPE_PROFILE { @@ -144,11 +146,6 @@ impl CertWriter<'_> { // RFC 2985 1.2.840.113549.1.9.14 const EXTENSION_REQUEST_OID: &[u8] = &[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x0E]; - // All DPE certs are valid from January 1st, 2023 00:00:00 until - // December 31st, 9999 23:59:59 - const NOT_BEFORE: &str = "20230227000000Z"; - const NOT_AFTER: &str = "99991231235959Z"; - /// Build new CertWriter that writes output to `cert` /// /// If `crit_dice`, all tcg-dice-* extensions will be marked as critical. @@ -261,9 +258,9 @@ impl CertWriter<'_> { } /// If `tagged`, include the tag and size fields - fn get_validity_size(tagged: bool) -> Result { - let len = Self::get_bytes_size(Self::NOT_BEFORE.as_bytes(), true)? - + Self::get_bytes_size(Self::NOT_AFTER.as_bytes(), true)?; + fn get_validity_size(validity: CertValidity<'_>, tagged: bool) -> Result { + let len = Self::get_bytes_size(validity.not_before.as_bytes(), true)? + + Self::get_bytes_size(validity.not_after.as_bytes(), true)?; Self::get_structure_size(len, tagged) } @@ -473,13 +470,14 @@ impl CertWriter<'_> { subject_name: &Name, pubkey: &EcdsaPub, measurements: &MeasurementData, + validity: CertValidity<'_>, tagged: bool, ) -> Result { let tbs_size = Self::get_version_size(/*tagged=*/ true)? + Self::get_integer_bytes_size(serial_number, /*tagged=*/ true)? + Self::get_ecdsa_sig_alg_id_size(/*tagged=*/ true)? + issuer_der.len() - + Self::get_validity_size(/*tagged=*/ true)? + + Self::get_validity_size(validity, /*tagged=*/ true)? + Self::get_rdn_size(subject_name, /*tagged=*/ true)? + Self::get_ecdsa_subject_pubkey_info_size(pubkey, /*tagged=*/ true)? + Self::get_extensions_size( @@ -507,20 +505,26 @@ impl CertWriter<'_> { Self::get_structure_size(cert_req_info_size, tagged) } + /// Get the size of the CMS version which differs based on the SignerIdentifier + fn get_cms_version_size(sid: &SignerIdentifier) -> Result { + match sid { + SignerIdentifier::IssuerAndSerialNumber { + issuer_name: _, + serial_number: _, + } => Self::get_integer_size(Self::CMS_V1, true), + SignerIdentifier::SubjectKeyIdentifier(_) => Self::get_integer_size(Self::CMS_V3, true), + } + } + /// Get the size of the ASN.1 SignerInfo structure /// If `tagged`, include the tag and size fields fn get_signer_info_size( - serial_number: &[u8], - issuer_der: &[u8], sig: &EcdsaSig, + sid: &SignerIdentifier, tagged: bool, ) -> Result { - let signer_info_size = Self::get_integer_size(Self::CMS_V1, true)? - + Self::get_issuer_and_serial_number_size( - serial_number, - issuer_der, - /*tagged=*/ true, - )? + let signer_info_size = Self::get_cms_version_size(sid)? + + Self::get_signer_identifier_size(sid, /*tagged=*/ true)? + Self::get_hash_alg_id_size(/*tagged=*/ true)? + Self::get_ecdsa_sig_alg_id_size(/*tagged=*/ true)? + Self::get_ecdsa_signature_octet_string_size(sig, /*tagged=*/ true)?; @@ -532,20 +536,19 @@ impl CertWriter<'_> { /// If `tagged`, include the tag and size fields fn get_signed_data_size( csr: &[u8], - serial_number: &[u8], - issuer_der: &[u8], sig: &EcdsaSig, + sid: &SignerIdentifier, tagged: bool, explicit: bool, ) -> Result { - let signed_data_size = Self::get_integer_size(Self::CMS_V1, true)? + let signed_data_size = Self::get_cms_version_size(sid)? + Self::get_structure_size( Self::get_hash_alg_id_size(/*tagged=*/ true)?, /*tagged=*/ true, )? + Self::get_encap_content_info_size(csr, /*tagged=*/ true)? + Self::get_structure_size( - Self::get_signer_info_size(serial_number, issuer_der, sig, /*tagged=*/ true)?, + Self::get_signer_info_size(sig, sid, /*tagged=*/ true)?, /*tagged=*/ true, )?; @@ -555,6 +558,31 @@ impl CertWriter<'_> { Self::get_structure_size(explicit_signed_data_size, tagged) } + /// Get the size of the ASN.1 SignerIdentifier structure + /// If `tagged`, include the tag and size fields + fn get_signer_identifier_size( + sid: &SignerIdentifier, + tagged: bool, + ) -> Result { + match sid { + SignerIdentifier::IssuerAndSerialNumber { + issuer_name, + serial_number, + } => Self::get_issuer_and_serial_number_size( + serial_number, + issuer_name, + /*tagged=*/ tagged, + ), + SignerIdentifier::SubjectKeyIdentifier(subject_key_identifier) => { + Ok(Self::get_subject_key_identifier_size( + subject_key_identifier, + /*tagged=*/ tagged, + /*explicit=*/ true, + )?) + } + } + } + /// Get the size of the ASN.1 IssuerAndSerialNumber structure /// If `tagged`, include the tag and size fields fn get_issuer_and_serial_number_size( @@ -568,6 +596,21 @@ impl CertWriter<'_> { Self::get_structure_size(issuer_and_serial_number_size, tagged) } + /// Get the size of the ASN.1 SubjectKeyIdentifier structure + /// If `tagged`, include the tag and size fields + fn get_subject_key_identifier_size( + subject_key_identifier: &[u8], + tagged: bool, + explicit: bool, + ) -> Result { + let subject_key_identifier_size = subject_key_identifier.len(); + + // Determine whether to include the explicit tag wrapping in the size calculation + let explicit_bytes_size = Self::get_structure_size(subject_key_identifier_size, explicit)?; + + Self::get_structure_size(explicit_bytes_size, tagged) + } + fn get_econtent_size( bytes: &[u8], tagged: bool, @@ -842,20 +885,20 @@ impl CertWriter<'_> { Ok(bytes_written) } - // Encode ASN.1 Validity which never expires - fn encode_validity(&mut self) -> Result { - let seq_size = Self::get_validity_size(/*tagged=*/ false)?; + // Encode ASN.1 Validity according to Platform + fn encode_validity(&mut self, validity: CertValidity<'_>) -> Result { + let seq_size = Self::get_validity_size(validity, /*tagged=*/ false)?; let mut bytes_written = self.encode_tag_field(Self::SEQUENCE_TAG)?; bytes_written += self.encode_size_field(seq_size)?; bytes_written += self.encode_tag_field(Self::GENERALIZE_TIME_TAG)?; - bytes_written += self.encode_size_field(Self::NOT_BEFORE.len())?; - bytes_written += self.encode_bytes(Self::NOT_BEFORE.as_bytes())?; + bytes_written += self.encode_size_field(validity.not_before.len())?; + bytes_written += self.encode_bytes(validity.not_before.as_bytes())?; bytes_written += self.encode_tag_field(Self::GENERALIZE_TIME_TAG)?; - bytes_written += self.encode_size_field(Self::NOT_AFTER.len())?; - bytes_written += self.encode_bytes(Self::NOT_AFTER.as_bytes())?; + bytes_written += self.encode_size_field(validity.not_after.len())?; + bytes_written += self.encode_bytes(validity.not_after.as_bytes())?; Ok(bytes_written) } @@ -1305,6 +1348,19 @@ impl CertWriter<'_> { Ok(bytes_written) } + /// Encodes an integer representing the CMS version which is dependent on the SignerIdentifier + /// + /// If the SignerIdentifier is IssuerAndSerialNumber the version is 1, otherwise it is 3. + fn encode_cms_version(&mut self, sid: &SignerIdentifier) -> Result { + match sid { + SignerIdentifier::IssuerAndSerialNumber { + issuer_name: _, + serial_number: _, + } => self.encode_integer(Self::CMS_V1), + SignerIdentifier::SubjectKeyIdentifier(_) => self.encode_integer(Self::CMS_V3), + } + } + /// Encode a SignedData /// /// This function does not populate the certificates or crls fields. @@ -1320,36 +1376,25 @@ impl CertWriter<'_> { #[allow(clippy::identity_op)] fn encode_signed_data( &mut self, - serial_number: &[u8], - issuer_name: &[u8], csr: &[u8], sig: &EcdsaSig, + sid: &SignerIdentifier, ) -> Result { // SignedData is EXPLICIT field number 0 let mut bytes_written = self.encode_byte(Self::CONTEXT_SPECIFIC | Self::CONSTRUCTED | 0x0)?; bytes_written += self.encode_size_field(Self::get_signed_data_size( - csr, - serial_number, - issuer_name, - sig, - /*tagged=*/ true, - /*explicit=*/ false, + csr, sig, sid, /*tagged=*/ true, /*explicit=*/ false, )?)?; // SignedData sequence bytes_written += self.encode_tag_field(Self::SEQUENCE_TAG)?; bytes_written += self.encode_size_field(Self::get_signed_data_size( - csr, - serial_number, - issuer_name, - sig, - /*tagged=*/ false, - /*explicit=*/ false, + csr, sig, sid, /*tagged=*/ false, /*explicit=*/ false, )?)?; // CMS version - bytes_written += self.encode_integer(Self::CMS_V1)?; + bytes_written += self.encode_cms_version(sid)?; // digestAlgorithms bytes_written += self.encode_tag_field(Self::SET_OF_TAG)?; @@ -1362,13 +1407,9 @@ impl CertWriter<'_> { // signerInfos bytes_written += self.encode_tag_field(Self::SET_OF_TAG)?; - bytes_written += self.encode_size_field(Self::get_signer_info_size( - serial_number, - issuer_name, - sig, - /*tagged=*/ true, - )?)?; - bytes_written += self.encode_signer_info(serial_number, issuer_name, sig)?; + bytes_written += + self.encode_size_field(Self::get_signer_info_size(sig, sid, /*tagged=*/ true)?)?; + bytes_written += self.encode_signer_info(sig, sid)?; Ok(bytes_written) } @@ -1428,22 +1469,20 @@ impl CertWriter<'_> { /// } pub fn encode_signer_info( &mut self, - serial_number: &[u8], - issuer_name: &[u8], sig: &EcdsaSig, + sid: &SignerIdentifier, ) -> Result { - let signer_info_size = - Self::get_signer_info_size(serial_number, issuer_name, sig, /*tagged=*/ false)?; + let signer_info_size = Self::get_signer_info_size(sig, sid, /*tagged=*/ false)?; // SignerInfo Sequence let mut bytes_written = self.encode_tag_field(Self::SEQUENCE_TAG)?; bytes_written += self.encode_size_field(signer_info_size)?; // CMS version - bytes_written += self.encode_integer(Self::CMS_V1)?; + bytes_written += self.encode_cms_version(sid)?; // SignerIdentifier - bytes_written += self.encode_issuer_and_serial_number(serial_number, issuer_name)?; + bytes_written += self.encode_signer_identifier(sid)?; // digestAlgorithm bytes_written += self.encode_hash_alg_id()?; @@ -1457,6 +1496,24 @@ impl CertWriter<'_> { Ok(bytes_written) } + /// Encode a SignerIdentifier + /// + /// SignerIdentifier ::= CHOICE { + /// issuerAndSerialNumber IssuerAndSerialNumber, + /// subjectKeyIdentifier [0] SubjectKeyIdentifier + /// } + fn encode_signer_identifier(&mut self, sid: &SignerIdentifier) -> Result { + match sid { + SignerIdentifier::IssuerAndSerialNumber { + issuer_name, + serial_number, + } => self.encode_issuer_and_serial_number(serial_number, issuer_name), + SignerIdentifier::SubjectKeyIdentifier(subject_key_identifier) => { + self.encode_subject_key_identifier(subject_key_identifier) + } + } + } + /// Encode an IssuerAndSerialNumber /// /// IssuerAndSerialNumber ::= SEQUENCE { @@ -1487,6 +1544,35 @@ impl CertWriter<'_> { Ok(bytes_written) } + /// Encode a SubjectKeyIdentifier + /// + /// SubjectKeyIdentifier ::= OCTET STRING + #[allow(clippy::identity_op)] + fn encode_subject_key_identifier( + &mut self, + subject_key_identifier: &[u8], + ) -> Result { + // SubjectKeyIdentifier is EXPLICIT field number 0 + let mut bytes_written = + self.encode_byte(Self::CONTEXT_SPECIFIC | Self::CONSTRUCTED | 0x0)?; + bytes_written += self.encode_size_field(Self::get_subject_key_identifier_size( + subject_key_identifier, + /*tagged=*/ true, + /*explicit=*/ false, + )?)?; + + // SubjectKeyIdentifier OCTET STRING + bytes_written += self.encode_tag_field(Self::OCTET_STRING_TAG)?; + bytes_written += self.encode_size_field(Self::get_subject_key_identifier_size( + subject_key_identifier, + /*tagged=*/ false, + /*explicit=*/ false, + )?)?; + bytes_written += self.encode_bytes(subject_key_identifier)?; + + Ok(bytes_written) + } + /// Encode an eContent /// /// eContent [0] EXPLICIT OCTET STRING OPTIONAL @@ -1554,6 +1640,7 @@ impl CertWriter<'_> { /// * `subject_name` - The subject name RDN struct to encode. /// * `pubkey` - ECDSA Public key. /// * `measurements` - DPE measurement data. + /// * `validity` - Time period in which certificate is valid. pub fn encode_ecdsa_tbs( &mut self, serial_number: &[u8], @@ -1561,6 +1648,7 @@ impl CertWriter<'_> { subject_name: &Name, pubkey: &EcdsaPub, measurements: &MeasurementData, + validity: CertValidity<'_>, ) -> Result { let tbs_size = Self::get_tbs_size( serial_number, @@ -1568,6 +1656,7 @@ impl CertWriter<'_> { subject_name, pubkey, measurements, + validity, /*tagged=*/ false, )?; @@ -1588,7 +1677,7 @@ impl CertWriter<'_> { bytes_written += self.encode_bytes(issuer_name)?; // validity - bytes_written += self.encode_validity()?; + bytes_written += self.encode_validity(validity)?; // subject bytes_written += self.encode_rdn(subject_name)?; @@ -1726,18 +1815,12 @@ impl CertWriter<'_> { pub fn encode_cms( &mut self, csr: &[u8], - serial_number: &[u8], - issuer_name: &[u8], sig: &EcdsaSig, + sid: &SignerIdentifier, ) -> Result { let size = Self::get_structure_size(Self::ID_SIGNED_DATA_OID.len(), /*tagged=*/ true)? + Self::get_signed_data_size( - csr, - serial_number, - issuer_name, - sig, - /*tagged=*/ true, - /*explicit=*/ true, + csr, sig, sid, /*tagged=*/ true, /*explicit=*/ true, )?; let cms_size = Self::get_structure_size(size, false)?; @@ -1746,7 +1829,7 @@ impl CertWriter<'_> { bytes_written += self.encode_size_field(cms_size)?; bytes_written += self.encode_oid(Self::ID_SIGNED_DATA_OID)?; - bytes_written += self.encode_signed_data(serial_number, issuer_name, csr, sig)?; + bytes_written += self.encode_signed_data(csr, sig, sid)?; Ok(bytes_written) } @@ -1758,6 +1841,7 @@ mod tests { use crate::x509::{CertWriter, DirectoryString, MeasurementData, Name}; use crate::DPE_PROFILE; use crypto::{CryptoBuf, EcdsaPub, EcdsaSig}; + use platform::CertValidity; use std::str; use x509_parser::certificate::X509CertificateParser; use x509_parser::nom::Parser; @@ -2003,6 +2087,11 @@ mod tests { supports_extend_tci: true, }; + let validity = CertValidity { + not_before: "20230227000000Z", + not_after: "99991231235959Z", + }; + let bytes_written = w .encode_ecdsa_tbs( &test_serial, @@ -2010,6 +2099,7 @@ mod tests { &test_subject_name, &test_pub, &measurements, + validity, ) .unwrap(); @@ -2063,6 +2153,11 @@ mod tests { supports_extend_tci: true, }; + let validity = CertValidity { + not_before: "20230227000000Z", + not_after: "99991231235959Z", + }; + let mut tbs_writer = CertWriter::new(cert_buf, true); let bytes_written = tbs_writer .encode_ecdsa_tbs( @@ -2071,6 +2166,7 @@ mod tests { &TEST_SUBJECT_NAME, &test_pub, &measurements, + validity, ) .unwrap(); diff --git a/platform/Cargo.toml b/platform/Cargo.toml index 7a800c30..7e1e0931 100644 --- a/platform/Cargo.toml +++ b/platform/Cargo.toml @@ -13,6 +13,7 @@ dpe_profile_p256_sha256 = [] dpe_profile_p384_sha384 = [] [dependencies] +arrayvec = { version = "0.7.4", default-features = false, features = ["zeroize"] } cfg-if = "1.0.0" openssl = {version = "0.10.57", optional = true} ufmt = { git = "https://github.com/korran/ufmt.git", rev = "1d0743c1ffffc68bc05ca8eeb81c166192863f33", features = ["inline"] } diff --git a/platform/src/default.rs b/platform/src/default.rs index a998b527..42e3ca7d 100644 --- a/platform/src/default.rs +++ b/platform/src/default.rs @@ -1,6 +1,7 @@ // Licensed under the Apache-2.0 license -use crate::{Platform, PlatformError, MAX_CHUNK_SIZE, MAX_SN_SIZE}; +use crate::{CertValidity, Platform, PlatformError, SignerIdentifier, MAX_CHUNK_SIZE}; +use arrayvec::ArrayVec; use cfg_if::cfg_if; use core::cmp::min; @@ -9,6 +10,8 @@ pub struct DefaultPlatform; pub const AUTO_INIT_LOCALITY: u32 = 0; pub const VENDOR_ID: u32 = 0; pub const VENDOR_SKU: u32 = 0; +pub const NOT_BEFORE: &str = "20230227000000Z"; +pub const NOT_AFTER: &str = "99991231235959Z"; // Run ./generate.sh to generate all test certs and test private keys #[cfg(feature = "dpe_profile_p256_sha256")] @@ -33,7 +36,7 @@ cfg_if! { pub fn parse_issuer_name() -> Vec { X509::from_pem(TEST_CERT_PEM) .unwrap() - .subject_name() + .issuer_name() .to_der() .unwrap() } @@ -60,7 +63,7 @@ cfg_if! { Certificate::from_pem(TEST_CERT_PEM) .unwrap() .tbs_certificate - .subject + .issuer .to_der() .unwrap() } @@ -109,13 +112,22 @@ impl Platform for DefaultPlatform { Ok(issuer_name.len()) } - fn get_issuer_sn(&mut self, out: &mut [u8; MAX_SN_SIZE]) -> Result { + fn get_signer_identifier(&mut self) -> Result { + let mut issuer_name = [0u8; MAX_CHUNK_SIZE]; + let issuer_len = self.get_issuer_name(&mut issuer_name)?; let sn = parse::DefaultPlatform::parse_issuer_sn(); - if sn.len() > out.len() { - return Err(PlatformError::IssuerNameError(0)); - } - out[..sn.len()].copy_from_slice(&sn); - Ok(sn.len()) + let mut issuer_name_vec = ArrayVec::new(); + issuer_name_vec + .try_extend_from_slice(&issuer_name[..issuer_len]) + .map_err(|_| PlatformError::IssuerNameError(0))?; + let mut serial_number_vec = ArrayVec::new(); + serial_number_vec + .try_extend_from_slice(&sn) + .map_err(|_| PlatformError::SerialNumberError(0))?; + Ok(SignerIdentifier::IssuerAndSerialNumber { + issuer_name: issuer_name_vec, + serial_number: serial_number_vec, + }) } fn get_vendor_id(&mut self) -> Result { @@ -134,4 +146,11 @@ impl Platform for DefaultPlatform { print!("{str}"); Ok(()) } + + fn get_cert_validity<'a>(&mut self) -> Result, PlatformError> { + Ok(CertValidity { + not_before: NOT_BEFORE, + not_after: NOT_AFTER, + }) + } } diff --git a/platform/src/lib.rs b/platform/src/lib.rs index 8caff83f..da4524fa 100644 --- a/platform/src/lib.rs +++ b/platform/src/lib.rs @@ -8,6 +8,8 @@ Abstract: #[cfg(feature = "openssl")] pub use openssl::x509::X509; +pub use arrayvec::ArrayVec; + #[cfg(any(feature = "openssl", feature = "rustcrypto"))] pub mod default; @@ -16,6 +18,20 @@ pub mod printer; pub const MAX_CHUNK_SIZE: usize = 2048; pub const MAX_SN_SIZE: usize = 20; +pub enum SignerIdentifier { + IssuerAndSerialNumber { + issuer_name: ArrayVec, + serial_number: ArrayVec, + }, + SubjectKeyIdentifier(ArrayVec), +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct CertValidity<'a> { + pub not_before: &'a str, + pub not_after: &'a str, +} + #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[repr(u16)] pub enum PlatformError { @@ -23,6 +39,8 @@ pub enum PlatformError { NotImplemented = 0x2, IssuerNameError(u32) = 0x3, PrintError(u32) = 0x4, + SerialNumberError(u32) = 0x5, + SubjectKeyIdentifierError(u32) = 0x6, } impl PlatformError { @@ -39,6 +57,8 @@ impl PlatformError { PlatformError::NotImplemented => None, PlatformError::IssuerNameError(code) => Some(*code), PlatformError::PrintError(code) => Some(*code), + PlatformError::SerialNumberError(code) => Some(*code), + PlatformError::SubjectKeyIdentifierError(code) => Some(*code), } } } @@ -65,11 +85,11 @@ pub trait Platform { /// * `out` - Output buffer for issuer name to be written to. fn get_issuer_name(&mut self, out: &mut [u8; MAX_CHUNK_SIZE]) -> Result; - /// Retrives the issuer's Serial Number + /// Retrieves a CMS Content Info's signer identifier /// - /// The issuer serial number is a big-endian integer which is at-most 20 - /// bytes. It must adhere to all the requirements of an ASN.1 integer. - fn get_issuer_sn(&mut self, out: &mut [u8; MAX_SN_SIZE]) -> Result; + /// This function can simply return an error if the DPE does not support CSRs. + /// Otherwise, the platform can choose either SubjectKeyIdentifier or IssuerAndSerialNumber. + fn get_signer_identifier(&mut self) -> Result; fn get_vendor_id(&mut self) -> Result; @@ -78,4 +98,12 @@ pub trait Platform { fn get_auto_init_locality(&mut self) -> Result; fn write_str(&mut self, str: &str) -> Result<(), PlatformError>; + + /// Retrieves the DPE certificate's validity period + /// + /// Each output string should represent a valid ISO 8601 date and time + /// in the yyyyMMddHHmmss format followed by a timezone. + /// + /// Example: 99991231235959Z is December 31st, 9999 23:59:59 UTC + fn get_cert_validity<'a>(&mut self) -> Result, PlatformError>; } diff --git a/verification/testing/certifyKey.go b/verification/testing/certifyKey.go index 01c6dd18..a7d347b6 100644 --- a/verification/testing/certifyKey.go +++ b/verification/testing/certifyKey.go @@ -161,21 +161,6 @@ func TestCertifyKeyCsr(d client.TestDPEInstance, c client.DPEClient, t *testing. t.Fatalf("[FATAL]: Could not get Certificate Chain: %v", err) } certChain := checkCertificateChain(t, certChainBytes) - lastCertInCertChain := certChain[len(certChain)-1] - - // Get DPE leaf cert - certifyKeyResp, err = c.CertifyKey(ctx, label, client.CertifyKeyX509, flags) - if err != nil { - t.Fatalf("[FATAL]: Could not certify key: %v", err) - } - leafCert := checkCertificateStructure(t, certifyKeyResp.Certificate) - - // This library expects the issuer of the cert to match the issuer of the CMS. - // - // The last cert in the cert chain would be signed by the preceding cert - // so its issuer is not what the library expects. The DPE leaf cert is signed - // by the alias key so it's issuer will match the issuer of the CMS. - lastCertInCertChain.RawIssuer = leafCert.RawIssuer // This library expects the cert to be in the Certificates field but DPE // does not populate it. Add it so Verify succeeds. @@ -186,7 +171,7 @@ func TestCertifyKeyCsr(d client.TestDPEInstance, c client.DPEClient, t *testing. // those verifying the signatures have an alternate means of // obtaining necessary certificates (e.g., from a previous set // of certificates). - wrappedCSR.Certificates = append(wrappedCSR.Certificates, lastCertInCertChain) + wrappedCSR.Certificates = append(wrappedCSR.Certificates, certChain...) err = wrappedCSR.Verify() if err != nil { t.Errorf("[ERROR]: Failed to verify CMS wrapper signature: %v", err)