Software APIs
dice_cwt.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include <stdint.h>
6 
8 #include "sw/device/silicon_creator/lib/base/util.h"
9 #include "sw/device/silicon_creator/lib/cert/cbor.h"
10 #include "sw/device/silicon_creator/lib/cert/cert.h"
11 #include "sw/device/silicon_creator/lib/cert/cwt_cose_key.h"
12 #include "sw/device/silicon_creator/lib/cert/cwt_dice_chain_entry.h"
13 #include "sw/device/silicon_creator/lib/cert/cwt_dice_chain_entry_input.h"
14 #include "sw/device/silicon_creator/lib/cert/cwt_dice_chain_entry_payload.h"
15 #include "sw/device/silicon_creator/lib/cert/dice.h"
16 #include "sw/device/silicon_creator/lib/cert/dice_keys.h"
17 #include "sw/device/silicon_creator/lib/drivers/hmac.h"
18 #include "sw/device/silicon_creator/lib/drivers/lifecycle.h"
19 #include "sw/device/silicon_creator/lib/drivers/otp.h"
20 #include "sw/device/silicon_creator/lib/error.h"
21 #include "sw/device/silicon_creator/lib/otbn_boot_services.h"
22 #include "sw/device/silicon_creator/lib/ownership/datatypes.h"
23 #include "sw/device/silicon_creator/lib/sigverify/ecdsa_p256_key.h"
24 #include "sw/device/silicon_creator/manuf/base/perso_tlv_data.h"
25 
26 #include "otp_ctrl_regs.h" // Generated.
27 
28 const dice_cert_format_t kDiceCertFormat = kDiceCertFormatCWTAndroid;
29 
30 enum config_desc_labels {
31  kSecurityVersionLabel = -70005,
32  // Implementataion specific value,
33  // less than -65536 and outside of [-70000, -70999]
34  kOwnerManifestMeasurmentLabel = -71006,
35 };
36 
37 // This input is designed to capture a configuration signal in a stable way,
38 // and to reflect important decisions a device makes at runtime.
39 // https://pigweed.googlesource.com/open-dice/+/HEAD/docs/specification.md#mode-value-details
40 enum open_dice_mode_value {
41  kDiceModeNormal = 1,
42  kDiceModeDebug = 2,
43 };
44 
45 enum payload_entry_sizes {
46  // The length of Profile Name
47  kProfileNameLength = 10,
48  // The Key ID length, which equals to the SHA256 digest size in bytes
49  kIssuerSubjectKeyIdLength = kHmacDigestNumBytes,
50  // The identifiers are 20 octets (reserve double size for HEX translation) so
51  // they fit in the RFC 5280 serialNumber field constraints and the
52  // X520SerialNumber type when hex encoded.
53  kIssuerSubjectNameLength = 40,
54  // 64 byte should be enough for 2 entries
55  kConfigDescBuffSize = 64,
56 };
57 static_assert(kIssuerSubjectNameLength <= kIssuerSubjectKeyIdLength * 2,
58  "Insufficient SubjectNameLength");
59 
60 // Reusable buffer for generating Configuration Descriptor
61 static uint8_t config_desc_buf[kConfigDescBuffSize] = {0};
62 // a0 # map(0)
63 const uint8_t kCborMap0[] = {0xa0};
64 // Reusable buffer for generating UDS/CDI_* COSE_Key
65 static uint8_t cose_key_buffer[kCwtCoseKeyMaxVariableSizeBytes] = {0};
66 // Reusable buffer for generating signature
67 static ecdsa_p256_signature_t curr_tbs_signature = {.r = {0}, .s = {0}};
68 
69 #define CWT_PROFILE_NAME "android.16"
70 
71 static uint8_t get_chip_mode_cdi0(void) {
72  return (lifecycle_is_prod() ? kDiceModeNormal : kDiceModeDebug);
73 }
74 
75 static uint8_t get_chip_mode_cdi1(owner_app_domain_t key_domain) {
76  if (launder32(key_domain) != kOwnerAppDomainProd) {
77  return kDiceModeDebug;
78  }
79  HARDENED_CHECK_EQ(key_domain, kOwnerAppDomainProd);
80  return kDiceModeNormal;
81 }
82 
83 static char issuer[kIssuerSubjectNameLength + 1] = {0};
84 static char subject[kIssuerSubjectNameLength + 1] = {0};
85 
86 static void fill_dice_id_string(
87  const uint8_t dice_id[kIssuerSubjectKeyIdLength],
88  char dice_id_str[kIssuerSubjectNameLength + 1]) {
89  size_t idx;
90  for (idx = 0; idx * 2 < kIssuerSubjectNameLength; idx++, dice_id_str += 2)
91  util_hexdump_byte(dice_id[idx], (uint8_t *)&dice_id_str[0]);
92 }
93 
94 static rom_error_t configuration_descriptor_build(
95  size_t *buf_size, const size_t sec_version,
96  const hmac_digest_t *manifest_measurement) {
98  cbor_out_init(&cbor_out, config_desc_buf);
99 
100  cbor_out_t *ptrs[2] = {NULL, &cbor_out};
101  const size_t ptrs_len = sizeof(ptrs) / sizeof(ptrs[0]);
102 
103  for (size_t i = 0; i < ptrs_len; ++i) {
104  cbor_out_t *cbor = ptrs[i];
105  size_t sz = 0;
106 
107  sz += cbor_write_map_header(cbor, (manifest_measurement != NULL) ? 2 : 1);
108  sz += cbor_write_int(cbor, kSecurityVersionLabel);
109  sz += cbor_write_int(cbor, sec_version);
110 
111  if (manifest_measurement != NULL) {
112  sz += cbor_write_int(cbor, kOwnerManifestMeasurmentLabel);
113  sz += cbor_write_bstr(cbor, (uint8_t *)&manifest_measurement->digest[0],
114  kHmacDigestNumBytes);
115  }
116 
117  if (sz > *buf_size)
118  return kErrorCertInvalidSize;
119  }
120 
121  *buf_size = cbor_out_size(&cbor_out);
122 
123  return kErrorOk;
124 }
125 
126 rom_error_t dice_uds_tbs_cert_build(
127  hmac_digest_t *otp_creator_sw_cfg_measurement,
128  hmac_digest_t *otp_owner_sw_cfg_measurement,
129  hmac_digest_t *otp_rot_creator_auth_codesign_measurement,
130  hmac_digest_t *otp_rot_creator_auth_state_measurement,
131  cert_key_id_pair_t *key_ids, ecdsa_p256_public_key_t *uds_pubkey,
132  uint8_t *tbs_cert, size_t *tbs_cert_size) {
133  cwt_cose_key_values_t cwt_cose_key_params = {
134  .pub_key_ec_x = (uint8_t *)uds_pubkey->x,
135  .pub_key_ec_x_size = sizeof(uds_pubkey->x),
136  .pub_key_ec_y = (uint8_t *)uds_pubkey->y,
137  .pub_key_ec_y_size = sizeof(uds_pubkey->y),
138  };
139  // For DICE CWT implementation, no need to sign UDS_Pub but just a COSE_Key
140  // structure.
141  // Those otp_*measurement parameters exist just for API alignment between
142  // different implementations.
143  OT_DISCARD(otp_creator_sw_cfg_measurement);
144  OT_DISCARD(otp_owner_sw_cfg_measurement);
145  OT_DISCARD(otp_rot_creator_auth_codesign_measurement);
146  OT_DISCARD(otp_rot_creator_auth_state_measurement);
147  OT_DISCARD(key_ids);
148  HARDENED_RETURN_IF_ERROR(
149  cwt_cose_key_build(&cwt_cose_key_params, tbs_cert, tbs_cert_size));
150 
151  return kErrorOk;
152 }
153 
154 rom_error_t dice_cdi_0_cert_build(hmac_digest_t *rom_ext_measurement,
155  uint32_t rom_ext_security_version,
156  cert_key_id_pair_t *key_ids,
157  ecdsa_p256_public_key_t *cdi_0_pubkey,
158  uint8_t *cert, size_t *cert_size) {
159  // Build Subject public key structure
160  size_t cose_key_size = sizeof(cose_key_buffer);
161  cwt_cose_key_values_t cwt_cose_key_params = {
162  .pub_key_ec_x = (uint8_t *)cdi_0_pubkey->x,
163  .pub_key_ec_x_size = sizeof(cdi_0_pubkey->x),
164  .pub_key_ec_y = (uint8_t *)cdi_0_pubkey->y,
165  .pub_key_ec_y_size = sizeof(cdi_0_pubkey->y),
166  };
167  HARDENED_RETURN_IF_ERROR(cwt_cose_key_build(
168  &cwt_cose_key_params, &cose_key_buffer[0], &cose_key_size));
169 
170  // Try to generate DiceChainEntryPayload
171  fill_dice_id_string((uint8_t *)(key_ids->endorsement->digest), issuer);
172  fill_dice_id_string((uint8_t *)(key_ids->cert->digest), subject);
173 
174  uint8_t
175  cdi0_entry_payload_buffer[kCwtDiceChainEntryPayloadMaxVariableSizeBytes];
176  size_t cdi0_entry_payload_size = sizeof(cdi0_entry_payload_buffer);
177 
178  size_t config_desc_buf_size = kConfigDescBuffSize;
179  // No extension measurement is needed in CDI_0, just pass a NULL to the
180  // config_descriptors to bypass encoding.
181  HARDENED_RETURN_IF_ERROR(configuration_descriptor_build(
182  &config_desc_buf_size, rom_ext_security_version, NULL));
183  hmac_digest_t conf_hash;
184  hmac_sha256(config_desc_buf, config_desc_buf_size, &conf_hash);
185  util_reverse_bytes(conf_hash.digest, kHmacDigestNumBytes);
186 
187  // Compute Authority Hash against an empty map since it's mandatory but
188  // "Authority Descriptor" isn't.
189  hmac_digest_t auth_hash;
190  hmac_sha256(kCborMap0, sizeof(kCborMap0), &auth_hash);
191  util_reverse_bytes(auth_hash.digest, kHmacDigestNumBytes);
192 
193  uint8_t mode = get_chip_mode_cdi0();
194  cwt_dice_chain_entry_payload_values_t cwt_dice_chain_entry_payload_params = {
195  .auth_hash = (uint8_t *)&auth_hash.digest[0],
196  .auth_hash_size = kHmacDigestNumBytes,
197  .code_hash = (uint8_t *)&rom_ext_measurement->digest[0],
198  .code_hash_size = kHmacDigestNumBytes,
199  .subject = &subject[0],
200  .subject_size = kIssuerSubjectNameLength,
201  .mode = &mode,
202  .mode_size = sizeof(mode),
203  .issuer = &issuer[0],
204  .issuer_size = kIssuerSubjectNameLength,
205  .subject_pk = &cose_key_buffer[0],
206  .subject_pk_size = cose_key_size,
207  .config_desc = config_desc_buf,
208  .config_desc_size = config_desc_buf_size,
209  .config_hash = (uint8_t *)&conf_hash.digest[0],
210  .config_hash_size = kHmacDigestNumBytes,
211  .profile_name = CWT_PROFILE_NAME,
212  .profile_name_size = kProfileNameLength};
213  HARDENED_RETURN_IF_ERROR(cwt_dice_chain_entry_payload_build(
214  &cwt_dice_chain_entry_payload_params, cdi0_entry_payload_buffer,
215  &cdi0_entry_payload_size));
216 
217  // Try to generate DiceChainEntryInput, by reusing the cert buffer.
218  size_t cdi0_entry_input_size = kCwtDiceChainEntryInputMaxVariableSizeBytes;
219  if (cdi0_entry_input_size > *cert_size)
220  return kErrorCertInvalidSize;
221  cwt_dice_chain_entry_input_values_t cwt_dice_chain_entry_input_params = {
222  .payload = cdi0_entry_payload_buffer,
223  .payload_size = cdi0_entry_payload_size};
224  HARDENED_RETURN_IF_ERROR(cwt_dice_chain_entry_input_build(
225  &cwt_dice_chain_entry_input_params, cert, &cdi0_entry_input_size));
226 
227  // Obtain digest & sign
228  hmac_digest_t tbs_digest;
229  hmac_sha256(cert, cdi0_entry_input_size, &tbs_digest);
230  HARDENED_RETURN_IF_ERROR(
231  otbn_boot_attestation_endorse(&tbs_digest, &curr_tbs_signature));
232  util_p256_signature_le_to_be_convert(curr_tbs_signature.r,
233  curr_tbs_signature.s);
234 
235  // Build the final DiceEntry
236  cwt_dice_chain_entry_values_t cwt_dice_chain_entry_params = {
237  .payload = cdi0_entry_payload_buffer,
238  .payload_size = cdi0_entry_payload_size,
239  .signature = (uint8_t *)&curr_tbs_signature,
240  .signature_size = sizeof(ecdsa_p256_signature_t)};
241  HARDENED_RETURN_IF_ERROR(cwt_dice_chain_entry_build(
242  &cwt_dice_chain_entry_params, cert, cert_size));
243 
244  // Save the CDI_0 private key to OTBN DMEM so it can endorse the next stage.
245  HARDENED_RETURN_IF_ERROR(otbn_boot_attestation_key_save(
246  kDiceKeyCdi0.keygen_seed_idx, kDiceKeyCdi0.type,
247  *kDiceKeyCdi0.keymgr_diversifier));
248  return kErrorOk;
249 }
250 
251 rom_error_t dice_cdi_1_cert_build(hmac_digest_t *owner_measurement,
252  hmac_digest_t *owner_manifest_measurement,
253  uint32_t owner_security_version,
254  owner_app_domain_t key_domain,
255  cert_key_id_pair_t *key_ids,
256  ecdsa_p256_public_key_t *cdi_1_pubkey,
257  uint8_t *cert, size_t *cert_size) {
258  // Build Subject public key structure
259  size_t cose_key_size = sizeof(cose_key_buffer);
260  cwt_cose_key_values_t cwt_cose_key_params = {
261  .pub_key_ec_x = (uint8_t *)cdi_1_pubkey->x,
262  .pub_key_ec_x_size = sizeof(cdi_1_pubkey->x),
263  .pub_key_ec_y = (uint8_t *)cdi_1_pubkey->y,
264  .pub_key_ec_y_size = sizeof(cdi_1_pubkey->y),
265  };
266  HARDENED_RETURN_IF_ERROR(cwt_cose_key_build(
267  &cwt_cose_key_params, &cose_key_buffer[0], &cose_key_size));
268 
269  // Try to generate DiceChainEntryPayload
270  fill_dice_id_string((uint8_t *)(key_ids->endorsement->digest), issuer);
271  fill_dice_id_string((uint8_t *)(key_ids->cert->digest), subject);
272 
273  uint8_t
274  cdi1_entry_payload_buffer[kCwtDiceChainEntryPayloadMaxVariableSizeBytes];
275  size_t cdi1_entry_payload_size = sizeof(cdi1_entry_payload_buffer);
276 
277  size_t config_desc_buf_size = sizeof(config_desc_buf);
278  HARDENED_RETURN_IF_ERROR(configuration_descriptor_build(
279  &config_desc_buf_size, owner_security_version,
280  owner_manifest_measurement));
281  hmac_digest_t conf_hash;
282  hmac_sha256(config_desc_buf, config_desc_buf_size, &conf_hash);
283  util_reverse_bytes(conf_hash.digest, kHmacDigestNumBytes);
284 
285  // Compute Authority Hash against an empty map since it's mandatory but
286  // "Authority Descriptor" isn't.
287  hmac_digest_t auth_hash;
288  hmac_sha256(kCborMap0, sizeof(kCborMap0), &auth_hash);
289  util_reverse_bytes(auth_hash.digest, kHmacDigestNumBytes);
290 
291  uint8_t mode = get_chip_mode_cdi1(key_domain);
292  cwt_dice_chain_entry_payload_values_t cwt_dice_chain_entry_payload_params = {
293  .auth_hash = (uint8_t *)&auth_hash.digest[0],
294  .auth_hash_size = kHmacDigestNumBytes,
295  .code_hash = (uint8_t *)&owner_measurement->digest[0],
296  .code_hash_size = kHmacDigestNumBytes,
297  .subject = &subject[0],
298  .subject_size = kIssuerSubjectNameLength,
299  .mode = &mode,
300  .mode_size = sizeof(mode),
301  .issuer = &issuer[0],
302  .issuer_size = kIssuerSubjectNameLength,
303  .subject_pk = &cose_key_buffer[0],
304  .subject_pk_size = cose_key_size,
305  .config_desc = config_desc_buf,
306  .config_desc_size = config_desc_buf_size,
307  .config_hash = (uint8_t *)&conf_hash.digest[0],
308  .config_hash_size = kHmacDigestNumBytes,
309  .profile_name = CWT_PROFILE_NAME,
310  .profile_name_size = kProfileNameLength};
311  HARDENED_RETURN_IF_ERROR(cwt_dice_chain_entry_payload_build(
312  &cwt_dice_chain_entry_payload_params, cdi1_entry_payload_buffer,
313  &cdi1_entry_payload_size));
314 
315  // Try to generate DiceChainEntryInput, by reusing the cert buffer.
316  size_t cdi1_entry_input_size = kCwtDiceChainEntryInputMaxVariableSizeBytes;
317  if (cdi1_entry_input_size > *cert_size)
318  return kErrorCertInvalidSize;
319  cwt_dice_chain_entry_input_values_t cwt_dice_chain_entry_input_params = {
320  .payload = cdi1_entry_payload_buffer,
321  .payload_size = cdi1_entry_payload_size};
322  HARDENED_RETURN_IF_ERROR(cwt_dice_chain_entry_input_build(
323  &cwt_dice_chain_entry_input_params, cert, &cdi1_entry_input_size));
324 
325  // Obtain digest & sign
326  hmac_digest_t tbs_digest;
327  hmac_sha256(cert, cdi1_entry_input_size, &tbs_digest);
328  HARDENED_RETURN_IF_ERROR(
329  otbn_boot_attestation_endorse(&tbs_digest, &curr_tbs_signature));
330  util_p256_signature_le_to_be_convert(curr_tbs_signature.r,
331  curr_tbs_signature.s);
332 
333  // Build the final DiceEntry
334  cwt_dice_chain_entry_values_t cwt_dice_chain_entry_params = {
335  .payload = cdi1_entry_payload_buffer,
336  .payload_size = cdi1_entry_payload_size,
337  .signature = (uint8_t *)&curr_tbs_signature,
338  .signature_size = sizeof(ecdsa_p256_signature_t)};
339  HARDENED_RETURN_IF_ERROR(cwt_dice_chain_entry_build(
340  &cwt_dice_chain_entry_params, cert, cert_size));
341 
342  // Save the CDI_1 private key to OTBN DMEM so it can endorse the next stage.
343  HARDENED_RETURN_IF_ERROR(otbn_boot_attestation_key_save(
344  kDiceKeyCdi1.keygen_seed_idx, kDiceKeyCdi1.type,
345  *kDiceKeyCdi1.keymgr_diversifier));
346 
347  return kErrorOk;
348 }
349 
350 rom_error_t dice_cert_check_valid(const perso_tlv_cert_obj_t *cert_obj,
351  const hmac_digest_t *pubkey_id,
352  const ecdsa_p256_public_key_t *pubkey,
353  hardened_bool_t *cert_valid_output) {
354  // TODO(lowRISC/opentitan:#24281): implement body
355  return kErrorOk;
356 }