Skip to content

Commit

Permalink
[dice,cwt] Endorse and store all 4 DICE CWT/X509 certificates
Browse files Browse the repository at this point in the history
In this implementation,
- Add one more object type "kPersoObjectTypeCwtCert" to reflects the CWT
  implementation
- Update "struct personalize_extension_pre_endorse{}" to pass more OTP
  measurments to the perso_ext for uds_build_tbs()
- Update the personalize_endorse_certificates() logic, to parse the
  payload based on DICE chain type

Bug: 356532759
Test: //sw/device/silicon_creator/manuf/base:ft_provision_cw340
Signed-off-by: Tommy Chiu <[email protected]>
  • Loading branch information
tommychiu-github committed Nov 1, 2024
1 parent 53e532e commit 2c64cde
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 24 deletions.
1 change: 1 addition & 0 deletions sw/device/silicon_creator/lib/cert/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ cc_library(
"//sw/device/silicon_creator/lib:attestation",
"//sw/device/silicon_creator/lib:otbn_boot_services",
"//sw/device/silicon_creator/lib/base:util",
"//sw/device/silicon_creator/lib/drivers:lifecycle",
"//sw/device/silicon_creator/manuf/lib:flash_info_fields",
],
)
Expand Down
2 changes: 2 additions & 0 deletions sw/device/silicon_creator/lib/cert/dice.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ static cdi_1_sig_values_t cdi_1_cert_params = {
.tbs_size = kCdi1MaxTbsSizeBytes,
};

const dice_chain_format_t dice_chain_format = kDiceChainFormatX509;

static_assert(kDiceMeasurementSizeInBytes == 32,
"The DICE attestation measurement size should equal the size of "
"the keymgr binding registers.");
Expand Down
6 changes: 6 additions & 0 deletions sw/device/silicon_creator/lib/cert/dice.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ enum {
kDiceMeasurementSizeInBytes = kDiceMeasurementSizeInBits / 8,
};

typedef enum {
kDiceChainFormatX509 = 0,
kDiceChainFormatCWT = 1,
} dice_chain_format_t;

extern const dice_chain_format_t dice_chain_format;
/**
* DICE ECC key descriptors.
*/
Expand Down
2 changes: 2 additions & 0 deletions sw/device/silicon_creator/lib/cert/dice_cwt.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

#include "otp_ctrl_regs.h" // Generated.

const dice_chain_format_t dice_chain_format = kDiceChainFormatCWT;

// Labels
#define CWT_COSE_KEY_LABEL_TYPE (1)
#define CWT_COSE_KEY_LABEL_ALG (3)
Expand Down
52 changes: 41 additions & 11 deletions sw/device/silicon_creator/manuf/base/ft_personalize.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ static cert_key_id_pair_t cdi_1_key_ids = {
.cert = &cdi_1_pubkey_id,
};
static ecdsa_p256_public_key_t curr_pubkey = {.x = {0}, .y = {0}};
static ecdsa_p256_public_key_t uds_pubkey = {.x = {0}, .y = {0}};
static perso_blob_t perso_blob_to_host; // Perso data device => host.
static perso_blob_t perso_blob_from_host; // Perso data host => device.

Expand Down Expand Up @@ -364,6 +365,7 @@ static status_t hash_certificate(const flash_ctrl_info_page_t *page,
if (size) {
*size = obj_size;
}

return OK_STATUS();
}

Expand Down Expand Up @@ -445,6 +447,7 @@ static status_t personalize_gen_dice_certificates(ujson_t *uj) {
curr_cert_size = kUdsMaxTbsSizeBytes;
TRY(otbn_boot_cert_ecc_p256_keygen(kDiceKeyUds, &uds_pubkey_id,
&curr_pubkey));
memcpy(&uds_pubkey, &curr_pubkey, sizeof(ecdsa_p256_public_key_t));
TRY(otbn_boot_attestation_key_save(kDiceKeyUds.keygen_seed_idx,
kDiceKeyUds.type,
*kDiceKeyUds.keymgr_diversifier));
Expand All @@ -455,7 +458,13 @@ static status_t personalize_gen_dice_certificates(ujson_t *uj) {
&otp_rot_creator_auth_codesign_measurement,
&otp_rot_creator_auth_state_measurement, &uds_key_ids, &curr_pubkey,
all_certs, &curr_cert_size));
TRY(perso_tlv_prepare_cert_for_shipping("UDS", true, all_certs,

bool needs_endorsement;
if (all_certs[0] == 0x30 || all_certs[1] == 0x82)
needs_endorsement = true;
else
needs_endorsement = false;
TRY(perso_tlv_prepare_cert_for_shipping("UDS", needs_endorsement, all_certs,
curr_cert_size, &perso_blob_to_host));

// Generate CDI_0 keys and cert.
Expand Down Expand Up @@ -590,14 +599,28 @@ static status_t personalize_endorse_certificates(ujson_t *uj) {
size_t free_room = sizeof(all_certs);
// Helper structure caching certificate information.
perso_tlv_cert_block_t block;
// UDS cert.
TRY(extract_next_cert(&next_cert, &free_room));

// Now the two CDI certs which were endorsed locally and sent to the host
// earlier.
size_t cdis[] = {cdi_0_offset, cdi_1_offset};
for (size_t i = 0; i < ARRAYSIZE(cdis); i++) {
size_t offset = cdis[i];

size_t cert_offsets[3] = {SIZE_MAX};
size_t cert_offsets_count = 3;
if (dice_chain_format == kDiceChainFormatX509) {
// UDS cert.
TRY(extract_next_cert(&next_cert, &free_room));

// Now the two CDI certs which were endorsed locally and sent to the host
// earlier.
cert_offsets[0] = cdi_0_offset;
cert_offsets[1] = cdi_1_offset;
cert_offsets_count = 2;
} else if (dice_chain_format == kDiceChainFormatCWT) {
// UDS cert will be in the "perso_blob_to_host" as well. So parse it along
// with CDIs
cert_offsets[0] = 0;
cert_offsets[1] = cdi_0_offset;
cert_offsets[2] = cdi_1_offset;
}

for (size_t i = 0; i < cert_offsets_count; i++) {
size_t offset = cert_offsets[i];
TRY(perso_tlv_set_cert_block(perso_blob_to_host.body + offset,
sizeof(perso_blob_to_host.body) - offset,
&block));
Expand All @@ -609,7 +632,6 @@ static status_t personalize_endorse_certificates(ujson_t *uj) {
next_cert += block.obj_size;
free_room -= block.obj_size;
}

// Now the rest of endorsed certificates received from the host, if any.
while (perso_blob_from_host.num_objs)
TRY(extract_next_cert(&next_cert, &free_room));
Expand Down Expand Up @@ -733,7 +755,15 @@ bool test_main(void) {
.certgen_inputs = &certgen_inputs,
.perso_blob_to_host = &perso_blob_to_host,
.cert_flash_layout = cert_flash_layout,
.flash_ctrl_handle = &flash_ctrl_state};
.flash_ctrl_handle = &flash_ctrl_state,
.uds_pubkey = &uds_pubkey,
.uds_pubkey_id = &uds_pubkey_id,
.otp_creator_sw_cfg_measurement = &otp_creator_sw_cfg_measurement,
.otp_owner_sw_cfg_measurement = &otp_owner_sw_cfg_measurement,
.otp_rot_creator_auth_codesign_measurement =
&otp_rot_creator_auth_codesign_measurement,
.otp_rot_creator_auth_state_measurement =
&otp_rot_creator_auth_state_measurement};
CHECK_STATUS_OK(personalize_extension_pre_cert_endorse(&pre_endorse));

CHECK_STATUS_OK(personalize_endorse_certificates(&uj));
Expand Down
7 changes: 5 additions & 2 deletions sw/device/silicon_creator/manuf/base/perso_tlv_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ status_t perso_tlv_set_cert_block(const uint8_t *buf, size_t max_room,
block->obj_size = obj_size;

PERSO_TLV_GET_FIELD(Objh, Type, objh, &obj_type);
if (obj_type != kPersoObjectTypeX509Cert) {
if (obj_type != kPersoObjectTypeX509Cert &&
obj_type != kPersoObjectTypeCwtCert) {
LOG_INFO("Skipping object of type %d", obj_type);
return NOT_FOUND();
}
Expand Down Expand Up @@ -116,7 +117,9 @@ status_t perso_tlv_prepare_cert_for_shipping(const char *name,
if (needs_endorsement) {
PERSO_TLV_SET_FIELD(Objh, Type, obj_header, kPersoObjectTypeX509Tbs);
} else {
PERSO_TLV_SET_FIELD(Objh, Type, obj_header, kPersoObjectTypeX509Cert);
// TODO(lowRISC/opentitan:#24281): should decide the obj_type by other
// factor
PERSO_TLV_SET_FIELD(Objh, Type, obj_header, kPersoObjectTypeCwtCert);
}

PERSO_TLV_SET_FIELD(Objh, Size, obj_header, obj_len);
Expand Down
1 change: 1 addition & 0 deletions sw/device/silicon_creator/manuf/base/perso_tlv_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ typedef enum perso_tlv_object_type {
kPersoObjectTypeX509Tbs = 0,
kPersoObjectTypeX509Cert = 1,
kPersoObjectTypeDevSeed = 2,
kPersoObjectTypeCwtCert = 3,
} perso_tlv_object_type_t;

typedef uint16_t perso_tlv_object_header_t;
Expand Down
14 changes: 14 additions & 0 deletions sw/device/silicon_creator/manuf/base/personalize_ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@ typedef struct personalize_extension_pre_endorse {
* Pointer to the flash controller handle necessary for proper flash access.
*/
dif_flash_ctrl_state_t *flash_ctrl_handle;

/**
* Pointer to the UDS public key necessary for the following perso extension.
*/
ecdsa_p256_public_key_t *uds_pubkey;
hmac_digest_t *uds_pubkey_id;

/**
* Pointer to the OTP measurements necessary for the following perso extension.
*/
hmac_digest_t *otp_creator_sw_cfg_measurement;
hmac_digest_t *otp_owner_sw_cfg_measurement;
hmac_digest_t *otp_rot_creator_auth_codesign_measurement;
hmac_digest_t *otp_rot_creator_auth_state_measurement;
} personalize_extension_pre_endorse_t;

/**
Expand Down
18 changes: 7 additions & 11 deletions sw/host/provisioning/ft_lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,15 +241,6 @@ fn get_cert(data: &[u8]) -> Result<CertHeader> {
let header_size = header_len + name_len;
let cert_body: Vec<u8> = data[header_size..wrapped_size].to_vec();

// Sanity check, total size and cert size must match
let cert_size = get_cert_size(&cert_body)?;
if cert_size != cert_body.len() {
bail!(
"cert size {} does not match length {}",
cert_size,
cert_body.len()
);
}
Ok(CertHeader {
wrapped_size,
cert_name,
Expand Down Expand Up @@ -343,7 +334,9 @@ fn provision_certificates(
}
start += obj_header_size;
match header.obj_type {
ObjType::EndorsedX509Cert | ObjType::UnendorsedX509Cert => (),
ObjType::EndorsedX509Cert | ObjType::UnendorsedX509Cert | ObjType::EndorsedCwtCert => {
()
}
ObjType::DevSeed => {
let dev_seed_size = header.obj_size - obj_header_size;
let seeds = &perso_blob.body[start..start + dev_seed_size];
Expand Down Expand Up @@ -380,7 +373,10 @@ fn provision_certificates(
};
// Ensure all certs parse with OpenSSL (even those that where endorsed on device).
log::info!("{} Cert: {}", cert.cert_name, hex::encode(&cert_bytes));
let _ = parse_certificate(&cert_bytes)?;
// TODO(lowRISC/opentitan:#24281): Add CWT parser
if header.obj_type != ObjType::DevSeed && header.obj_type != ObjType::EndorsedCwtCert {
let _ = parse_certificate(&cert_bytes)?;
}
// Push the cert into the hasher so we can ensure the certs written to the device's flash
// info pages match those verified on the host.
cert_hasher.update(cert_bytes);
Expand Down
2 changes: 2 additions & 0 deletions sw/host/provisioning/perso_tlv_lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub enum ObjType {
UnendorsedX509Cert = perso_tlv_objects::perso_tlv_object_type_kPersoObjectTypeX509Tbs as isize,
EndorsedX509Cert = perso_tlv_objects::perso_tlv_object_type_kPersoObjectTypeX509Cert as isize,
DevSeed = perso_tlv_objects::perso_tlv_object_type_kPersoObjectTypeDevSeed as isize,
EndorsedCwtCert = perso_tlv_objects::perso_tlv_object_type_kPersoObjectTypeCwtCert as isize,
}

impl ObjType {
Expand All @@ -19,6 +20,7 @@ impl ObjType {
0 => Ok(ObjType::UnendorsedX509Cert),
1 => Ok(ObjType::EndorsedX509Cert),
2 => Ok(ObjType::DevSeed),
3 => Ok(ObjType::EndorsedCwtCert),
_ => bail!("incorrect input value of {value} for ObjType"),
}
}
Expand Down

0 comments on commit 2c64cde

Please sign in to comment.