Skip to content

Commit

Permalink
[dice,cwt] Add manual implementation of CDI_0/1 builder
Browse files Browse the repository at this point in the history
Add an working implementation for dice-cwt builders.

Bug: 356532759
Test: ft_provision_dice_cwt_fpga_cw340_rom_with_fake_keys
Signed-off-by: Tommy Chiu <[email protected]>
  • Loading branch information
tommychiu-github committed Oct 23, 2024
1 parent ec3f1da commit 8df6d0d
Show file tree
Hide file tree
Showing 2 changed files with 245 additions and 27 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 @@ -130,6 +130,8 @@ cc_library(
"//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:otbn_boot_services",
"//sw/device/silicon_creator/lib/base:util",
"//sw/device/silicon_creator/manuf/lib:flash_info_fields",
],
)
Expand Down
270 changes: 243 additions & 27 deletions sw/device/silicon_creator/lib/cert/dice_cwt.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,63 @@
#include <stdint.h>

#include "sw/device/lib/base/memory.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/dice.h"
#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/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/lib/flash_info_fields.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;
// Labels
#define CWT_COSE_KEY_LABEL_TYPE (1)
#define CWT_COSE_KEY_LABEL_ALG (3)
#define CWT_COSE_KEY_LABEL_CRUVE (-1)
#define CWT_COSE_KEY_LABEL_EC2_X (-2)
#define CWT_COSE_KEY_LABEL_EC2_Y (-3)
#define CWT_LABEL_ISS (1)
#define CWT_LABEL_SUB (2)
#define CWT_LABEL_CODE_HASH (-4670545)
#define CWT_LABEL_CFG_HASH (-4670547)
#define CWT_LABEL_CFG_DESCR (-4670548)
#define CWT_LABEL_AUTH_HASH (-4670549)
#define CWT_LABEL_MODE (-4670551)
#define CWT_LABEL_SUBJECT_PK (-4670552)
#define CWT_LABEL_KEY_USAGE (-4670553)
#define CWT_LABEL_PROFILE_NAME (-4670554)

// Values
const int64_t kCoseKeyAlgEcdsa256 = -7;
const int64_t kCoseEc2CrvP256 = 1;
const int64_t kCoseKeyKtyEc2 = 2;
#define CWT_COSE_KEY_ALG_ECDSA256 (-7)
#define CWT_COSE_EC2_CRUVE_P256 (1)
#define CWT_COSE_KEY_TYPE_EC2 (2)

#define CWT_PROFILE_NAME "android.16"
#define CWT_PROFILE_NAME_VALUE_LEN 10 /* "android.16" */
#define CWT_PROFILE_NAME_LEN (1 + CWT_PROFILE_NAME_VALUE_LEN)

#define CWT_ISSU_SUBJ_KEY_ID_LEN kHmacDigestNumBytes
#define CWT_ISSU_SUBJ_LEN (CWT_ISSU_SUBJ_KEY_ID_LEN * 2)

// Entry numbers
enum {
kCoseKeyMapCount = 5,
kDiceChainEntryArrayCount = 4,
kDiceChainEntryInputArrayCount = 4,
kDiceChainEntryPayloadMapCount = 10,
};

// CWT sizes
enum {
kCoseKeyEcP256SizeBytes = 77,
kCdi0MaxPayloadSizeBytes = 448,
};

// UDS (Creator) attestation key diverisfier constants.
// Note: versions are always set to 0 so these keys are always valid from the
Expand Down Expand Up @@ -103,33 +137,177 @@ const sc_keymgr_ecc_key_t kDiceKeyCdi1 = {
// -2 : bstr, ; X coordinate, big-endian
// -3 : bstr ; Y coordinate, big-endian
// }
static rom_error_t cose_key_ec_p256_build(ecdsa_p256_public_key_t *uds_pubkey,
uint8_t *cose_key_buffer,
size_t *cose_key_buffer_size) {
struct CborOut kCborOutHandle;
struct CborOut *pCborOut = &kCborOutHandle;

RETURN_IF_ERROR(
cbor_write_out_init(pCborOut, cose_key_buffer, *cose_key_buffer_size));
RETURN_IF_ERROR(cbor_map_init(pCborOut, kCoseKeyMapCount));
RETURN_IF_ERROR(cbor_write_pair_uint_uint(pCborOut, CWT_COSE_KEY_LABEL_TYPE,
CWT_COSE_KEY_TYPE_EC2));
RETURN_IF_ERROR(cbor_write_pair_uint_int(pCborOut, CWT_COSE_KEY_LABEL_ALG,
CWT_COSE_KEY_ALG_ECDSA256));
RETURN_IF_ERROR(cbor_write_pair_int_uint(pCborOut, CWT_COSE_KEY_LABEL_CRUVE,
CWT_COSE_EC2_CRUVE_P256));
RETURN_IF_ERROR(cbor_write_pair_int_bytes(pCborOut, CWT_COSE_KEY_LABEL_EC2_X,
(uint8_t *)uds_pubkey->x,
sizeof(uds_pubkey->x)));
RETURN_IF_ERROR(cbor_write_pair_int_bytes(pCborOut, CWT_COSE_KEY_LABEL_EC2_Y,
(uint8_t *)uds_pubkey->y,
sizeof(uds_pubkey->y)));
*cose_key_buffer_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) {
HARDENED_RETURN_IF_ERROR(
cose_key_ec_p256_build(uds_pubkey, tbs_cert, tbs_cert_size));
return kErrorOk;
}

// protected:
// a1 # map(1)
// 01 # unsigned(1)
// 26 # negative(-7)
const uint8_t cbor_map_algo_es256[] = {0xa1, 0x01, 0x26};

// a0 # map(0)
const uint8_t cbor_map_0 = 0xa0;

// Pre-calculated SHA256 of "0xa0"
const uint8_t sha256_of_cbor_map_0[] = {
0xc1, 0x9a, 0x79, 0x7f, 0xa1, 0xfd, 0x59, 0x0c, 0xd2, 0xe5, 0xb4,
0x2d, 0x1c, 0xf5, 0xf2, 0x46, 0xe2, 0x9b, 0x91, 0x68, 0x4e, 0x2f,
0x87, 0x40, 0x4b, 0x81, 0xdc, 0x34, 0x5c, 0x7a, 0x56, 0xa0};

static ecdsa_p256_signature_t curr_tbs_signature = {.r = {0}, .s = {0}};

/**
* Helper function to convert an attestation certificate signature from little
* to big endian.
*/
static void curr_tbs_signature_le_to_be_convert(ecdsa_p256_signature_t *sig) {
util_reverse_bytes(sig->r, kEcdsaP256SignatureComponentBytes);
util_reverse_bytes(sig->s, kEcdsaP256SignatureComponentBytes);
}

/**
* Convert 32-byte digest to 64-byte string, with tailing "\0"
*/
static void fill_dice_id_string(const uint8_t dice_id[CWT_ISSU_SUBJ_KEY_ID_LEN],
char dice_id_str[CWT_ISSU_SUBJ_LEN + 1]) {
size_t idx;
for (idx = 0; idx < CWT_ISSU_SUBJ_KEY_ID_LEN; idx++, dice_id_str += 2)
util_hexdump_byte(dice_id[idx], (uint8_t *)&dice_id_str[0]);
}

static rom_error_t dice_chain_entry_payload_build(
uint8_t *payload, size_t *payload_size, const char *issuer,
const size_t issuer_size, const char *subject, const size_t subject_size,
uint8_t *cose_key, const size_t cose_key_size,
hmac_digest_t *rom_ext_measurement) {
if (*payload_size > kCdi0MaxPayloadSizeBytes)
return kErrorCertInvalidSize;

struct CborOut kCborOutHandle;
struct CborOut *pCborOut = &kCborOutHandle;

RETURN_IF_ERROR(cbor_write_out_init(pCborOut, payload, *payload_size));
RETURN_IF_ERROR(cbor_map_init(pCborOut, kDiceChainEntryPayloadMapCount));
RETURN_IF_ERROR(cbor_write_pair_uint_tstr(pCborOut, CWT_LABEL_ISS, issuer));
RETURN_IF_ERROR(cbor_write_pair_uint_tstr(pCborOut, CWT_LABEL_SUB, subject));
RETURN_IF_ERROR(cbor_write_pair_int_bytes(
pCborOut, CWT_LABEL_CODE_HASH,
(uint8_t *)(&rom_ext_measurement->digest[0]), kHmacDigestNumBytes));
RETURN_IF_ERROR(cbor_write_pair_int_bytes(pCborOut, CWT_LABEL_CFG_HASH,
sha256_of_cbor_map_0,
sizeof(sha256_of_cbor_map_0)));
RETURN_IF_ERROR(
cbor_write_pair_int_bytes(pCborOut, CWT_LABEL_CFG_DESCR, &cbor_map_0, 1));

RETURN_IF_ERROR(cbor_write_pair_int_bytes(pCborOut, CWT_LABEL_AUTH_HASH,
sha256_of_cbor_map_0,
sizeof(sha256_of_cbor_map_0)));
uint8_t mode = 1;
RETURN_IF_ERROR(
cbor_write_pair_int_bytes(pCborOut, CWT_LABEL_MODE, &mode, 1));
RETURN_IF_ERROR(cbor_write_pair_int_bytes(pCborOut, CWT_LABEL_SUBJECT_PK,
cose_key, cose_key_size));
uint8_t key_usage = 0x20;
RETURN_IF_ERROR(
cbor_write_pair_int_bytes(pCborOut, CWT_LABEL_KEY_USAGE, &key_usage, 1));

RETURN_IF_ERROR(cbor_write_pair_int_tstr(pCborOut, CWT_LABEL_PROFILE_NAME,
CWT_PROFILE_NAME));
*payload_size = CborOutSize(pCborOut);

return kErrorOk;
}

// DiceChainEntryInput = [
// context: "Signature1",
// protected: bstr .cbor { 1 : AlgorithmES256 },
// external_aad: bstr .size 0,
// payload: bstr .cbor DiceChainEntryPayload
// ]
static rom_error_t dice_chain_entry_input_build(
uint8_t *dice_chain_entry_input_buffer,
size_t *dice_chain_entry_input_buffer_size, uint8_t *cdi0_payload_buffer,
const size_t cdi0_payload_size) {
if (cdi0_payload_size > *dice_chain_entry_input_buffer_size)
return kErrorCertInvalidSize;

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));
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);
RETURN_IF_ERROR(cbor_write_out_init(pCborOut, dice_chain_entry_input_buffer,
*dice_chain_entry_input_buffer_size));
RETURN_IF_ERROR(cbor_array_init(pCborOut, kDiceChainEntryInputArrayCount));
RETURN_IF_ERROR(cbor_write_string(pCborOut, "Signature1"));
RETURN_IF_ERROR(cbor_write_bytes(pCborOut, (uint8_t *)&cbor_map_algo_es256[0],
sizeof(cbor_map_algo_es256)));
RETURN_IF_ERROR(cbor_write_bytes(pCborOut, NULL, 0));
RETURN_IF_ERROR(
cbor_write_bytes(pCborOut, cdi0_payload_buffer, cdi0_payload_size));
*dice_chain_entry_input_buffer_size = CborOutSize(pCborOut);

return kErrorOk;
}

// DiceChainEntry = [ ; COSE_Sign1 (untagged), [RFC9052 s4.2]
// protected : bstr .cbor { 1 : AlgorithmES256},
// unprotected: {},
// payload: bstr .cbor DiceChainEntryPayload,
// signature: bstr ; ECDSA(SigningKey, DiceChainEntryInput)
// ]
static rom_error_t dice_chain_build(
uint8_t *cert, size_t *cert_size, uint8_t *cdi0_payload_buffer,
const size_t payload_buff_size,
ecdsa_p256_signature_t *curr_tbs_signature) {
struct CborOut kCborOutHandle;
struct CborOut *pCborOut = &kCborOutHandle;

RETURN_IF_ERROR(cbor_write_out_init(pCborOut, cert, *cert_size));
RETURN_IF_ERROR(cbor_array_init(pCborOut, kDiceChainEntryArrayCount));
RETURN_IF_ERROR(cbor_write_bytes(pCborOut, (uint8_t *)&cbor_map_algo_es256[0],
sizeof(cbor_map_algo_es256)));
RETURN_IF_ERROR(cbor_map_init(pCborOut, 0));
RETURN_IF_ERROR(cbor_write_bytes(pCborOut, (uint8_t *)&cdi0_payload_buffer[0],
payload_buff_size));
// (r+s) in RAW
RETURN_IF_ERROR(cbor_write_bytes(pCborOut, (uint8_t *)curr_tbs_signature,
sizeof(ecdsa_p256_signature_t)));
*cert_size = CborOutSize(pCborOut);

return kErrorOk;
}
Expand All @@ -139,7 +317,43 @@ 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
size_t payload_buff_size = kCdi0MaxPayloadSizeBytes;
uint8_t cdi0_payload_buffer[payload_buff_size];
size_t cose_key_size = kCoseKeyEcP256SizeBytes;
uint8_t cose_key_buffer[cose_key_size];
/* NULL terminated string buffer */
char issuer[CWT_ISSU_SUBJ_LEN + 1] = {0};
char subject[CWT_ISSU_SUBJ_LEN + 1] = {0};

HARDENED_RETURN_IF_ERROR(
cose_key_ec_p256_build(cdi_0_pubkey, cose_key_buffer, &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]);
HARDENED_RETURN_IF_ERROR(dice_chain_entry_payload_build(
cdi0_payload_buffer, &payload_buff_size, &issuer[0], sizeof(issuer),
subject, sizeof(subject), cose_key_buffer, cose_key_size,
rom_ext_measurement));

// Try to generate DiceChainEntryInput, by reusing the cert buffer.
size_t dice_chain_entry_input_size = *cert_size;
HARDENED_RETURN_IF_ERROR(
dice_chain_entry_input_build(cert, &dice_chain_entry_input_size,
cdi0_payload_buffer, payload_buff_size));
// Obtain digest & sign
hmac_digest_t tbs_digest;
hmac_sha256(cert, dice_chain_entry_input_size, &tbs_digest);
HARDENED_RETURN_IF_ERROR(
otbn_boot_attestation_endorse(&tbs_digest, &curr_tbs_signature));
curr_tbs_signature_le_to_be_convert(&curr_tbs_signature);

// Build the final DiceEntry
HARDENED_RETURN_IF_ERROR(
dice_chain_build(cert, cert_size, cdi0_payload_buffer, payload_buff_size,
&curr_tbs_signature));

return kErrorOk;
}

Expand All @@ -149,6 +363,8 @@ 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
HARDENED_RETURN_IF_ERROR(
dice_cdi_0_cert_build(owner_measurement, owner_security_version, key_ids,
cdi_1_pubkey, cert, cert_size));
return kErrorOk;
}

0 comments on commit 8df6d0d

Please sign in to comment.