diff --git a/sw/device/silicon_creator/lib/cert/BUILD b/sw/device/silicon_creator/lib/cert/BUILD index a7d1f10b570d6d..b514530a9cd320 100644 --- a/sw/device/silicon_creator/lib/cert/BUILD +++ b/sw/device/silicon_creator/lib/cert/BUILD @@ -145,6 +145,18 @@ 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"], @@ -152,9 +164,12 @@ cc_library( 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", ], ) @@ -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", ], diff --git a/sw/device/silicon_creator/lib/cert/dice_cwt.c b/sw/device/silicon_creator/lib/cert/dice_cwt.c index b3a3548737a9a5..463bb775a64ff0 100644 --- a/sw/device/silicon_creator/lib/cert/dice_cwt.c +++ b/sw/device/silicon_creator/lib/cert/dice_cwt.c @@ -5,36 +5,91 @@ #include #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, @@ -42,26 +97,14 @@ rom_error_t dice_uds_tbs_cert_build( 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; } @@ -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; } @@ -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; }