Skip to content

Commit 5626516

Browse files
tommychiu-githubtimothytrippel
authored andcommitted
[dice,cwt] Endorse and store all 4 DICE CWT/X509 certificates
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]>
1 parent 6030ae2 commit 5626516

File tree

9 files changed

+93
-35
lines changed

9 files changed

+93
-35
lines changed

sw/device/silicon_creator/lib/cert/cert.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ enum {
5151
kCertKeyIdSizeInBytes = kCertX509Asn1SerialNumberSizeInBytes,
5252
};
5353

54+
/**
55+
* DICE certificate format. It supports 2 types currently.
56+
* Each DICE implementation declares one of those specifically.
57+
*/
58+
typedef enum dice_cert_format {
59+
kDiceCertFormatX509TcbInfo = 0,
60+
kDiceCertFormatCWTAndroid = 1,
61+
} dice_cert_format_t;
62+
5463
/**
5564
* Defines a grouping of certificates onto a single flash info page.
5665
*/

sw/device/silicon_creator/lib/cert/dice.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ static cdi_1_sig_values_t cdi_1_cert_params = {
3434
.tbs_size = kCdi1MaxTbsSizeBytes,
3535
};
3636

37+
const dice_cert_format_t kDiceCertFormat = kDiceCertFormatX509TcbInfo;
38+
3739
static_assert(kDiceMeasurementSizeInBytes == 32,
3840
"The DICE attestation measurement size should equal the size of "
3941
"the keymgr binding registers.");

sw/device/silicon_creator/lib/cert/dice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ enum {
2323
kDiceMeasurementSizeInBytes = kDiceMeasurementSizeInBits / 8,
2424
};
2525

26+
extern const dice_cert_format_t kDiceCertFormat;
2627
/**
2728
* DICE ECC key descriptors.
2829
*/

sw/device/silicon_creator/manuf/base/ft_personalize.c

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,15 @@ static cert_key_id_pair_t cdi_1_key_ids = {
107107
.cert = &cdi_1_pubkey_id,
108108
};
109109
static ecdsa_p256_public_key_t curr_pubkey = {.x = {0}, .y = {0}};
110+
static ecdsa_p256_public_key_t uds_pubkey = {.x = {0}, .y = {0}};
110111
static perso_blob_t perso_blob_to_host; // Perso data device => host.
111112
static perso_blob_t perso_blob_from_host; // Perso data host => device.
112113

113114
/**
114115
* Certificates flash info page layout.
115116
*/
116117
static uint8_t all_certs[8192];
118+
static size_t uds_offset;
117119
static size_t cdi_0_offset;
118120
static size_t cdi_1_offset;
119121
static cert_flash_info_layout_t cert_flash_layout[] = {
@@ -367,6 +369,7 @@ static status_t hash_certificate(const flash_ctrl_info_page_t *page,
367369
if (size) {
368370
*size = obj_size;
369371
}
372+
370373
return OK_STATUS();
371374
}
372375

@@ -456,6 +459,7 @@ static status_t personalize_gen_dice_certificates(ujson_t *uj) {
456459
curr_cert_size = kUdsMaxTbsSizeBytes;
457460
TRY(otbn_boot_cert_ecc_p256_keygen(kDiceKeyUds, &uds_pubkey_id,
458461
&curr_pubkey));
462+
memcpy(&uds_pubkey, &curr_pubkey, sizeof(ecdsa_p256_public_key_t));
459463
TRY(otbn_boot_attestation_key_save(kDiceKeyUds.keygen_seed_idx,
460464
kDiceKeyUds.type,
461465
*kDiceKeyUds.keymgr_diversifier));
@@ -468,9 +472,11 @@ static status_t personalize_gen_dice_certificates(ujson_t *uj) {
468472
all_certs, &curr_cert_size));
469473
// DO NOT CHANGE THE "UDS" STRING BELOW with modifying the `dice_cert_names`
470474
// collection in sw/host/provisioning/ft_lib/src/lib.rs.
471-
TRY(perso_tlv_push_cert_to_perso_blob("UDS", /*needs_endorsement=*/true,
472-
all_certs, curr_cert_size,
473-
&perso_blob_to_host));
475+
uds_offset = perso_blob_to_host.next_free;
476+
TRY(perso_tlv_push_cert_to_perso_blob(
477+
"UDS",
478+
/*needs_endorsement=*/kDiceCertFormat == kDiceCertFormatX509TcbInfo,
479+
all_certs, curr_cert_size, &perso_blob_to_host));
474480
LOG_INFO("Generated UDS certificate.");
475481

476482
// Generate CDI_0 keys and cert.
@@ -628,14 +634,24 @@ static status_t personalize_endorse_certificates(ujson_t *uj) {
628634
// LTV object.
629635
perso_tlv_cert_obj_t block;
630636

631-
// Exract the UDS cert perso LTV object.
632-
TRY(extract_next_cert(&next_cert, &free_room));
633-
634-
// Extract the two CDI cert perso LTV objects which were endorsed on-device
635-
// and sent to the host.
636-
size_t cdi_offsets[] = {cdi_0_offset, cdi_1_offset};
637-
for (size_t i = 0; i < ARRAYSIZE(cdi_offsets); i++) {
638-
size_t offset = cdi_offsets[i];
637+
// CWT DICE doesn't need host to endorse any certificate for it, so all
638+
// payload are in the "perso_blob_to_host".
639+
// Default to this setting, and move to X509 setting if the flag is set.
640+
size_t cert_offsets[3] = {uds_offset, cdi_0_offset, cdi_1_offset};
641+
size_t cert_offsets_count = 3;
642+
if (kDiceCertFormat == kDiceCertFormatX509TcbInfo) {
643+
// Exract the UDS cert perso LTV object.
644+
TRY(extract_next_cert(&next_cert, &free_room));
645+
// Extract the two CDI cert perso LTV objects which were endorsed on-device
646+
// and sent to the host.
647+
cert_offsets[0] = cert_offsets[1];
648+
cert_offsets[1] = cert_offsets[2];
649+
cert_offsets_count = 2;
650+
}
651+
// Extract the cert perso LTV objects which were endorsed on-device and send
652+
// to the host.
653+
for (size_t i = 0; i < cert_offsets_count; i++) {
654+
size_t offset = cert_offsets[i];
639655
TRY(perso_tlv_get_cert_obj(perso_blob_to_host.body + offset,
640656
sizeof(perso_blob_to_host.body) - offset,
641657
&block));
@@ -782,7 +798,15 @@ bool test_main(void) {
782798
.certgen_inputs = &certgen_inputs,
783799
.perso_blob_to_host = &perso_blob_to_host,
784800
.cert_flash_layout = cert_flash_layout,
785-
.flash_ctrl_handle = &flash_ctrl_state};
801+
.flash_ctrl_handle = &flash_ctrl_state,
802+
.uds_pubkey = &uds_pubkey,
803+
.uds_pubkey_id = &uds_pubkey_id,
804+
.otp_creator_sw_cfg_measurement = &otp_creator_sw_cfg_measurement,
805+
.otp_owner_sw_cfg_measurement = &otp_owner_sw_cfg_measurement,
806+
.otp_rot_creator_auth_codesign_measurement =
807+
&otp_rot_creator_auth_codesign_measurement,
808+
.otp_rot_creator_auth_state_measurement =
809+
&otp_rot_creator_auth_state_measurement};
786810
CHECK_STATUS_OK(personalize_extension_pre_cert_endorse(&pre_endorse));
787811

788812
CHECK_STATUS_OK(personalize_endorse_certificates(&uj));

sw/device/silicon_creator/manuf/base/perso_tlv_data.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ rom_error_t perso_tlv_get_cert_obj(uint8_t *buf, size_t ltv_buf_size,
2828
// Extract LTV object type.
2929
PERSO_TLV_GET_FIELD(Objh, Type, objh, &obj_type);
3030
obj->obj_type = obj_type;
31-
if (obj_type != kPersoObjectTypeX509Cert) {
31+
if (obj_type != kPersoObjectTypeX509Cert &&
32+
obj_type != kPersoObjectTypeCwtCert) {
3233
LOG_INFO("Skipping object of type %d", obj_type);
3334
return kErrorPersoTlvCertObjNotFound;
3435
}
@@ -67,12 +68,15 @@ rom_error_t perso_tlv_get_cert_obj(uint8_t *buf, size_t ltv_buf_size,
6768
obj->cert_body_p = buf;
6869

6970
// Sanity check on the certificate body size.
70-
size_t decoded_cert_size =
71-
cert_x509_asn1_decode_size_header(obj->cert_body_p);
72-
if (decoded_cert_size != obj->cert_body_size) {
73-
LOG_ERROR("Unexpected cert size %d instead of %d for cert %s",
74-
decoded_cert_size, obj->cert_body_size, obj->name);
75-
return kErrorPersoTlvInternal;
71+
// TODO(24281): add sanity check on CWT certificate body size.
72+
if (obj_type == kPersoObjectTypeX509Cert) {
73+
size_t decoded_cert_size =
74+
cert_x509_asn1_decode_size_header(obj->cert_body_p);
75+
if (decoded_cert_size != obj->cert_body_size) {
76+
LOG_ERROR("Unexpected cert size %d instead of %d for cert %s",
77+
decoded_cert_size, obj->cert_body_size, obj->name);
78+
return kErrorPersoTlvInternal;
79+
}
7680
}
7781

7882
return kErrorOk;
@@ -106,7 +110,10 @@ rom_error_t perso_tlv_cert_obj_build(const char *name, bool needs_endorsement,
106110
if (needs_endorsement) {
107111
PERSO_TLV_SET_FIELD(Objh, Type, obj_header, kPersoObjectTypeX509Tbs);
108112
} else {
109-
PERSO_TLV_SET_FIELD(Objh, Type, obj_header, kPersoObjectTypeX509Cert);
113+
// TODO(lowRISC/opentitan:#24281): should decide the obj_type by other
114+
// factor
115+
// PERSO_TLV_SET_FIELD(Objh, Type, obj_header, kPersoObjectTypeX509Cert);
116+
PERSO_TLV_SET_FIELD(Objh, Type, obj_header, kPersoObjectTypeCwtCert);
110117
}
111118
PERSO_TLV_SET_FIELD(Objh, Size, obj_header, obj_size);
112119

sw/device/silicon_creator/manuf/base/perso_tlv_data.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ typedef enum perso_tlv_object_type {
2929
kPersoObjectTypeX509Tbs = 0,
3030
kPersoObjectTypeX509Cert = 1,
3131
kPersoObjectTypeDevSeed = 2,
32+
kPersoObjectTypeCwtCert = 3,
3233
} perso_tlv_object_type_t;
3334

3435
typedef uint16_t perso_tlv_object_header_t;

sw/device/silicon_creator/manuf/base/personalize_ext.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,26 @@ typedef struct personalize_extension_pre_endorse {
4848
* knows where to place endorsed objects received from the host.
4949
*/
5050
cert_flash_info_layout_t *cert_flash_layout;
51-
5251
/**
5352
* Pointer to the flash controller handle necessary for proper flash access.
5453
*/
5554
dif_flash_ctrl_state_t *flash_ctrl_handle;
55+
/**
56+
* Pointer to the UDS public key. Personalization extensions may require
57+
* accessing it to generate different certificate chains that fit a specific
58+
* SKU's requirements.
59+
*/
60+
ecdsa_p256_public_key_t *uds_pubkey;
61+
hmac_digest_t *uds_pubkey_id;
62+
/**
63+
* Pointer to the OTP measurements used to generate the UDS public key.
64+
* Personalization extensions may require accessing these to generate
65+
* different certificate chains that fit a specific SKU's requirements.
66+
*/
67+
hmac_digest_t *otp_creator_sw_cfg_measurement;
68+
hmac_digest_t *otp_owner_sw_cfg_measurement;
69+
hmac_digest_t *otp_rot_creator_auth_codesign_measurement;
70+
hmac_digest_t *otp_rot_creator_auth_state_measurement;
5671
} personalize_extension_pre_endorse_t;
5772

5873
/**

sw/host/provisioning/ft_lib/src/lib.rs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ use p256::NistP256;
1515
use zerocopy::AsBytes;
1616

1717
use cert_lib::{
18-
get_cert_size, parse_and_endorse_x509_cert, validate_cert_chain, CertEndorsementKey,
19-
EndorsedCert,
18+
parse_and_endorse_x509_cert, validate_cert_chain, CertEndorsementKey, EndorsedCert,
2019
};
2120
use ft_ext_lib::ft_ext;
2221
use opentitanlib::app::TransportWrapper;
@@ -244,15 +243,6 @@ fn get_cert(data: &[u8]) -> Result<CertHeader> {
244243
let header_size = header_len + name_len;
245244
let cert_body: Vec<u8> = data[header_size..wrapped_size].to_vec();
246245

247-
// Sanity check, total size and cert size must match
248-
let cert_size = get_cert_size(&cert_body)?;
249-
if cert_size != cert_body.len() {
250-
bail!(
251-
"cert size {} does not match length {}",
252-
cert_size,
253-
cert_body.len()
254-
);
255-
}
256246
Ok(CertHeader {
257247
wrapped_size,
258248
cert_name,
@@ -350,7 +340,7 @@ fn provision_certificates(
350340
}
351341
start += obj_header_size;
352342
match header.obj_type {
353-
ObjType::EndorsedX509Cert | ObjType::UnendorsedX509Cert => (),
343+
ObjType::EndorsedX509Cert | ObjType::UnendorsedX509Cert | ObjType::EndorsedCwtCert => {}
354344
ObjType::DevSeed => {
355345
let dev_seed_size = header.obj_size - obj_header_size;
356346
let seeds = &perso_blob.body[start..start + dev_seed_size];
@@ -390,7 +380,10 @@ fn provision_certificates(
390380
};
391381

392382
// Collect all DICE certs to validate the chain.
393-
if dice_cert_names.contains(cert.cert_name) {
383+
// TODO(lowRISC/opentitan:#24281): Add CWT verifier
384+
if dice_cert_names.contains(cert.cert_name)
385+
&& header.obj_type == ObjType::UnendorsedX509Cert
386+
{
394387
dice_cert_chain.push(EndorsedCert {
395388
format: CertFormat::X509,
396389
name: cert.cert_name.to_string(),
@@ -401,7 +394,10 @@ fn provision_certificates(
401394

402395
// Ensure all certs parse with OpenSSL (even those that where endorsed on device).
403396
log::info!("{} Cert: {}", cert.cert_name, hex::encode(&cert_bytes));
404-
let _ = parse_certificate(&cert_bytes)?;
397+
// TODO(lowRISC/opentitan:#24281): Add CWT parser
398+
if header.obj_type != ObjType::DevSeed && header.obj_type != ObjType::EndorsedCwtCert {
399+
let _ = parse_certificate(&cert_bytes)?;
400+
}
405401
// Push the cert into the hasher so we can ensure the certs written to the device's flash
406402
// info pages match those verified on the host.
407403
cert_hasher.update(cert_bytes);
@@ -443,6 +439,7 @@ fn provision_certificates(
443439
}
444440

445441
// Validate the certificate endorsements with OpenSSL.
442+
// TODO(lowRISC/opentitan:#24281): Add CWT verifier
446443
log::info!("Validating DICE certificate chain with OpenSSL ...");
447444
validate_cert_chain(ca_certificate.to_str().unwrap(), &dice_cert_chain)?;
448445
log::info!("Success.");

sw/host/provisioning/perso_tlv_lib/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub enum ObjType {
1111
UnendorsedX509Cert = perso_tlv_objects::perso_tlv_object_type_kPersoObjectTypeX509Tbs as isize,
1212
EndorsedX509Cert = perso_tlv_objects::perso_tlv_object_type_kPersoObjectTypeX509Cert as isize,
1313
DevSeed = perso_tlv_objects::perso_tlv_object_type_kPersoObjectTypeDevSeed as isize,
14+
EndorsedCwtCert = perso_tlv_objects::perso_tlv_object_type_kPersoObjectTypeCwtCert as isize,
1415
}
1516

1617
impl ObjType {
@@ -19,6 +20,7 @@ impl ObjType {
1920
0 => Ok(ObjType::UnendorsedX509Cert),
2021
1 => Ok(ObjType::EndorsedX509Cert),
2122
2 => Ok(ObjType::DevSeed),
23+
3 => Ok(ObjType::EndorsedCwtCert),
2224
_ => bail!("incorrect input value of {value} for ObjType"),
2325
}
2426
}

0 commit comments

Comments
 (0)