Skip to content

Commit

Permalink
dice-cwt: All CWT in the perso_blob_to_host
Browse files Browse the repository at this point in the history
  • Loading branch information
tommychiu-github committed Oct 29, 2024
1 parent e94fabf commit c9ed06e
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 42 deletions.
2 changes: 2 additions & 0 deletions sw/device/silicon_creator/lib/cert/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ 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/cert:uds_template_library",
"//sw/device/silicon_creator/lib/drivers:lifecycle",
"//sw/device/silicon_creator/manuf/lib:flash_info_fields",
],
)
Expand Down
38 changes: 36 additions & 2 deletions sw/device/silicon_creator/lib/cert/dice_cwt.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
#include "sw/device/silicon_creator/lib/cert/cbor.h"
#include "sw/device/silicon_creator/lib/cert/cert.h"
#include "sw/device/silicon_creator/lib/cert/dice.h"
#include "sw/device/silicon_creator/lib/cert/uds.h" // Generated.
#include "sw/device/silicon_creator/lib/drivers/hmac.h"
#include "sw/device/silicon_creator/lib/drivers/keymgr.h"
#include "sw/device/silicon_creator/lib/drivers/lifecycle.h"
#include "sw/device/silicon_creator/lib/drivers/otp.h"
#include "sw/device/silicon_creator/lib/error.h"
#include "sw/device/silicon_creator/lib/otbn_boot_services.h"
Expand Down Expand Up @@ -60,7 +62,7 @@ enum {
// CWT sizes
enum {
kCoseKeyEcP256SizeBytes = 77,
kCdi0MaxPayloadSizeBytes = 455,
kCdi0MaxPayloadSizeBytes = 454,
};

// UDS (Creator) attestation key diverisfier constants.
Expand Down Expand Up @@ -164,15 +166,47 @@ static rom_error_t cose_key_ec_p256_build(ecdsa_p256_public_key_t *uds_pubkey,
return kErrorOk;
}

static bool is_debug_exposed(void) {
lifecycle_state_t lc_state = lifecycle_state_get();
if (lc_state == kLcStateProd || lc_state == kLcStateProdEnd) {
return false;
}
return true;
}

rom_error_t dice_uds_tbs_cert_build(
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,
cert_key_id_pair_t *key_ids, ecdsa_p256_public_key_t *uds_pubkey,
uint8_t *tbs_cert, size_t *tbs_cert_size) {
uds_tbs_values_t uds_cert_tbs_params = {
.otp_creator_sw_cfg_hash =
(unsigned char *)otp_creator_sw_cfg_measurement->digest,
.otp_creator_sw_cfg_hash_size = kHmacDigestNumBytes,
.otp_owner_sw_cfg_hash =
(unsigned char *)otp_owner_sw_cfg_measurement->digest,
.otp_owner_sw_cfg_hash_size = kHmacDigestNumBytes,
.otp_rot_creator_auth_codesign_hash =
(unsigned char *)otp_rot_creator_auth_codesign_measurement->digest,
.otp_rot_creator_auth_codesign_hash_size = kHmacDigestNumBytes,
.otp_rot_creator_auth_state_hash =
(unsigned char *)otp_rot_creator_auth_state_measurement->digest,
.otp_rot_creator_auth_state_hash_size = kHmacDigestNumBytes,
.debug_flag = is_debug_exposed(),
.creator_pub_key_id = (unsigned char *)key_ids->cert->digest,
.creator_pub_key_id_size = kCertKeyIdSizeInBytes,
.auth_key_key_id = (unsigned char *)key_ids->endorsement->digest,
.auth_key_key_id_size = kCertKeyIdSizeInBytes,
.creator_pub_key_ec_x = (unsigned char *)uds_pubkey->x,
.creator_pub_key_ec_x_size = kEcdsaP256PublicKeyCoordBytes,
.creator_pub_key_ec_y = (unsigned char *)uds_pubkey->y,
.creator_pub_key_ec_y_size = kEcdsaP256PublicKeyCoordBytes,
};
HARDENED_RETURN_IF_ERROR(
cose_key_ec_p256_build(uds_pubkey, tbs_cert, tbs_cert_size));
uds_build_tbs(&uds_cert_tbs_params, tbs_cert, tbs_cert_size));

return kErrorOk;
}

Expand Down
3 changes: 2 additions & 1 deletion sw/device/silicon_creator/manuf/base/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,8 @@ _FT_PROVISIONING_HARNESS = "//sw/host/provisioning/ft"
"//hw/top_earlgrey:silicon_creator": None,
},
fpga = fpga_params(
timeout = "long",
timeout = "short",
# timeout = "long",
binaries = {
":sram_ft_individualize_sival": "sram_ft_individualize",
":ft_personalize{}".format(ext["suffix"] + dice["suffix"]): "ft_personalize",
Expand Down
49 changes: 32 additions & 17 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 All @@ -126,10 +127,10 @@ static cert_flash_info_layout_t cert_flash_layout[] = {
// These flash info pages can be used by provisioning extensions to store
// additional certificates SKU owners may desire to provision.
{
.used = false,
.used = true,
.group_name = "Ext0",
.info_page = &kFlashCtrlInfoPageOwnerReserved6,
.num_certs = 0,
.num_certs = 1,
},
{
.used = false,
Expand Down Expand Up @@ -184,8 +185,11 @@ static void sw_reset(void) {
static status_t config_and_erase_certificate_flash_pages(void) {
flash_ctrl_cert_info_page_creator_cfg(&kFlashCtrlInfoPageAttestationKeySeeds);
flash_ctrl_cert_info_page_creator_cfg(&kFlashCtrlInfoPageDiceCerts);
flash_ctrl_cert_info_page_creator_cfg(&kFlashCtrlInfoPageOwnerReserved6);
TRY(flash_ctrl_info_erase(&kFlashCtrlInfoPageDiceCerts,
kFlashCtrlEraseTypePage));
TRY(flash_ctrl_info_erase(&kFlashCtrlInfoPageOwnerReserved6,
kFlashCtrlEraseTypePage));
return OK_STATUS();
}

Expand Down Expand Up @@ -308,12 +312,21 @@ static status_t hash_certificate(const flash_ctrl_info_page_t *page,
size_t offset, size_t *size) {
uint8_t buffer[1024]; // 1K should be enough for the largest certificate.
uint32_t cert_size;
uint32_t bytes_read;
uint16_t wrapped_cert_size;
uint16_t name_len;
uint16_t hdr_and_name_len;

// Read the first word of the certificate which contains it's size.
TRY(flash_ctrl_info_read(page, offset, 1, buffer));
bytes_read = sizeof(uint32_t);
cert_size = cert_x509_asn1_decode_size_header(buffer);
// Try to parse Cert Header, and calculate the real cert size
// Note: only the first 16-bit is Cert Header
perso_tlv_cert_header_t crth;
memcpy(&crth, &buffer[0], sizeof(crth));
PERSO_TLV_GET_FIELD(Crth, Size, crth, &wrapped_cert_size);
PERSO_TLV_GET_FIELD(Crth, NameSize, crth, &name_len);
hdr_and_name_len = sizeof(perso_tlv_cert_header_t) + name_len;
cert_size = wrapped_cert_size - hdr_and_name_len;

if (cert_size == 0) {
LOG_ERROR("Inconsistent certificate header %02x %02x page %x:%x", buffer[0],
buffer[1], page->base_addr, offset);
Expand All @@ -330,14 +343,12 @@ static status_t hash_certificate(const flash_ctrl_info_page_t *page,
return DATA_LOSS();
}

offset += bytes_read;
TRY(flash_ctrl_info_read(page, offset,
util_size_to_words(cert_size - bytes_read),
buffer + bytes_read));
hmac_sha256_update(buffer, cert_size);
TRY(flash_ctrl_info_read(page, offset, util_size_to_words(wrapped_cert_size),
buffer));
hmac_sha256_update(&buffer[hdr_and_name_len], cert_size);

if (size) {
*size = cert_size;
*size = wrapped_cert_size;
}
return OK_STATUS();
}
Expand Down Expand Up @@ -420,6 +431,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 Down Expand Up @@ -571,7 +583,7 @@ static status_t personalize_endorse_certificates(ujson_t *uj) {

// Now the two CDI certs which were endorsed locally and sent to the host
// earlier.
size_t cdis[] = {cdi_0_offset, cdi_1_offset};
size_t cdis[] = {cdi_0_offset, cdi_1_offset, uds_cwt_offset};
for (size_t i = 0; i < ARRAYSIZE(cdis); i++) {
size_t offset = cdis[i];
TRY(perso_tlv_set_cert_block(perso_blob_to_host.body + offset,
Expand Down Expand Up @@ -616,15 +628,17 @@ static status_t personalize_endorse_certificates(ujson_t *uj) {
// We just prepared the set of wrapped certificates, let's trust that the
// data is correct and does not need more validation.
memcpy(&crth, certs, sizeof(crth));
certs += sizeof(crth);
PERSO_TLV_GET_FIELD(Crth, NameSize, crth, &name_len);
memcpy(name, certs, name_len);
memcpy(name, (void *)(certs + sizeof(crth)), name_len);
name[name_len] = '\0';
certs += name_len;

// Compute the number of words necessary for certificate storage
// (rounded up to word alignment).
uint32_t cert_size_bytes = cert_x509_asn1_decode_size_header(certs);
uint32_t cert_size_bytes;
// Try to get cert size from the header, which includs "name_len" and
// "sizeof(perso_tlv_cert_header_t)" already
PERSO_TLV_GET_FIELD(Crth, Size, crth, &cert_size_bytes);
//uint32_t cert_size_bytes = cert_x509_asn1_decode_size_header(certs);
uint32_t cert_size_words = util_size_to_words(cert_size_bytes);
uint32_t cert_size_bytes_ru = cert_size_words * sizeof(uint32_t);

Expand Down Expand Up @@ -706,7 +720,8 @@ 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};
CHECK_STATUS_OK(personalize_extension_pre_cert_endorse(&pre_endorse));

CHECK_STATUS_OK(personalize_endorse_certificates(&uj));
Expand Down
23 changes: 5 additions & 18 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 @@ -68,22 +69,6 @@ status_t perso_tlv_set_cert_block(const uint8_t *buf, size_t max_room,
buf += name_len;
max_room -= name_len;
block->name[name_len] = '\0';

size_t cert_size;

cert_size = cert_x509_asn1_decode_size_header(buf);
if (cert_size > max_room)
return INTERNAL();

uint16_t wire_cert_size =
wrapped_cert_size - sizeof(perso_tlv_cert_header_t) - name_len;

if (cert_size != wire_cert_size) {
LOG_ERROR("Unexpected cert size %d instead of %d for cert %s", cert_size,
wire_cert_size, block->name);
return INTERNAL();
}

block->wrapped_cert_size = wrapped_cert_size;

return OK_STATUS();
Expand Down Expand Up @@ -138,7 +123,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
6 changes: 6 additions & 0 deletions sw/device/silicon_creator/manuf/base/personalize_ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "sw/device/lib/testing/json/provisioning_data.h"
#include "sw/device/silicon_creator/lib/cert/cert.h"

extern size_t uds_cwt_offset;
/**
* Parameters passed to personalization extension function invoked before data
* is sent to the host for endorsement. Not all parameters are necessarily used
Expand Down Expand Up @@ -40,6 +41,11 @@ 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;
} personalize_extension_pre_endorse_t;

/**
Expand Down
19 changes: 15 additions & 4 deletions sw/host/provisioning/ft_lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ fn get_cert(data: &[u8]) -> Result<CertHeader> {
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)?;
// let cert_size = get_cert_size(&cert_body)?;
let cert_size = cert_body.len();
if cert_size != cert_body.len() {
bail!(
"cert size {} does not match length {}",
Expand Down Expand Up @@ -343,7 +344,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 @@ -379,8 +382,16 @@ fn provision_certificates(
cert.cert_body
};
// 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)?;
log::info!(
"{} {:?} Cert: {}",
cert.cert_name,
header.obj_type,
hex::encode(&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 c9ed06e

Please sign in to comment.