Skip to content

Commit

Permalink
Move all tests to use shared test file
Browse files Browse the repository at this point in the history
Make it easier to run DPE tests against different targets by putting all
the test cases in a test vector file. This allows test infrastructure
for a specific target to add required setup and transport code and then
execute the tests in a loop.

In particular, this is to support easily running these tests against a
Caliptra HwModel target.

Additional fixes:

* Make hex string conversion use all caps. This matches what Caliptra
  uses for subject/issuer serialNumber fields.
* Support encoding X.509 Directory Strings as either PrintableString or
  UTF8String. This allows more flexibility when specifying issuer
  encodings.
  • Loading branch information
jhand2 committed Oct 10, 2023
1 parent 07c17de commit fb9d4c3
Show file tree
Hide file tree
Showing 18 changed files with 366 additions and 777 deletions.
4 changes: 2 additions & 2 deletions ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ function test_rust_targets() {
function run_verification_tests() {
profile=$1

cargo build --manifest-path simulator/Cargo.toml #--features=$profile --no-default-features
cargo build --manifest-path simulator/Cargo.toml --features=$profile --no-default-features

( cd verification
go test
go test -v
)
}

Expand Down
2 changes: 1 addition & 1 deletion crypto/src/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ impl CryptoBuf {
}

let mut curr_idx = 0;
const HEX_CHARS: &[u8; 16] = b"0123456789abcdef";
const HEX_CHARS: &[u8; 16] = b"0123456789ABCDEF";
for &b in src {
let h1 = (b >> 4) as usize;
let h2 = (b & 0xF) as usize;
Expand Down
16 changes: 9 additions & 7 deletions dpe/src/commands/certify_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
dpe_instance::{DpeEnv, DpeInstance, DpeTypes},
response::{CertifyKeyResp, DpeErrorCode, Response, ResponseHdr},
tci::TciNodeData,
x509::{MeasurementData, Name, X509CertWriter},
x509::{DirectoryString, MeasurementData, Name, X509CertWriter},
DPE_PROFILE, MAX_CERT_SIZE, MAX_HANDLES,
};
use bitflags::bitflags;
Expand Down Expand Up @@ -82,14 +82,16 @@ impl CommandExecution for CertifyKeyCmd {
.derive_key_pair(algs, &cdi, &self.label, b"ECC")
.map_err(|_| DpeErrorCode::CryptoError)?;

let mut subject_name = Name {
cn: b"DPE Leaf",
serial: [0u8; DPE_PROFILE.get_hash_size() * 2],
};
let mut subj_serial = [0u8; DPE_PROFILE.get_hash_size() * 2];
env.crypto
.get_pubkey_serial(DPE_PROFILE.alg_len(), &pub_key, &mut subject_name.serial)
.get_pubkey_serial(DPE_PROFILE.alg_len(), &pub_key, &mut subj_serial)
.map_err(|_| DpeErrorCode::CryptoError)?;

let subject_name = Name {
cn: DirectoryString::PrintableString(b"DPE Leaf"),
serial: DirectoryString::PrintableString(&subj_serial),
};

// Get TCI Nodes
const INITIALIZER: TciNodeData = TciNodeData::new();
let mut nodes = [INITIALIZER; MAX_HANDLES];
Expand Down Expand Up @@ -122,7 +124,7 @@ impl CommandExecution for CertifyKeyCmd {
}
let mut bytes_written = tbs_writer.encode_ecdsa_tbs(
/*serial=*/
&subject_name.serial[..20], // Serial number must be truncated to 20 bytes
&subject_name.serial.bytes()[..20], // Serial number must be truncated to 20 bytes
&issuer_name[..issuer_len],
&subject_name,
&pub_key,
Expand Down
76 changes: 53 additions & 23 deletions dpe/src/x509.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,34 @@ use crate::{
use bitflags::bitflags;
use crypto::{EcdsaPub, EcdsaSig};

pub enum DirectoryString<'a> {
PrintableString(&'a [u8]),
Utf8String(&'a [u8]),
}

impl DirectoryString<'_> {
pub fn len(&self) -> usize {
self.bytes().len()
}

pub fn is_empty(&self) -> bool {
self.bytes().is_empty()
}

pub fn bytes(&self) -> &[u8] {
match self {
Self::PrintableString(val) => val,
Self::Utf8String(val) => val,
}
}
}

/// Type for specifying an X.509 RelativeDistinguisedName
///
/// `serial` is expected to hold a hex string of the hash of the public key
pub struct Name<'a> {
pub cn: &'a [u8],
pub serial: [u8; DPE_PROFILE.get_hash_size() * 2],
pub cn: DirectoryString<'a>,
pub serial: DirectoryString<'a>,
}

pub struct MeasurementData<'a> {
Expand Down Expand Up @@ -48,6 +70,7 @@ impl X509CertWriter<'_> {
const BIT_STRING_TAG: u8 = 0x3;
const OCTET_STRING_TAG: u8 = 0x4;
const OID_TAG: u8 = 0x6;
const UTF8_STRING_TAG: u8 = 0xC;
const PRINTABLE_STRING_TAG: u8 = 0x13;
const GENERALIZE_TIME_TAG: u8 = 0x18;
const SEQUENCE_TAG: u8 = 0x30;
Expand Down Expand Up @@ -187,12 +210,12 @@ impl X509CertWriter<'_> {
fn get_rdn_size(name: &Name, tagged: bool) -> Result<usize, DpeErrorCode> {
let cn_seq_size = Self::get_structure_size(
Self::get_bytes_size(&Self::RDN_COMMON_NAME_OID, /*tagged=*/ true)?
+ Self::get_bytes_size(name.cn, true)?,
+ Self::get_bytes_size(name.cn.bytes(), true)?,
/*tagged=*/ true,
)?;
let serialnumber_seq_size = Self::get_structure_size(
Self::get_bytes_size(&Self::RDN_COMMON_NAME_OID, /*tagged=*/ true)?
+ Self::get_bytes_size(&name.serial, /*tagged=*/ true)?,
+ Self::get_bytes_size(name.serial.bytes(), /*tagged=*/ true)?,
/*tagged=*/ true,
)?;

Expand Down Expand Up @@ -507,10 +530,17 @@ impl X509CertWriter<'_> {
Ok(bytes_written)
}

fn encode_printable_string(&mut self, s: &[u8]) -> Result<usize, DpeErrorCode> {
let mut bytes_written = self.encode_tag_field(Self::PRINTABLE_STRING_TAG)?;
bytes_written += self.encode_size_field(s.len())?;
bytes_written += self.encode_bytes(s)?;
/// Encode a DirectoryString for an RDN. Multiple string types are allowed, so
/// this function accepts a `tag`. This is important because some verifiers
/// will do an exact DER comparison when building cert chains.
fn encode_rdn_string(&mut self, s: &DirectoryString) -> Result<usize, DpeErrorCode> {
let (val, tag) = match s {
DirectoryString::PrintableString(val) => (val, Self::PRINTABLE_STRING_TAG),
DirectoryString::Utf8String(val) => (val, Self::UTF8_STRING_TAG),
};
let mut bytes_written = self.encode_tag_field(tag)?;
bytes_written += self.encode_size_field(val.len())?;
bytes_written += self.encode_bytes(val)?;

Ok(bytes_written)
}
Expand Down Expand Up @@ -559,7 +589,7 @@ impl X509CertWriter<'_> {
bytes_written += self.encode_tag_field(Self::SEQUENCE_TAG)?;
bytes_written += self.encode_size_field(cn_size)?;
bytes_written += self.encode_oid(&Self::RDN_COMMON_NAME_OID)?;
bytes_written += self.encode_printable_string(name.cn)?;
bytes_written += self.encode_rdn_string(&name.cn)?;

// Encode RDN SET
bytes_written += self.encode_tag_field(Self::SET_OF_TAG)?;
Expand All @@ -569,7 +599,7 @@ impl X509CertWriter<'_> {
bytes_written += self.encode_tag_field(Self::SEQUENCE_TAG)?;
bytes_written += self.encode_size_field(serialnumber_size)?;
bytes_written += self.encode_oid(&Self::RDN_SERIALNUMBER_OID)?;
bytes_written += self.encode_printable_string(&name.serial)?;
bytes_written += self.encode_rdn_string(&name.serial)?;

Ok(bytes_written)
}
Expand Down Expand Up @@ -1140,7 +1170,7 @@ impl X509CertWriter<'_> {
#[cfg(test)]
mod tests {
use crate::tci::{TciMeasurement, TciNodeData};
use crate::x509::{MeasurementData, Name, X509CertWriter};
use crate::x509::{DirectoryString, MeasurementData, Name, X509CertWriter};
use crate::DPE_PROFILE;
use crypto::{CryptoBuf, EcdsaPub, EcdsaSig};
use std::str;
Expand Down Expand Up @@ -1185,8 +1215,8 @@ mod tests {
}

const TEST_ISSUER: Name = Name {
cn: b"Caliptra Alias",
serial: [0x00; DPE_PROFILE.get_hash_size() * 2],
cn: DirectoryString::PrintableString(b"Caliptra Alias"),
serial: DirectoryString::PrintableString(&[0x00; DPE_PROFILE.get_hash_size() * 2]),
};

fn encode_test_issuer() -> Vec<u8> {
Expand Down Expand Up @@ -1238,8 +1268,8 @@ mod tests {
fn test_rdn() {
let mut cert = [0u8; 256];
let test_name = Name {
cn: b"Caliptra Alias",
serial: [0x0u8; DPE_PROFILE.get_hash_size() * 2],
cn: DirectoryString::PrintableString(b"Caliptra Alias"),
serial: DirectoryString::PrintableString(&[0x0u8; DPE_PROFILE.get_hash_size() * 2]),
};

let mut w = X509CertWriter::new(&mut cert, true);
Expand All @@ -1252,8 +1282,8 @@ mod tests {

let expected = format!(
"CN={}, serialNumber={}",
str::from_utf8(test_name.cn).unwrap(),
str::from_utf8(&test_name.serial).unwrap()
str::from_utf8(test_name.cn.bytes()).unwrap(),
str::from_utf8(&test_name.serial.bytes()).unwrap()
);
let actual = name.to_string_with_registry(oid_registry()).unwrap();
assert_eq!(expected, actual);
Expand Down Expand Up @@ -1353,8 +1383,8 @@ mod tests {
let issuer_der = encode_test_issuer();

let test_subject_name = Name {
cn: b"DPE Leaf",
serial: [0x00; DPE_PROFILE.get_hash_size() * 2],
cn: DirectoryString::PrintableString(b"DPE Leaf"),
serial: DirectoryString::PrintableString(&[0x00; DPE_PROFILE.get_hash_size() * 2]),
};

const ECC_INT_SIZE: usize = DPE_PROFILE.get_ecc_int_size();
Expand Down Expand Up @@ -1402,12 +1432,12 @@ mod tests {

const TEST_SERIAL: &[u8] = &[0x1F; 20];
const TEST_ISSUER_NAME: Name = Name {
cn: b"Caliptra Alias",
serial: [0x00; DPE_PROFILE.get_hash_size() * 2],
cn: DirectoryString::PrintableString(b"Caliptra Alias"),
serial: DirectoryString::PrintableString(&[0x00; DPE_PROFILE.get_hash_size() * 2]),
};
const TEST_SUBJECT_NAME: Name = Name {
cn: b"DPE Leaf",
serial: [0x00; DPE_PROFILE.get_hash_size() * 2],
cn: DirectoryString::PrintableString(b"DPE Leaf"),
serial: DirectoryString::PrintableString(&[0x00; DPE_PROFILE.get_hash_size() * 2]),
};

const ECC_INT_SIZE: usize = DPE_PROFILE.get_ecc_int_size();
Expand Down
11 changes: 8 additions & 3 deletions simulator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ name = "simulator"
version = "0.1.0"
edition = "2021"

[features]
default = ["dpe_profile_p256_sha256"]
dpe_profile_p256_sha256 = ["dpe/dpe_profile_p256_sha256", "crypto/dpe_profile_p256_sha256", "platform/dpe_profile_p256_sha256"]
dpe_profile_p384_sha384 = ["dpe/dpe_profile_p384_sha384", "crypto/dpe_profile_p384_sha384", "platform/dpe_profile_p384_sha384"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
Expand All @@ -13,6 +18,6 @@ openssl = "0.10.57"
clap = { version = "4.1.8", features = ["derive"] }
log = "0.4.17"
env_logger = "0.10.0"
dpe = { path = "../dpe" }
crypto = { path = "../crypto", features = ["openssl"] }
platform = { path = "../platform", features = ["openssl"] }
dpe = { path = "../dpe", default-features = false }
crypto = { path = "../crypto", default-features = false, features = ["openssl"] }
platform = { path = "../platform", default-features = false, features = ["openssl"] }
Loading

0 comments on commit fb9d4c3

Please sign in to comment.