Skip to content

Commit

Permalink
Encode SubjectAlternativeName extension
Browse files Browse the repository at this point in the history
Currently, only the otherName choice is supported.
  • Loading branch information
sree-revoori1 committed Mar 20, 2024
1 parent d7931b2 commit dfce6bf
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 5 deletions.
9 changes: 8 additions & 1 deletion dpe/src/commands/certify_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use caliptra_cfi_lib::cfi_launder;
use caliptra_cfi_lib::{cfi_assert, cfi_assert_eq};
use cfg_if::cfg_if;
use crypto::{Crypto, Hasher};
use platform::{Platform, MAX_ISSUER_NAME_SIZE, MAX_KEY_IDENTIFIER_SIZE};
use platform::{Platform, PlatformError, MAX_ISSUER_NAME_SIZE, MAX_KEY_IDENTIFIER_SIZE};

#[repr(C)]
#[derive(Debug, PartialEq, Eq, zerocopy::FromBytes, zerocopy::AsBytes)]
Expand Down Expand Up @@ -142,13 +142,20 @@ impl CommandExecution for CertifyKeyCmd {
env.platform
.get_issuer_key_identifier(&mut authority_key_identifier)?;

let subject_alt_name = match env.platform.get_subject_alternative_name() {
Ok(subject_alt_name) => Some(subject_alt_name),
Err(PlatformError::NotImplemented) => None,
Err(e) => Err(DpeErrorCode::Platform(e))?,
};

let measurements = MeasurementData {
label: &self.label,
tci_nodes: &nodes[..tcb_count],
is_ca: self.uses_is_ca(),
supports_recursive: dpe.support.recursive(),
subject_key_identifier,
authority_key_identifier,
subject_alt_name,
};

let mut issuer_name = [0u8; MAX_ISSUER_NAME_SIZE];
Expand Down
155 changes: 153 additions & 2 deletions dpe/src/x509.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ use crate::{
};
use bitflags::bitflags;
use crypto::{EcdsaPub, EcdsaSig};
use platform::{CertValidity, SignerIdentifier, MAX_KEY_IDENTIFIER_SIZE};
use platform::{
CertValidity, OtherName, SignerIdentifier, SubjectAltName, MAX_KEY_IDENTIFIER_SIZE,
};

pub enum DirectoryString<'a> {
PrintableString(&'a [u8]),
Expand Down Expand Up @@ -51,6 +53,7 @@ pub struct MeasurementData<'a> {
pub supports_recursive: bool,
pub subject_key_identifier: [u8; MAX_KEY_IDENTIFIER_SIZE],
pub authority_key_identifier: [u8; MAX_KEY_IDENTIFIER_SIZE],
pub subject_alt_name: Option<SubjectAltName>,
}

pub struct CertWriter<'a> {
Expand Down Expand Up @@ -145,6 +148,9 @@ impl CertWriter<'_> {
// RFC 5280 2.5.29.35
const AUTHORITY_KEY_IDENTIFIER_OID: &'static [u8] = &[0x55, 0x1D, 0x23];

// RFC 5280 2.5.29.17
const SUBJECT_ALTERNATIVE_NAME_OID: &'static [u8] = &[0x55, 0x1D, 0x11];

// RFC 5652 1.2.840.113549.1.7.2
const ID_SIGNED_DATA_OID: &'static [u8] =
&[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02];
Expand Down Expand Up @@ -502,6 +508,49 @@ impl CertWriter<'_> {
Self::get_structure_size(size, tagged)
}

fn get_subject_alt_name_extension_size(
measurements: &MeasurementData,
tagged: bool,
) -> Result<usize, DpeErrorCode> {
match &measurements.subject_alt_name {
None => Ok(0),
Some(SubjectAltName::OtherName(other_name)) => {
let san_size = Self::get_other_name_size(other_name, /*tagged=*/ true)?;

// Extension data is sequence -> octet string. To compute size, wrap
// in tagging twice.
let ext_size = Self::get_structure_size(san_size, /*tagged=*/ true)?;
let size = Self::get_structure_size(Self::SUBJECT_ALTERNATIVE_NAME_OID.len(), /*tagged=*/true)? // Extension OID
+ Self::get_structure_size(Self::BOOL_SIZE, /*tagged=*/true)? // Critical bool
+ Self::get_structure_size(ext_size, /*tagged=*/true)?; // OCTET STRING

Self::get_structure_size(size, tagged)
}
}
}

fn get_other_name_size(other_name: &OtherName, tagged: bool) -> Result<usize, DpeErrorCode> {
let size = Self::get_structure_size(other_name.oid.len(), /*tagged=*/ true)?
+ Self::get_other_name_value_size(
other_name.other_name.as_slice(),
/*tagged=*/ true,
/*explicit=*/ true,
)?;

Self::get_structure_size(size, tagged)
}

fn get_other_name_value_size(
other_name_value: &[u8],
tagged: bool,
explicit: bool,
) -> Result<usize, DpeErrorCode> {
// Determine whether to include the explicit tag wrapping in the size calculation
let size = Self::get_structure_size(other_name_value.len(), explicit)?;

Self::get_structure_size(size, tagged)
}

/// Get the size of the TBS Extensions field.
fn get_extensions_size(
measurements: &MeasurementData,
Expand All @@ -523,7 +572,8 @@ impl CertWriter<'_> {
measurements,
/*tagged=*/ true,
is_x509,
)?;
)?
+ Self::get_subject_alt_name_extension_size(measurements, /*tagged=*/ true)?;

// Determine whether to include the explicit tag wrapping in the size calculation
size = Self::get_structure_size(size, /*tagged=*/ explicit)?;
Expand Down Expand Up @@ -1402,6 +1452,104 @@ impl CertWriter<'_> {
Ok(bytes_written)
}

#[allow(clippy::identity_op)]
fn encode_other_name_value(&mut self, other_name_value: &[u8]) -> Result<usize, DpeErrorCode> {
// value 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_other_name_value_size(
other_name_value,
/*tagged=*/ true,
/*explicit=*/ false,
)?)?;

// value := UTF8STRING
bytes_written += self.encode_tag_field(Self::UTF8_STRING_TAG)?;
bytes_written += self.encode_size_field(Self::get_other_name_value_size(
other_name_value,
/*tagged=*/ false,
/*explicit=*/ false,
)?)?;
bytes_written += self.encode_bytes(other_name_value)?;

Ok(bytes_written)
}

/// OtherName ::= SEQUENCE {
/// type-id OBJECT IDENTIFIER,
/// value [0] EXPLICIT ANY DEFINED BY type-id
/// }
#[allow(clippy::identity_op)]
fn encode_other_name(&mut self, other_name: &OtherName) -> Result<usize, DpeErrorCode> {
// otherName 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_other_name_size(
other_name, /*tagged=*/ false,
)?)?;
bytes_written += self.encode_oid(other_name.oid)?;
bytes_written += self.encode_other_name_value(other_name.other_name.as_slice())?;

Ok(bytes_written)
}

/// SubjectAltName ::= GeneralNames
///
/// GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
///
/// GeneralName ::= CHOICE {
/// otherName [0] OtherName,
/// rfc822Name [1] IA5String,
/// dNSName [2] IA5String,
/// x400Address [3] ORAddress,
/// directoryName [4] Name,
/// ediPartyName [5] EDIPartyName,
/// uniformResourceIdentifier [6] IA5String,
/// iPAddress [7] OCTET STRING,
/// registeredID [8] OBJECT IDENTIFIER
/// }
///
/// Currently, only otherName is supported.
fn encode_subject_alt_name_extension(
&mut self,
measurements: &MeasurementData,
) -> Result<usize, DpeErrorCode> {
match &measurements.subject_alt_name {
None => Ok(0),
Some(SubjectAltName::OtherName(other_name)) => {
// Encode Extension
let san_extension_size = Self::get_subject_alt_name_extension_size(
measurements,
/*tagged=*/ false,
)?;
let mut bytes_written = self.encode_byte(Self::SEQUENCE_TAG)?;
bytes_written += self.encode_size_field(san_extension_size)?;
bytes_written += self.encode_oid(Self::SUBJECT_ALTERNATIVE_NAME_OID)?;

bytes_written += self.encode_byte(Self::BOOL_TAG)?;
bytes_written += self.encode_size_field(Self::BOOL_SIZE)?;
// authority key identifier extension must NOT be marked critical
bytes_written += self.encode_byte(0x00)?;

// Extension data is sequence -> octet string. To compute size, wrap
// in tagging once.
let other_name_size = Self::get_other_name_size(other_name, /*tagged=*/ true)?;
bytes_written += self.encode_byte(Self::OCTET_STRING_TAG)?;
bytes_written += self.encode_size_field(Self::get_structure_size(
other_name_size,
/*tagged=*/ true,
)?)?;

bytes_written += self.encode_byte(Self::SEQUENCE_TAG)?;
bytes_written += self.encode_size_field(other_name_size)?;
bytes_written += self.encode_other_name(other_name)?;

Ok(bytes_written)
}
}
}

/// AuthorityKeyIdentifier ::= SEQUENCE {
/// keyIdentifier [0] KeyIdentifier OPTIONAL,
/// authorityCertIssuer [1] GeneralNames OPTIONAL,
Expand Down Expand Up @@ -1526,6 +1674,7 @@ impl CertWriter<'_> {
bytes_written += self.encode_extended_key_usage(measurements)?;
bytes_written += self.encode_subject_key_identifier_extension(measurements, is_x509)?;
bytes_written += self.encode_authority_key_identifier_extension(measurements, is_x509)?;
bytes_written += self.encode_subject_alt_name_extension(measurements)?;

Ok(bytes_written)
}
Expand Down Expand Up @@ -2295,6 +2444,7 @@ pub(crate) mod tests {
supports_recursive: true,
subject_key_identifier: [0u8; MAX_KEY_IDENTIFIER_SIZE],
authority_key_identifier: [0u8; MAX_KEY_IDENTIFIER_SIZE],
subject_alt_name: None,
};

let mut not_before = ArrayVec::new();
Expand Down Expand Up @@ -2381,6 +2531,7 @@ pub(crate) mod tests {
supports_recursive: true,
subject_key_identifier,
authority_key_identifier: subject_key_identifier,
subject_alt_name: None,
};

let mut not_before = ArrayVec::new();
Expand Down
8 changes: 6 additions & 2 deletions platform/src/default.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Licensed under the Apache-2.0 license

use crate::{
CertValidity, Platform, PlatformError, SignerIdentifier, MAX_CHUNK_SIZE, MAX_ISSUER_NAME_SIZE,
MAX_KEY_IDENTIFIER_SIZE,
CertValidity, Platform, PlatformError, SignerIdentifier, SubjectAltName, MAX_CHUNK_SIZE,
MAX_ISSUER_NAME_SIZE, MAX_KEY_IDENTIFIER_SIZE,
};
use arrayvec::ArrayVec;
use cfg_if::cfg_if;
Expand Down Expand Up @@ -197,4 +197,8 @@ impl Platform for DefaultPlatform {
not_after: not_after_vec,
})
}

fn get_subject_alternative_name(&mut self) -> Result<SubjectAltName, PlatformError> {
Err(PlatformError::NotImplemented)
}
}
21 changes: 21 additions & 0 deletions platform/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub const MAX_ISSUER_NAME_SIZE: usize = 128;
pub const MAX_SN_SIZE: usize = 20;
pub const MAX_KEY_IDENTIFIER_SIZE: usize = 20;
pub const MAX_VALIDITY_SIZE: usize = 24;
pub const MAX_OTHER_NAME_SIZE: usize = 128;

#[derive(Debug, PartialEq, Eq)]
pub enum SignerIdentifier {
Expand All @@ -30,6 +31,17 @@ pub enum SignerIdentifier {
SubjectKeyIdentifier(ArrayVec<u8, { MAX_KEY_IDENTIFIER_SIZE }>),
}

#[derive(Debug, PartialEq, Eq)]
pub enum SubjectAltName {
OtherName(OtherName),
}

#[derive(Debug, PartialEq, Eq)]
pub struct OtherName {
pub oid: &'static [u8],
pub other_name: ArrayVec<u8, { MAX_OTHER_NAME_SIZE }>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct CertValidity {
pub not_before: ArrayVec<u8, { MAX_VALIDITY_SIZE }>,
Expand All @@ -47,6 +59,7 @@ pub enum PlatformError {
SubjectKeyIdentifierError(u32) = 0x6,
CertValidityError(u32) = 0x7,
IssuerKeyIdentifierError(u32) = 0x8,
SubjectAlternativeNameError(u32) = 0x9,
}

impl PlatformError {
Expand All @@ -67,6 +80,7 @@ impl PlatformError {
PlatformError::SubjectKeyIdentifierError(code) => Some(*code),
PlatformError::CertValidityError(code) => Some(*code),
PlatformError::IssuerKeyIdentifierError(code) => Some(*code),
PlatformError::SubjectAlternativeNameError(code) => Some(*code),
}
}
}
Expand Down Expand Up @@ -125,4 +139,11 @@ pub trait Platform {
///
/// Example: 99991231235959Z is December 31st, 9999 23:59:59 UTC
fn get_cert_validity(&mut self) -> Result<CertValidity, PlatformError>;

/// Retrieves the SubjectAlternativeName extension
///
/// Currently, only the otherName choice is supported. This function
/// can be left unimplemented if the SubjectAlternativeName extension is
/// not needed in the DPE leaf cert or CSR.
fn get_subject_alternative_name(&mut self) -> Result<SubjectAltName, PlatformError>;
}

0 comments on commit dfce6bf

Please sign in to comment.