Skip to content

Commit

Permalink
[rom_ext, attestation] Fix DICE measurements
Browse files Browse the repository at this point in the history
1. Report the DICE measurements in big-endian order.
2. Check the key IDs reported by the DICE certs.

Signed-off-by: Chris Frantz <cfrantz@google.com>
  • Loading branch information
cfrantz committed Oct 21, 2024
1 parent edabd2f commit dcfe293
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 19 deletions.
31 changes: 19 additions & 12 deletions sw/device/silicon_creator/lib/dice.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ static bool is_debug_exposed(void) {
* Helper function to convert a buffer of bytes from little to big endian in
* place.
*/
static void le_be_buf_format(unsigned char *buf, size_t num_bytes) {
static void le_be_buf_format(void *ptr, size_t num_bytes) {
unsigned char *buf = (unsigned char *)ptr;
unsigned char temp;
for (size_t i = 0; i < (num_bytes / 2); ++i) {
temp = buf[i];
Expand All @@ -90,8 +91,8 @@ static void le_be_buf_format(unsigned char *buf, size_t num_bytes) {
* endian in place.
*/
static void curr_pubkey_le_to_be_convert(attestation_public_key_t *pubkey) {
le_be_buf_format((unsigned char *)pubkey->x, kAttestationPublicKeyCoordBytes);
le_be_buf_format((unsigned char *)pubkey->y, kAttestationPublicKeyCoordBytes);
le_be_buf_format(pubkey->x, kAttestationPublicKeyCoordBytes);
le_be_buf_format(pubkey->y, kAttestationPublicKeyCoordBytes);
}

rom_error_t dice_attestation_keygen(dice_key_t desired_key,
Expand Down Expand Up @@ -160,7 +161,7 @@ rom_error_t dice_attestation_keygen(dice_key_t desired_key,
// endian form, but the HMAC driver returns the digest in little endian, so we
// re-format it.
hmac_sha256(pubkey, kAttestationPublicKeyCoordBytes * 2, pubkey_id);
le_be_buf_format((unsigned char *)pubkey_id, kHmacDigestNumBytes);
le_be_buf_format(pubkey_id, kHmacDigestNumBytes);

return kErrorOk;
}
Expand All @@ -170,10 +171,8 @@ rom_error_t dice_attestation_keygen(dice_key_t desired_key,
* to big endian.
*/
static void curr_tbs_signature_le_to_be_convert(attestation_signature_t *sig) {
le_be_buf_format((unsigned char *)sig->r,
kAttestationSignatureComponentBytes);
le_be_buf_format((unsigned char *)sig->s,
kAttestationSignatureComponentBytes);
le_be_buf_format(sig->r, kAttestationSignatureComponentBytes);
le_be_buf_format(sig->s, kAttestationSignatureComponentBytes);
}

/**
Expand All @@ -185,6 +184,7 @@ static void measure_otp_partition(otp_partition_t partition,
otp_dai_read(partition, /*address=*/0, otp_state,
kOtpPartitions[partition].size / sizeof(uint32_t));
hmac_sha256(otp_state, kOtpPartitions[partition].size, measurement);
le_be_buf_format(measurement, sizeof(*measurement));
}

rom_error_t dice_uds_tbs_cert_build(dice_cert_key_id_pair_t *key_ids,
Expand Down Expand Up @@ -226,9 +226,12 @@ rom_error_t dice_cdi_0_cert_build(hmac_digest_t *rom_ext_measurement,
dice_cert_key_id_pair_t *key_ids,
attestation_public_key_t *cdi_0_pubkey,
uint8_t *cert, size_t *cert_size) {
hmac_digest_t rom_ext_hash = *rom_ext_measurement;
le_be_buf_format(&rom_ext_hash, sizeof(rom_ext_hash));

// Generate the TBS certificate.
cdi_0_tbs_values_t cdi_0_cert_tbs_params = {
.rom_ext_hash = (unsigned char *)rom_ext_measurement->digest,
.rom_ext_hash = (unsigned char *)rom_ext_hash.digest,
.rom_ext_hash_size = kDiceMeasurementSizeInBytes,
.rom_ext_security_version = rom_ext_security_version,
.owner_intermediate_pub_key_id = (unsigned char *)key_ids->cert->digest,
Expand Down Expand Up @@ -271,12 +274,16 @@ rom_error_t dice_cdi_1_cert_build(hmac_digest_t *owner_measurement,
dice_cert_key_id_pair_t *key_ids,
attestation_public_key_t *cdi_1_pubkey,
uint8_t *cert, size_t *cert_size) {
hmac_digest_t owner_hash = *owner_measurement;
hmac_digest_t owner_manifest_hash = *owner_manifest_measurement;
le_be_buf_format(&owner_hash, sizeof(owner_hash));
le_be_buf_format(&owner_manifest_hash, sizeof(owner_manifest_hash));

// Generate the TBS certificate.
cdi_1_tbs_values_t cdi_1_cert_tbs_params = {
.owner_hash = (unsigned char *)owner_measurement->digest,
.owner_hash = (unsigned char *)owner_hash.digest,
.owner_hash_size = kDiceMeasurementSizeInBytes,
.owner_manifest_hash =
(unsigned char *)owner_manifest_measurement->digest,
.owner_manifest_hash = (unsigned char *)owner_manifest_hash.digest,
.owner_manifest_hash_size = kDiceMeasurementSizeInBytes,
.owner_security_version = owner_security_version,
.owner_pub_key_id = (unsigned char *)key_ids->cert->digest,
Expand Down
1 change: 1 addition & 0 deletions sw/host/tests/attestation/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ rust_binary(
"@crate_index//:anyhow",
"@crate_index//:base64ct",
"@crate_index//:clap",
"@crate_index//:hex",
"@crate_index//:humantime",
"@crate_index//:log",
"@crate_index//:num-bigint-dig",
Expand Down
51 changes: 44 additions & 7 deletions sw/host/tests/attestation/attestation_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use opentitanlib::test_utils::init::InitializeTest;
use opentitanlib::uart::console::UartConsole;
use opentitanlib::util::file::FromReader;

use ot_certs::template::{CertificateExtension, Value};
use ot_certs::template::{AttributeType, CertificateExtension, Name, SubjectPublicKeyInfo, Value};
use ot_certs::x509;

#[derive(Debug, Parser)]
Expand Down Expand Up @@ -68,6 +68,23 @@ fn get_base64_blob(haystack: &str, rx: &str) -> Result<Vec<u8>> {
Ok(bin)
}

fn check_public_key(key: &SubjectPublicKeyInfo, id: &[u8], subject: &Name) -> Result<bool> {
let SubjectPublicKeyInfo::EcPublicKey(info) = key;

let mut material = Vec::new();
material.extend(&info.public_key.x.get_value().to_bytes_be());
material.extend(&info.public_key.y.get_value().to_bytes_be());
let hash = sha256::sha256(&material).to_be_bytes();
let keyid = &hash[..20];
log::info!("computed id = {:?}", hex::encode(keyid));
log::info!(" id = {:?}", hex::encode(id));

let name = subject[0][&AttributeType::SerialNumber].get_value();
log::info!(" subject = {:?}", name);

Ok(keyid == id && &hex::encode(keyid) == name)
}

fn attestation_test(opts: &Opts, transport: &TransportWrapper) -> Result<()> {
let uart = transport.uart("console")?;
let capture = UartConsole::wait_for(
Expand All @@ -90,20 +107,26 @@ fn attestation_test(opts: &Opts, transport: &TransportWrapper) -> Result<()> {

let image = Image::read_from_file(opts.init.bootstrap.bootstrap.as_deref().unwrap())?;

// TODO: determine the correct endianness for expressing these measurements.
let measurements = image
.subimages()?
.iter()
.map(|s| s.compute_digest().unwrap().to_le_bytes())
.map(|s| s.compute_digest().unwrap().to_be_bytes())
.collect::<Vec<_>>();
let owner_measurements = [
// The owner page digests should not include the signature or seal fields.
sha256::sha256(&owner_page_0[0..OwnerBlock::SIGNATURE_OFFSET]).to_le_bytes(),
sha256::sha256(&owner_page_1[0..OwnerBlock::SIGNATURE_OFFSET]).to_le_bytes(),
sha256::sha256(&owner_page_0[0..OwnerBlock::SIGNATURE_OFFSET]).to_be_bytes(),
sha256::sha256(&owner_page_1[0..OwnerBlock::SIGNATURE_OFFSET]).to_be_bytes(),
];

let CertificateExtension::DiceTcbInfo(dice) = &cdi0.private_extensions[0];
log::info!("Checking CDI_0 (ROM_EXT) DICE Extension: {dice:#?}");
log::info!("Checking CDI_0 (ROM_EXT) DICE certificate: {cdi0:#?}");
// Check that the subject key and subject key identifiers match.
log::info!("Subject key:");
assert!(check_public_key(
&cdi0.subject_public_key_info,
cdi0.subject_key_identifier.get_value(),
&cdi0.subject,
)?);
assert_eq!(dice.model.get_value(), "ROM_EXT");
assert_eq!(dice.vendor.get_value(), "OpenTitan");
assert_eq!(dice.layer.get_value(), &BigUint::from(1u8));
Expand All @@ -112,7 +135,21 @@ fn attestation_test(opts: &Opts, transport: &TransportWrapper) -> Result<()> {
assert_eq!(fw_ids[0].digest.get_value(), &measurements[0]);

let CertificateExtension::DiceTcbInfo(dice) = &cdi1.private_extensions[0];
log::info!("Checking CDI_1 (Owner) DICE Extension: {dice:#?}");
log::info!("Checking CDI_1 (Owner) DICE certificate: {cdi1:#?}");
// Check that the subject key and subject key identifiers match.
log::info!("Subject key:");
assert!(check_public_key(
&cdi1.subject_public_key_info,
cdi1.subject_key_identifier.get_value(),
&cdi1.subject,
)?);
// Check that the authority key identifier of CDI_1 is the subject key of CDI_0.
log::info!("Issuer key:");
assert!(check_public_key(
&cdi0.subject_public_key_info,
cdi1.authority_key_identifier.get_value(),
&cdi1.issuer,
)?);
assert_eq!(dice.model.get_value(), "Owner");
assert_eq!(dice.vendor.get_value(), "OpenTitan");
assert_eq!(dice.layer.get_value(), &BigUint::from(2u8));
Expand Down

0 comments on commit dcfe293

Please sign in to comment.