Skip to content

Commit

Permalink
[dice,cwt] Utilize CWT template to flesh out CDI_0/1 generator
Browse files Browse the repository at this point in the history
Try to flesh out the CDI_0/1 generating APIs by the auto-gen CWT
templates.

Signed-off-by: Tommy Chiu <[email protected]>
  • Loading branch information
tommychiu-github committed Nov 12, 2024
1 parent a430c0b commit ebb7c31
Show file tree
Hide file tree
Showing 2 changed files with 269 additions and 40 deletions.
16 changes: 16 additions & 0 deletions sw/device/silicon_creator/lib/cert/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -145,16 +145,31 @@ cc_library(
],
)

cc_library(
name = "cwt_template",
deps = [
":cbor",
":cwt_cose_key_template_library",
":cwt_dice_chain_entry_input_template_library",
":cwt_dice_chain_entry_payload_template_library",
":cwt_dice_chain_entry_template_library",
"//sw/device/lib/base:status",
],
)

cc_library(
name = "dice_cwt",
srcs = ["dice_cwt.c"],
hdrs = ["dice.h"],
deps = [
":cbor",
":cert",
":cwt_template",
"//hw/ip/otp_ctrl/data:otp_ctrl_c_regs",
"//sw/device/lib/base:status",
"//sw/device/silicon_creator/lib:attestation",
"//sw/device/silicon_creator/lib/base:util",
"//sw/device/silicon_creator/lib/cert:dice_keys",
"//sw/device/silicon_creator/manuf/base:perso_tlv_data",
],
)
Expand All @@ -164,6 +179,7 @@ cc_library(
srcs = ["dice_keys.c"],
hdrs = ["dice_keys.h"],
deps = [
"//sw/device/silicon_creator/lib:otbn_boot_services",
"//sw/device/silicon_creator/lib/drivers:keymgr",
"//sw/device/silicon_creator/manuf/lib:flash_info_fields",
],
Expand Down
293 changes: 253 additions & 40 deletions sw/device/silicon_creator/lib/cert/dice_cwt.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,63 +5,106 @@
#include <stdint.h>

#include "sw/device/lib/base/memory.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/runtime/print.h"
#include "sw/device/silicon_creator/lib/base/util.h"
#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/cwt_cose_key.h"
#include "sw/device/silicon_creator/lib/cert/cwt_dice_chain_entry.h"
#include "sw/device/silicon_creator/lib/cert/cwt_dice_chain_entry_input.h"
#include "sw/device/silicon_creator/lib/cert/cwt_dice_chain_entry_payload.h"
#include "sw/device/silicon_creator/lib/cert/dice.h"
#include "sw/device/silicon_creator/lib/cert/dice_keys.h"
#include "sw/device/silicon_creator/lib/drivers/hmac.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"
#include "sw/device/silicon_creator/lib/sigverify/ecdsa_p256_key.h"
#include "sw/device/silicon_creator/manuf/base/perso_tlv_data.h"

#include "otp_ctrl_regs.h" // Generated.

// Keys
const int64_t kCoseKeyKtyLabel = 1;
const int64_t kCoseKeyAlgLabel = 3;
const int64_t kCoseEc2CrvLabel = -1;
const int64_t kCoseEc2XLabel = -2;
const int64_t kCoseEc2YLabel = -3;

// Values
const int64_t kCoseKeyAlgEcdsa256 = -7;
const int64_t kCoseEc2CrvP256 = 1;
const int64_t kCoseKeyKtyEc2 = 2;

// PubKeyECDSA256 = { ; COSE_Key [RFC9052 s7]
// 1 : 2, ; Key type : EC2
// 3 : AlgorithmES256, ; Algorithm : ECDSA w/ SHA-256
// -1 : 1, ; Curve: P256
// -2 : bstr, ; X coordinate, big-endian
// -3 : bstr ; Y coordinate, big-endian
// }
const dice_cert_format_t kDiceCertFormat = kDiceCertFormatCWTAndroid;

enum {
kSecurityVersionLabel = -70005,
// Implementataion specific value,
// less than -65536 and outside of [-70000, -70999]
kOwnerManifestMeasurmentLabel = -71006,
};

enum {
// The length of Profile Name
kProfileNameLength = 10,
// The Key ID length, which equals to the SHA256 digest size in bytes
kIssuerSubjectKeyIdLenght = kHmacDigestNumBytes,
// The size of issuer & subject name, which equals to the ascii size
// transformed form Key ID.
kIssuerSubjectNameLength = kIssuerSubjectKeyIdLenght * 2,
// 64 byte should be enough for 2 entries
kConfigDescBuffSize = 64,
};
// Reusable buffer for generating Configuration Descriptor
uint8_t config_desc_buf[kConfigDescBuffSize] = {0};
// TODO(lowRISC/opentitan:#24281): Set to "Debug=2" for now, should move to
// "Normal=1" while production
uint8_t kMode = 2;
// a0 # map(0)
const uint8_t kCborMap0[] = {0xa0};
// Reusable buffer for generating UDS/CDI_* COSE_Key
static uint8_t cose_key_buffer[kCwtCoseKeyMaxVariableSizeBytes] = {0};
// Reusable buffer for generating signature
static ecdsa_p256_signature_t curr_tbs_signature = {.r = {0}, .s = {0}};

#define CWT_PROFILE_NAME "android.16"

static char issuer[kIssuerSubjectNameLength + 1] = {0};
static char subject[kIssuerSubjectNameLength + 1] = {0};

static void fill_dice_id_string(
const uint8_t dice_id[kIssuerSubjectKeyIdLenght],
char dice_id_str[kIssuerSubjectNameLength + 1]) {
size_t idx;
for (idx = 0; idx < kIssuerSubjectKeyIdLenght; idx++, dice_id_str += 2)
util_hexdump_byte(dice_id[idx], (uint8_t *)&dice_id_str[0]);
}

static rom_error_t configuration_descriptor_build(
uint8_t *buf, size_t *buf_size, const size_t sec_version,
const hmac_digest_t *manifest_measurement) {
struct CborOut kCborOutHandle;
struct CborOut *pCborOut = &kCborOutHandle;
HARDENED_RETURN_IF_ERROR(
cbor_write_out_init(pCborOut, config_desc_buf, *buf_size));
HARDENED_RETURN_IF_ERROR(
cbor_map_init(pCborOut, (manifest_measurement != NULL) ? 2 : 1));
HARDENED_RETURN_IF_ERROR(
cbor_write_pair_int_uint(pCborOut, kSecurityVersionLabel, sec_version));
if (manifest_measurement != NULL)
HARDENED_RETURN_IF_ERROR(cbor_write_pair_int_bytes(
pCborOut, kOwnerManifestMeasurmentLabel,
(uint8_t *)&manifest_measurement->digest[0], kHmacDigestNumBytes));
*buf_size = CborOutSize(pCborOut);

return kErrorOk;
}

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) {
struct CborOut kCborOutHandle;

struct CborOut *pCborOut = &kCborOutHandle;

HARDENED_RETURN_IF_ERROR(
cbor_write_out_init(pCborOut, tbs_cert, *tbs_cert_size));
HARDENED_RETURN_IF_ERROR(cbor_map_init(pCborOut, 5));
cwt_cose_key_values_t cwt_cose_key_params = {
.pub_key_ec_x = (uint8_t *)uds_pubkey->x,
.pub_key_ec_x_size = sizeof(uds_pubkey->x),
.pub_key_ec_y = (uint8_t *)uds_pubkey->y,
.pub_key_ec_y_size = sizeof(uds_pubkey->y),
};
HARDENED_RETURN_IF_ERROR(
cbor_write_pair_uint_uint(pCborOut, kCoseKeyKtyLabel, kCoseKeyKtyEc2));
HARDENED_RETURN_IF_ERROR(cbor_write_pair_uint_int(pCborOut, kCoseKeyAlgLabel,
kCoseKeyAlgEcdsa256));
HARDENED_RETURN_IF_ERROR(
cbor_write_pair_int_uint(pCborOut, kCoseEc2CrvLabel, kCoseEc2CrvP256));
HARDENED_RETURN_IF_ERROR(cbor_write_pair_int_bytes(pCborOut, kCoseEc2XLabel,
(uint8_t *)uds_pubkey->x,
sizeof(uds_pubkey->x)));
HARDENED_RETURN_IF_ERROR(cbor_write_pair_int_bytes(pCborOut, kCoseEc2YLabel,
(uint8_t *)uds_pubkey->y,
sizeof(uds_pubkey->y)));
*tbs_cert_size = CborOutSize(pCborOut);
cwt_cose_key_build(&cwt_cose_key_params, tbs_cert, tbs_cert_size));

return kErrorOk;
}
Expand All @@ -71,7 +114,91 @@ rom_error_t dice_cdi_0_cert_build(hmac_digest_t *rom_ext_measurement,
cert_key_id_pair_t *key_ids,
ecdsa_p256_public_key_t *cdi_0_pubkey,
uint8_t *cert, size_t *cert_size) {
// TODO(lowRISC/opentitan:#24281): implement body
// Build Subject public key structure
size_t cose_key_size = sizeof(cose_key_buffer);
cwt_cose_key_values_t cwt_cose_key_params = {
.pub_key_ec_x = (uint8_t *)cdi_0_pubkey->x,
.pub_key_ec_x_size = sizeof(cdi_0_pubkey->x),
.pub_key_ec_y = (uint8_t *)cdi_0_pubkey->y,
.pub_key_ec_y_size = sizeof(cdi_0_pubkey->y),
};
HARDENED_RETURN_IF_ERROR(cwt_cose_key_build(
&cwt_cose_key_params, &cose_key_buffer[0], &cose_key_size));

// Try to generate DiceChainEntryPayload
fill_dice_id_string((uint8_t *)(&key_ids->endorsement->digest[0]),
&issuer[0]);
fill_dice_id_string((uint8_t *)(&key_ids->cert->digest[0]), &subject[0]);

uint8_t
cdi0_entry_payload_buffer[kCwtDiceChainEntryPayloadMaxVariableSizeBytes];
size_t cdi0_entry_payload_size = sizeof(cdi0_entry_payload_buffer);

size_t config_desc_buf_size = kConfigDescBuffSize;
HARDENED_RETURN_IF_ERROR(configuration_descriptor_build(
config_desc_buf, &config_desc_buf_size, rom_ext_security_version, NULL));
hmac_digest_t conf_hash;
hmac_sha256(config_desc_buf, config_desc_buf_size, &conf_hash);
util_reverse_bytes(conf_hash.digest, kHmacDigestNumBytes);

hmac_digest_t auth_hash;
hmac_sha256(kCborMap0, sizeof(kCborMap0), &auth_hash);
util_reverse_bytes(auth_hash.digest, kHmacDigestNumBytes);

cwt_dice_chain_entry_payload_values_t cwt_dice_chain_entry_payload_params = {
.auth_hash = (uint8_t *)&auth_hash.digest[0],
.auth_hash_size = kHmacDigestNumBytes,
.code_hash = (uint8_t *)&rom_ext_measurement->digest[0],
.code_hash_size = kHmacDigestNumBytes,
.subject = &subject[0],
.subject_size = kIssuerSubjectNameLength,
.mode = &kMode,
.mode_size = sizeof(kMode),
.issuer = &issuer[0],
.issuer_size = kIssuerSubjectNameLength,
.subject_pk = &cose_key_buffer[0],
.subject_pk_size = cose_key_size,
.config_desc = config_desc_buf,
.config_desc_size = config_desc_buf_size,
.config_hash = (uint8_t *)&conf_hash.digest[0],
.config_hash_size = kHmacDigestNumBytes,
.profile_name = CWT_PROFILE_NAME,
.profile_name_size = kProfileNameLength};
HARDENED_RETURN_IF_ERROR(cwt_dice_chain_entry_payload_build(
&cwt_dice_chain_entry_payload_params, cdi0_entry_payload_buffer,
&cdi0_entry_payload_size));

// Try to generate DiceChainEntryInput, by reusing the cert buffer.
size_t cdi0_entry_input_size = kCwtDiceChainEntryInputMaxVariableSizeBytes;
if (cdi0_entry_input_size > *cert_size)
return kErrorCertInvalidSize;
cwt_dice_chain_entry_input_values_t cwt_dice_chain_entry_input_params = {
.payload = cdi0_entry_payload_buffer,
.payload_size = cdi0_entry_payload_size};
HARDENED_RETURN_IF_ERROR(cwt_dice_chain_entry_input_build(
&cwt_dice_chain_entry_input_params, cert, &cdi0_entry_input_size));

// Obtain digest & sign
hmac_digest_t tbs_digest;
hmac_sha256(cert, cdi0_entry_input_size, &tbs_digest);
HARDENED_RETURN_IF_ERROR(
otbn_boot_attestation_endorse(&tbs_digest, &curr_tbs_signature));
util_p256_signature_le_to_be_convert(curr_tbs_signature.r,
curr_tbs_signature.s);

// Build the final DiceEntry
cwt_dice_chain_entry_values_t cwt_dice_chain_entry_params = {
.payload = cdi0_entry_payload_buffer,
.payload_size = cdi0_entry_payload_size,
.signature = (uint8_t *)&curr_tbs_signature,
.signature_size = sizeof(ecdsa_p256_signature_t)};
HARDENED_RETURN_IF_ERROR(cwt_dice_chain_entry_build(
&cwt_dice_chain_entry_params, cert, cert_size));

// Save the CDI_0 private key to OTBN DMEM so it can endorse the next stage.
HARDENED_RETURN_IF_ERROR(otbn_boot_attestation_key_save(
kDiceKeyCdi0.keygen_seed_idx, kDiceKeyCdi0.type,
*kDiceKeyCdi0.keymgr_diversifier));
return kErrorOk;
}

Expand All @@ -81,7 +208,93 @@ rom_error_t dice_cdi_1_cert_build(hmac_digest_t *owner_measurement,
cert_key_id_pair_t *key_ids,
ecdsa_p256_public_key_t *cdi_1_pubkey,
uint8_t *cert, size_t *cert_size) {
// TODO(lowRISC/opentitan:#24281): implement body
// Build Subject public key structure
size_t cose_key_size = sizeof(cose_key_buffer);
cwt_cose_key_values_t cwt_cose_key_params = {
.pub_key_ec_x = (uint8_t *)cdi_1_pubkey->x,
.pub_key_ec_x_size = sizeof(cdi_1_pubkey->x),
.pub_key_ec_y = (uint8_t *)cdi_1_pubkey->y,
.pub_key_ec_y_size = sizeof(cdi_1_pubkey->y),
};
HARDENED_RETURN_IF_ERROR(cwt_cose_key_build(
&cwt_cose_key_params, &cose_key_buffer[0], &cose_key_size));

// Try to generate DiceChainEntryPayload
fill_dice_id_string((uint8_t *)(&key_ids->endorsement->digest[0]),
&issuer[0]);
fill_dice_id_string((uint8_t *)(&key_ids->cert->digest[0]), &subject[0]);

uint8_t
cdi1_entry_payload_buffer[kCwtDiceChainEntryPayloadMaxVariableSizeBytes];
size_t cdi1_entry_payload_size = sizeof(cdi1_entry_payload_buffer);

size_t config_desc_buf_size = sizeof(config_desc_buf);
HARDENED_RETURN_IF_ERROR(configuration_descriptor_build(
config_desc_buf, &config_desc_buf_size, owner_security_version,
owner_manifest_measurement));
hmac_digest_t conf_hash;
hmac_sha256(config_desc_buf, config_desc_buf_size, &conf_hash);
util_reverse_bytes(conf_hash.digest, kHmacDigestNumBytes);

hmac_digest_t auth_hash;
hmac_sha256(kCborMap0, sizeof(kCborMap0), &auth_hash);
util_reverse_bytes(auth_hash.digest, kHmacDigestNumBytes);

cwt_dice_chain_entry_payload_values_t cwt_dice_chain_entry_payload_params = {
.auth_hash = (uint8_t *)&auth_hash.digest[0],
.auth_hash_size = kHmacDigestNumBytes,
.code_hash = (uint8_t *)&owner_measurement->digest[0],
.code_hash_size = kHmacDigestNumBytes,
.subject = &subject[0],
.subject_size = kIssuerSubjectNameLength,
.mode = &kMode,
.mode_size = sizeof(kMode),
.issuer = &issuer[0],
.issuer_size = kIssuerSubjectNameLength,
.subject_pk = &cose_key_buffer[0],
.subject_pk_size = cose_key_size,
.config_desc = config_desc_buf,
.config_desc_size = config_desc_buf_size,
.config_hash = (uint8_t *)&conf_hash.digest[0],
.config_hash_size = kHmacDigestNumBytes,
.profile_name = CWT_PROFILE_NAME,
.profile_name_size = kProfileNameLength};
HARDENED_RETURN_IF_ERROR(cwt_dice_chain_entry_payload_build(
&cwt_dice_chain_entry_payload_params, cdi1_entry_payload_buffer,
&cdi1_entry_payload_size));

// Try to generate DiceChainEntryInput, by reusing the cert buffer.
size_t cdi1_entry_input_size = kCwtDiceChainEntryInputMaxVariableSizeBytes;
if (cdi1_entry_input_size > *cert_size)
return kErrorCertInvalidSize;
cwt_dice_chain_entry_input_values_t cwt_dice_chain_entry_input_params = {
.payload = cdi1_entry_payload_buffer,
.payload_size = cdi1_entry_payload_size};
HARDENED_RETURN_IF_ERROR(cwt_dice_chain_entry_input_build(
&cwt_dice_chain_entry_input_params, cert, &cdi1_entry_input_size));

// Obtain digest & sign
hmac_digest_t tbs_digest;
hmac_sha256(cert, cdi1_entry_input_size, &tbs_digest);
HARDENED_RETURN_IF_ERROR(
otbn_boot_attestation_endorse(&tbs_digest, &curr_tbs_signature));
util_p256_signature_le_to_be_convert(curr_tbs_signature.r,
curr_tbs_signature.s);

// Build the final DiceEntry
cwt_dice_chain_entry_values_t cwt_dice_chain_entry_params = {
.payload = cdi1_entry_payload_buffer,
.payload_size = cdi1_entry_payload_size,
.signature = (uint8_t *)&curr_tbs_signature,
.signature_size = sizeof(ecdsa_p256_signature_t)};
HARDENED_RETURN_IF_ERROR(cwt_dice_chain_entry_build(
&cwt_dice_chain_entry_params, cert, cert_size));

// Save the CDI_1 private key to OTBN DMEM so it can endorse the next stage.
HARDENED_RETURN_IF_ERROR(otbn_boot_attestation_key_save(
kDiceKeyCdi1.keygen_seed_idx, kDiceKeyCdi1.type,
*kDiceKeyCdi1.keymgr_diversifier));

return kErrorOk;
}

Expand Down

0 comments on commit ebb7c31

Please sign in to comment.