Software APIs
ft_personalize.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 <stdalign.h>
6 
9 #include "sw/device/lib/crypto/drivers/entropy.h"
15 #include "sw/device/lib/testing/json/provisioning_data.h"
16 #include "sw/device/lib/testing/lc_ctrl_testutils.h"
17 #include "sw/device/lib/testing/rstmgr_testutils.h"
18 #include "sw/device/lib/testing/test_framework/check.h"
20 #include "sw/device/lib/testing/test_framework/ottf_test_config.h"
21 #include "sw/device/lib/testing/test_framework/status.h"
22 #include "sw/device/lib/testing/test_framework/ujson_ottf.h"
23 #include "sw/device/silicon_creator/lib/attestation.h"
24 #include "sw/device/silicon_creator/lib/base/boot_measurements.h"
26 #include "sw/device/silicon_creator/lib/base/util.h"
27 #include "sw/device/silicon_creator/lib/cert/cdi_0.h" // Generated.
28 #include "sw/device/silicon_creator/lib/cert/cdi_1.h" // Generated.
29 #include "sw/device/silicon_creator/lib/cert/cert.h"
30 #include "sw/device/silicon_creator/lib/cert/dice.h"
31 #include "sw/device/silicon_creator/lib/cert/uds.h" // Generated.
32 #include "sw/device/silicon_creator/lib/drivers/flash_ctrl.h"
33 #include "sw/device/silicon_creator/lib/drivers/hmac.h"
34 #include "sw/device/silicon_creator/lib/drivers/keymgr.h"
35 #include "sw/device/silicon_creator/lib/drivers/kmac.h"
36 #include "sw/device/silicon_creator/lib/drivers/otp.h"
37 #include "sw/device/silicon_creator/lib/error.h"
38 #include "sw/device/silicon_creator/lib/manifest.h"
39 #include "sw/device/silicon_creator/lib/otbn_boot_services.h"
40 #include "sw/device/silicon_creator/manuf/base/perso_tlv_data.h"
41 #include "sw/device/silicon_creator/manuf/base/personalize_ext.h"
42 #include "sw/device/silicon_creator/manuf/lib/flash_info_fields.h"
43 #include "sw/device/silicon_creator/manuf/lib/individualize_sw_cfg.h"
44 #include "sw/device/silicon_creator/manuf/lib/personalize.h"
45 
46 #include "flash_ctrl_regs.h" // Generated.
48 
49 OTTF_DEFINE_TEST_CONFIG(.console.type = kOttfConsoleSpiDevice,
50  .console.base_addr = TOP_EARLGREY_SPI_DEVICE_BASE_ADDR,
51  .console.test_may_clobber = false, );
52 
53 enum {
54  /**
55  * Size of the largest OTP partition to be measured.
56  */
57  kDiceMeasuredOtpPartitionMaxSizeIn32bitWords =
58  (OTP_CTRL_PARAM_OWNER_SW_CFG_SIZE -
59  OTP_CTRL_PARAM_OWNER_SW_CFG_DIGEST_SIZE) /
60  sizeof(uint32_t),
61 };
62 
63 static uint32_t otp_state[kDiceMeasuredOtpPartitionMaxSizeIn32bitWords] = {0};
64 
65 // clang-format off
66 static_assert(
67  OTP_CTRL_PARAM_OWNER_SW_CFG_SIZE > OTP_CTRL_PARAM_CREATOR_SW_CFG_SIZE &&
68  OTP_CTRL_PARAM_OWNER_SW_CFG_SIZE > OTP_CTRL_PARAM_ROT_CREATOR_AUTH_CODESIGN_SIZE &&
69  OTP_CTRL_PARAM_OWNER_SW_CFG_SIZE > OTP_CTRL_PARAM_ROT_CREATOR_AUTH_STATE_SIZE,
70  "The largest DICE measured OTP partition is no longer the "
71  "OwnerSwCfg partition. Update the "
72  "kDiceMeasuredOtpPartitionMaxSizeIn32bitWords constant.");
73 // clang-format on
74 
75 /**
76  * Peripheral handles.
77  */
78 static dif_flash_ctrl_state_t flash_ctrl_state;
79 static dif_lc_ctrl_t lc_ctrl;
80 static dif_otp_ctrl_t otp_ctrl;
81 static dif_rstmgr_t rstmgr;
82 
83 /**
84  * Keymgr binding values.
85  */
86 static keymgr_binding_value_t attestation_binding_value = {.data = {0}};
87 static keymgr_binding_value_t sealing_binding_value = {.data = {0}};
88 
89 /**
90  * Certificate data.
91  */
92 static hmac_digest_t otp_creator_sw_cfg_measurement;
93 static hmac_digest_t otp_owner_sw_cfg_measurement;
94 static hmac_digest_t otp_rot_creator_auth_codesign_measurement;
95 static hmac_digest_t otp_rot_creator_auth_state_measurement;
96 static manuf_certgen_inputs_t certgen_inputs;
97 static hmac_digest_t uds_endorsement_key_id;
98 static hmac_digest_t uds_pubkey_id;
99 static hmac_digest_t cdi_0_pubkey_id;
100 static hmac_digest_t cdi_1_pubkey_id;
101 static cert_key_id_pair_t uds_key_ids = {
102  .endorsement = &uds_endorsement_key_id,
103  .cert = &uds_pubkey_id,
104 };
105 static cert_key_id_pair_t cdi_0_key_ids = {
106  .endorsement = &uds_pubkey_id,
107  .cert = &cdi_0_pubkey_id,
108 };
109 static cert_key_id_pair_t cdi_1_key_ids = {
110  .endorsement = &cdi_0_pubkey_id,
111  .cert = &cdi_1_pubkey_id,
112 };
113 static ecdsa_p256_public_key_t curr_pubkey = {.x = {0}, .y = {0}};
114 static ecdsa_p256_public_key_t uds_pubkey = {.x = {0}, .y = {0}};
115 static perso_blob_t perso_blob_to_host; // Perso data device => host.
116 static perso_blob_t perso_blob_from_host; // Perso data host => device.
117 
118 /**
119  * Certificates flash info page layout.
120  */
121 static uint8_t all_certs[8192];
122 // 1K should be enough for the largest certificate perso LTV object.
123 enum { kBufferSize = 1024 };
124 static alignas(uint32_t) uint8_t cert_buffer[kBufferSize];
125 static size_t uds_offset;
126 static size_t cdi_0_offset;
127 static size_t cdi_1_offset;
128 static cert_flash_info_layout_t cert_flash_layout[] = {
129  {
130  // The DICE UDS cert is placed on this page since it must remain stable
131  // post manufacturing. This page should never be erased by ROM_EXT, nor
132  // owner firmware.
133  .used = true,
134  .group_name = "FACTORY",
135  .info_page = &kFlashCtrlInfoPageFactoryCerts,
136  .num_certs = 1,
137  },
138  {
139  .used = true,
140  .group_name = "DICE",
141  .info_page = &kFlashCtrlInfoPageDiceCerts,
142  .num_certs = 2,
143  },
144  // These flash info pages can be used by provisioning extensions to store
145  // additional certificates SKU owners may desire to provision.
146  {
147  .used = false,
148  .group_name = "Ext0",
149  .info_page = &kFlashCtrlInfoPageOwnerReserved6,
150  .num_certs = 0,
151  },
152  {
153  .used = false,
154  .group_name = "Ext1",
155  .info_page = &kFlashCtrlInfoPageOwnerReserved7,
156  .num_certs = 0,
157  },
158 };
159 
160 static void log_self_hash(void) {
161  // clang-format off
162  LOG_INFO("Personalization Firmware Hash: 0x%08x%08x%08x%08x%08x%08x%08x%08x",
163  boot_measurements.rom_ext.data[7],
164  boot_measurements.rom_ext.data[6],
165  boot_measurements.rom_ext.data[5],
166  boot_measurements.rom_ext.data[4],
167  boot_measurements.rom_ext.data[3],
168  boot_measurements.rom_ext.data[2],
169  boot_measurements.rom_ext.data[1],
170  boot_measurements.rom_ext.data[0]);
171  // clang-format on
172 }
173 
174 /*
175  * Return a pointer to the ROM_EXT manifest located in the slot b.
176  */
177 static const manifest_t *rom_ext_manifest_b_get(void) {
178  return (const manifest_t *)(TOP_EARLGREY_EFLASH_BASE_ADDR +
180 }
181 
182 extern const uint32_t kCreatorSwCfgManufStateValue;
183 
184 /*
185  * Check if the `identifier` field in slot_b is a ROM_EXT.
186  */
187 static status_t check_next_slot_bootable(void) {
188  TRY_CHECK(rom_ext_manifest_b_get()->identifier == CHIP_ROM_EXT_IDENTIFIER);
189  return OK_STATUS();
190 }
191 
192 /**
193  * Initializes all DIF handles used in this program.
194  */
195 static status_t peripheral_handles_init(void) {
197  &flash_ctrl_state,
199  TRY(dif_lc_ctrl_init(
201  TRY(dif_otp_ctrl_init(
204  &rstmgr));
205  return OK_STATUS();
206 }
207 
208 /**
209  * Issue a software reset.
210  */
211 static void sw_reset(void) {
212  rstmgr_testutils_reason_clear();
213  CHECK_DIF_OK(dif_rstmgr_software_device_reset(&rstmgr));
215 }
216 
217 /**
218  * Configures flash info pages to store device certificates.
219  */
220 static status_t config_and_erase_certificate_flash_pages(void) {
221  flash_ctrl_cert_info_page_creator_cfg(&kFlashCtrlInfoPageAttestationKeySeeds);
222  flash_ctrl_cert_info_page_creator_cfg(&kFlashCtrlInfoPageFactoryCerts);
223  flash_ctrl_cert_info_page_creator_cfg(&kFlashCtrlInfoPageDiceCerts);
224  // No need to erase the kFlashCtrlInfoPageAttestationKeySeeds page as it is
225  // erased on the first call to `manuf_personalize_flash_asymm_key_seed()`.
226  TRY(flash_ctrl_info_erase(&kFlashCtrlInfoPageFactoryCerts,
227  kFlashCtrlEraseTypePage));
228  TRY(flash_ctrl_info_erase(&kFlashCtrlInfoPageDiceCerts,
229  kFlashCtrlEraseTypePage));
230  return OK_STATUS();
231 }
232 
233 /**
234  * Helper function to compute measurements of various OTP partitions that are to
235  * be included in attestation certificates.
236  */
237 static status_t measure_otp_partition(otp_partition_t partition,
238  hmac_digest_t *measurement,
239  bool use_expected_values) {
240  // Compute the digest.
241  otp_dai_read(partition, /*address=*/0, otp_state,
242  kOtpPartitions[partition].size / sizeof(uint32_t));
243 
244  if (use_expected_values) {
245  // Sets the expected values for fields in the OTP that are not provisioned
246  // until the final stages of personalization.
247  if (partition == kOtpPartitionOwnerSwCfg) {
248  manuf_individualize_device_partition_expected_read(
249  kDifOtpCtrlPartitionOwnerSwCfg, (uint8_t *)otp_state);
250  } else if (partition == kOtpPartitionCreatorSwCfg) {
251  manuf_individualize_device_partition_expected_read(
252  kDifOtpCtrlPartitionCreatorSwCfg, (uint8_t *)otp_state);
253  }
254  }
255 
256  hmac_sha256(otp_state, kOtpPartitions[partition].size, measurement);
257 
258  return OK_STATUS();
259 }
260 
261 /**
262  * Provision OTP SECRET{1,2} partitions, keymgr flash info pages, enable flash
263  * scrambling, and reboot.
264  */
265 static status_t personalize_otp_and_flash_secrets(ujson_t *uj) {
266  // Provision OTP Secret1 partition, and complete provisioning of OTP
267  // CreatorSwCfg partition.
268  if (!status_ok(manuf_personalize_device_secret1_check(&otp_ctrl))) {
269  TRY(manuf_personalize_device_secret1(&lc_ctrl, &otp_ctrl));
270  }
271  if (!status_ok(
272  manuf_individualize_device_flash_data_default_cfg_check(&otp_ctrl))) {
273  TRY(manuf_individualize_device_field_cfg(
274  &otp_ctrl,
275  OTP_CTRL_PARAM_CREATOR_SW_CFG_FLASH_DATA_DEFAULT_CFG_OFFSET));
276  LOG_INFO("Bootstrap requested.");
278  }
279 
280  // Provision OTP Secret2 partition and flash info pages 1, 2, and 4 (keymgr
281  // and DICE keygen seeds).
282  if (!status_ok(manuf_personalize_device_secrets_check(&otp_ctrl))) {
283  lc_token_hash_t token_hash;
284  // Wait for host the host generated RMA unlock token hash to arrive over the
285  // console.
286  LOG_INFO("Waiting For RMA Unlock Token Hash ...");
287  CHECK_STATUS_OK(
288  UJSON_WITH_CRC(ujson_deserialize_lc_token_hash_t, uj, &token_hash));
289 
290  TRY(manuf_personalize_device_secrets(&flash_ctrl_state, &lc_ctrl, &otp_ctrl,
291  &token_hash));
292  TRY(manuf_personalize_flash_asymm_key_seed(
293  &flash_ctrl_state, kFlashInfoFieldUdsAttestationKeySeed,
294  kAttestationSeedWords));
295  TRY(manuf_personalize_flash_asymm_key_seed(
296  &flash_ctrl_state, kFlashInfoFieldCdi0AttestationKeySeed,
297  kAttestationSeedWords));
298  TRY(manuf_personalize_flash_asymm_key_seed(
299  &flash_ctrl_state, kFlashInfoFieldCdi1AttestationKeySeed,
300  kAttestationSeedWords));
301  // Provision the attestation key generation version field (at the end of the
302  // attestation seed info page).
303  uint32_t kKeyGenVersion = kAttestationKeyGenVersion0;
304  TRY(manuf_flash_info_field_write(
305  &flash_ctrl_state, kFlashInfoFieldAttestationKeyGenVersion,
306  /*data_in=*/&kKeyGenVersion, /*num_words=*/1,
307  /*erase_page_before_write=*/false));
308  sw_reset();
309  }
310 
311  return OK_STATUS();
312 }
313 
314 /**
315  * Sets the attestation binding to the ROM_EXT measurement, and the sealing
316  * binding to all zeros.
317  *
318  * The sealing binding value is set to all zeros as it is unused in the current
319  * personalization flow. This may be changed in the future.
320  */
321 static void compute_keymgr_owner_int_binding(manuf_certgen_inputs_t *inputs) {
322  memcpy(attestation_binding_value.data, inputs->rom_ext_measurement,
323  kDiceMeasurementSizeInBytes);
324  memset(sealing_binding_value.data, 0, kDiceMeasurementSizeInBytes);
325 }
326 
327 /**
328  * Sets the attestation binding to a combination of the Owner firmware and
329  * Ownership Manifest measurements, and the sealing binding to all zeros.
330  *
331  * The sealing binding value is set to the TEST application key domain.
332  */
333 static void compute_keymgr_owner_binding(manuf_certgen_inputs_t *inputs) {
334  hmac_digest_t combined_measurements;
335  hmac_sha256_init();
336  hmac_sha256_update((unsigned char *)inputs->owner_measurement,
337  kDiceMeasurementSizeInBytes);
338  hmac_sha256_update((unsigned char *)inputs->owner_manifest_measurement,
339  kDiceMeasurementSizeInBytes);
340  hmac_sha256_process();
341  hmac_sha256_final(&combined_measurements);
342  memcpy(attestation_binding_value.data, combined_measurements.digest,
343  kDiceMeasurementSizeInBytes);
344  memset(sealing_binding_value.data, 0, kDiceMeasurementSizeInBytes);
345  sealing_binding_value.data[0] = kOwnerAppDomainProd;
346 }
347 
348 /**
349  * Read a certificate from the passed in location in a flash INFO page and hash
350  * its contents on the existing sha256 hashing stream. Determine the actual
351  * certificate size from its ASN1 header.
352  *
353  * If the caller passed a pointer, save there the certificate size.
354  */
355 static status_t hash_certificate(const flash_ctrl_info_page_t *page,
356  size_t offset, size_t *size) {
357  memset(cert_buffer, 0, sizeof(cert_buffer));
358 
359  // Read first word of the certificate perso LTV object (contains the size).
360  perso_tlv_object_header_t objh;
361  uint16_t obj_size;
362  TRY(flash_ctrl_info_read(page, offset, 1, cert_buffer));
363  memcpy(&objh, cert_buffer, sizeof(perso_tlv_object_header_t));
364  PERSO_TLV_GET_FIELD(Objh, Size, objh, &obj_size);
365 
366  // Validate the perso LTV object size.
367  if (obj_size == 0) {
368  LOG_ERROR(
369  "Inconsistent certificate perso LTV object header %02x %02x at "
370  "page:offset %x:%x",
371  cert_buffer[0], cert_buffer[1], page->base_addr, offset);
372  return DATA_LOSS();
373  }
374  if (obj_size > sizeof(cert_buffer)) {
375  LOG_ERROR("Bad certificate perso LTV object size %d at page:offset %x:%x",
376  obj_size, page->base_addr, offset);
377  return DATA_LOSS();
378  }
379  if ((obj_size + offset) > FLASH_CTRL_PARAM_BYTES_PER_PAGE) {
380  LOG_ERROR("Cert size overflow (%d + %d) page %x:%x", obj_size, offset,
381  page->base_addr, offset);
382  return DATA_LOSS();
383  }
384 
385  // Read the entire perso LTV object from flash and parse it.
386  perso_tlv_cert_obj_t cert_obj;
387  TRY(flash_ctrl_info_read(page, offset, util_size_to_words(obj_size),
388  cert_buffer));
389  TRY(perso_tlv_get_cert_obj(cert_buffer, kBufferSize, &cert_obj));
390 
391  hmac_sha256_update(cert_obj.cert_body_p, cert_obj.cert_body_size);
392 
393  if (size) {
394  *size = obj_size;
395  }
396 
397  return OK_STATUS();
398 }
399 
400 static status_t hash_all_certs(void) {
401  uint32_t cert_obj_size;
402  hmac_sha256_init();
403 
404  // Push all certificates into the hash.
405  for (size_t i = 0; i < ARRAYSIZE(cert_flash_layout); i++) {
406  uint32_t page_offset = 0;
407  const cert_flash_info_layout_t curr_layout = cert_flash_layout[i];
408  // Skip the page if it is not in use.
409  if (!curr_layout.used) {
410  continue;
411  }
412  for (size_t j = 0; j < curr_layout.num_certs; j++) {
413  TRY(hash_certificate(curr_layout.info_page, page_offset, &cert_obj_size));
414  page_offset += util_size_to_words(cert_obj_size) * sizeof(uint32_t);
415  page_offset = util_round_up_to(page_offset, 3);
416  }
417  }
418 
419  return OK_STATUS();
420 }
421 
422 /**
423  * Crank the keymgr to produce the DICE attestation keys and certificates.
424  */
425 static status_t personalize_gen_dice_certificates(ujson_t *uj) {
426  /*****************************************************************************
427  * Initialization.
428  ****************************************************************************/
429  // Load OTBN attestation keygen program.
430  // TODO(#21550): this should already be loaded by the ROM.
431  TRY(otbn_boot_app_load());
432 
433  // Configure certificate flash info page permissions.
434  TRY(config_and_erase_certificate_flash_pages());
435 
436  // Retrieve certificate provisioning data.
437  // DO NOT CHANGE THE BELOW STRING without modifying the host code in
438  // sw/host/provisioning/ft_lib/src/lib.rs
439  LOG_INFO("Waiting for certificate inputs ...");
440  TRY(ujson_deserialize_manuf_certgen_inputs_t(uj, &certgen_inputs));
441  // We copy over the UDS endorsement key ID to an SHA256 digest type, since
442  // this is the format of key IDs generated on-dice.
443  memcpy(uds_endorsement_key_id.digest, certgen_inputs.dice_auth_key_key_id,
444  kCertKeyIdSizeInBytes);
445 
446  // Initialize entropy complex / KMAC for key manager operations.
447  TRY(entropy_complex_init());
448  TRY(kmac_keymgr_configure());
449 
450  // Advance keymgr to CreatorRootKey state.
451  TRY(sc_keymgr_state_check(kScKeymgrStateReset));
452  sc_keymgr_advance_state();
453  TRY(sc_keymgr_state_check(kScKeymgrStateInit));
454  sc_keymgr_advance_state();
455 
456  // Measure OTP partitions.
457  //
458  // Note:
459  // - We do not measure HwCfg0 as this is the Device ID, which is already
460  // mixed into the keyladder directly via hardware channels.
461  // - We pre-calculate the OTP measurement of CreatorSwCfg and OwnerSwCfg
462  // partitions using expected values for fields not yet provisioned. This
463  // ensures consistent measurements throughout personalization.
464  TRY(measure_otp_partition(kOtpPartitionCreatorSwCfg,
465  &otp_creator_sw_cfg_measurement,
466  /*use_expected_values=*/true));
467  TRY(measure_otp_partition(kOtpPartitionOwnerSwCfg,
468  &otp_owner_sw_cfg_measurement,
469  /*use_expected_values=*/true));
470  TRY(measure_otp_partition(kOtpPartitionRotCreatorAuthCodesign,
471  &otp_rot_creator_auth_codesign_measurement,
472  /*use_expected_values=*/false));
473  TRY(measure_otp_partition(kOtpPartitionRotCreatorAuthState,
474  &otp_rot_creator_auth_state_measurement,
475  /*use_expected_values=*/false));
476 
477  /*****************************************************************************
478  * DICE certificates.
479  ****************************************************************************/
480  size_t curr_cert_size = 0;
481 
482  // Generate UDS keys and (TBS) cert.
483  curr_cert_size = kUdsMaxTbsSizeBytes;
484  TRY(otbn_boot_cert_ecc_p256_keygen(kDiceKeyUds, &uds_pubkey_id,
485  &curr_pubkey));
486  memcpy(&uds_pubkey, &curr_pubkey, sizeof(ecdsa_p256_public_key_t));
487  TRY(otbn_boot_attestation_key_save(kDiceKeyUds.keygen_seed_idx,
488  kDiceKeyUds.type,
489  *kDiceKeyUds.keymgr_diversifier));
490 
491  // Build the certificate in a temp buffer, use all_certs for that.
492  TRY(dice_uds_tbs_cert_build(
493  &otp_creator_sw_cfg_measurement, &otp_owner_sw_cfg_measurement,
494  &otp_rot_creator_auth_codesign_measurement,
495  &otp_rot_creator_auth_state_measurement, &uds_key_ids, &curr_pubkey,
496  all_certs, &curr_cert_size));
497  // DO NOT CHANGE THE "UDS" STRING BELOW with modifying the `dice_cert_names`
498  // collection in sw/host/provisioning/ft_lib/src/lib.rs.
499  uds_offset = perso_blob_to_host.next_free;
500  TRY(perso_tlv_push_cert_to_perso_blob(
501  "UDS",
502  /*needs_endorsement=*/kDiceCertFormat == kDiceCertFormatX509TcbInfo,
503  kDiceCertFormat, all_certs, curr_cert_size, &perso_blob_to_host));
504  LOG_INFO("Generated UDS certificate.");
505 
506  // Generate CDI_0 keys and cert.
507  curr_cert_size = kCdi0MaxCertSizeBytes;
508  compute_keymgr_owner_int_binding(&certgen_inputs);
509  TRY(sc_keymgr_owner_int_advance(&sealing_binding_value,
510  &attestation_binding_value,
511  /*max_key_version=*/0));
512  TRY(otbn_boot_cert_ecc_p256_keygen(kDiceKeyCdi0, &cdi_0_pubkey_id,
513  &curr_pubkey));
514  TRY(dice_cdi_0_cert_build((hmac_digest_t *)certgen_inputs.rom_ext_measurement,
515  certgen_inputs.rom_ext_security_version,
516  &cdi_0_key_ids, &curr_pubkey, all_certs,
517  &curr_cert_size));
518  cdi_0_offset = perso_blob_to_host.next_free;
519  // DO NOT CHANGE THE "CDI_0" STRING BELOW with modifying the `dice_cert_names`
520  // collection in sw/host/provisioning/ft_lib/src/lib.rs.
521  TRY(perso_tlv_push_cert_to_perso_blob("CDI_0", /*needs_endorsement=*/false,
522  kDiceCertFormat, all_certs,
523  curr_cert_size, &perso_blob_to_host));
524  LOG_INFO("Generated CDI_0 certificate.");
525 
526  // Generate CDI_1 keys and cert.
527  curr_cert_size = kCdi1MaxCertSizeBytes;
528  compute_keymgr_owner_binding(&certgen_inputs);
529  TRY(sc_keymgr_owner_advance(&sealing_binding_value,
530  &attestation_binding_value,
531  /*max_key_version=*/0));
532  TRY(otbn_boot_cert_ecc_p256_keygen(kDiceKeyCdi1, &cdi_1_pubkey_id,
533  &curr_pubkey));
534  TRY(dice_cdi_1_cert_build(
535  (hmac_digest_t *)certgen_inputs.owner_measurement,
536  (hmac_digest_t *)certgen_inputs.owner_manifest_measurement,
537  certgen_inputs.owner_security_version, kOwnerAppDomainProd,
538  &cdi_1_key_ids, &curr_pubkey, all_certs, &curr_cert_size));
539  cdi_1_offset = perso_blob_to_host.next_free;
540  // DO NOT CHANGE THE "CDI_1" STRING BELOW with modifying the `dice_cert_names`
541  // collection in sw/host/provisioning/ft_lib/src/lib.rs.
542  TRY(perso_tlv_push_cert_to_perso_blob("CDI_1", /*needs_endorsement=*/false,
543  kDiceCertFormat, all_certs,
544  curr_cert_size, &perso_blob_to_host));
545  LOG_INFO("Generated CDI_1 certificate.");
546 
547  return OK_STATUS();
548 }
549 
550 // Returns how much data is left in the perso blob receive buffer (i.e., `body`
551 // field). Useful when scanning the receive buffer containing perso LTV objects.
552 static size_t max_available(void) {
553  if (perso_blob_from_host.next_free > sizeof(perso_blob_from_host.body))
554  return 0; // This could never happen, but just in case.
555 
556  return sizeof(perso_blob_from_host.body) - perso_blob_from_host.next_free;
557 }
558 
559 /**
560  * Find the next certificate perso LTV object in the receive perso buffer and
561  * copy it to the passed in location.
562  *
563  * @param dest Pointer to pointer in the destination buffer; this function
564  * advances the pointer by the size of the copied certificate perso
565  * LTV object.
566  * @param free_room Pointer to the size of the destination buffer; this function
567  * reduces the size of the buffer by the size of the copied
568  * certificate perso LTV object.
569  */
570 static status_t extract_next_cert(uint8_t **dest, size_t *free_room) {
571  // A just in case sanity check that the next free location in the perso blob
572  // data buffer is at the end of the buffer.
573  if (perso_blob_from_host.next_free > sizeof(perso_blob_from_host.body)) {
574  return INTERNAL(); // Something is really screwed up.
575  }
576 
577  // Scan the received buffer until the next endorsed cert is found.
578  while (perso_blob_from_host.num_objs != 0) {
579  perso_tlv_cert_obj_t block;
580 
581  // Extract the next perso LTV object, aborting if it is not a certificate.
582  rom_error_t err = perso_tlv_get_cert_obj(
583  perso_blob_from_host.body + perso_blob_from_host.next_free,
584  max_available(), &block);
585  switch (err) {
586  case kErrorOk:
587  break;
588  case kErrorPersoTlvCertObjNotFound: {
589  // The object found is not a certificate. Skip to next perso LTV object.
590  perso_blob_from_host.next_free += block.obj_size;
591  perso_blob_from_host.num_objs--;
592  continue;
593  }
594  default:
595  return INTERNAL();
596  }
597 
598  // Check there is enough room in the destination buffer to copy the
599  // certificate perso LTV object.
600  if (*free_room < block.obj_size)
601  return RESOURCE_EXHAUSTED();
602 
603  // Copy the certificate object to the destination buffer.
604  uint8_t *dest_p = *dest;
605  memcpy(dest_p, block.obj_p, block.obj_size);
606  LOG_INFO("Copied %s certificate", block.name);
607 
608  // Advance destination buffer pointer and reduce free space counter.
609  *dest = dest_p + block.obj_size;
610  *free_room = *free_room - block.obj_size;
611 
612  // Advance pointer to next perso LTV object in the receive buffer.
613  perso_blob_from_host.next_free += block.obj_size;
614  perso_blob_from_host.num_objs--;
615  return OK_STATUS();
616  }
617 
618  return OK_STATUS();
619 }
620 
621 static status_t write_cert_to_flash_info_page(
622  const cert_flash_info_layout_t *layout, perso_tlv_cert_obj_t *block,
623  uint8_t *cert_data, uint32_t page_offset, uint32_t cert_write_size_bytes,
624  uint32_t cert_write_size_words) {
625  if ((page_offset + cert_write_size_bytes) > FLASH_CTRL_PARAM_BYTES_PER_PAGE) {
626  LOG_ERROR("%s %s certificate did not fit into the info page.",
627  layout->group_name, block->name);
628  return OUT_OF_RANGE();
629  }
630  if (sizeof(cert_buffer) < cert_write_size_bytes) {
631  LOG_ERROR("%s %s certificate did not fit into the buffer.",
632  layout->group_name, block->name);
633  return OUT_OF_RANGE();
634  }
635 
636  memset(cert_buffer, 0, cert_write_size_bytes);
637 
638  // Copy the actual certificate data into the cert buffer.
639  // This is necessary because flash_ctrl_info_write() requires the
640  // data source pointer to be word-aligned. The input cert_data
641  // pointer might not meet this alignment requirement, whereas
642  // cert_buffer is expected to be world-aligned.
643  memcpy(cert_buffer, cert_data, block->obj_size);
644 
645  TRY(flash_ctrl_info_write(layout->info_page, page_offset,
646  cert_write_size_words, cert_buffer));
647 
648  return OK_STATUS();
649 }
650 
651 static status_t personalize_endorse_certificates(ujson_t *uj) {
652  /*****************************************************************************
653  * Certificate Export and Endorsement.
654  ****************************************************************************/
655  // Export the certificates to the provisioning appliance.
656  // DO NOT CHANGE THE BELOW STRING without modifying the host code in
657  // sw/host/provisioning/ft_lib/src/lib.rs
658  LOG_INFO("Exporting TBS certificates ...");
659 
660  RESP_OK(ujson_serialize_perso_blob_t, uj, &perso_blob_to_host);
661 
662  // Import endorsed certificates from the provisioning appliance.
663  // DO NOT CHANGE THE BELOW STRING without modifying the host code in
664  // sw/host/provisioning/ft_lib/src/lib.rs
665  LOG_INFO("Importing endorsed certificates ...");
666  TRY(ujson_deserialize_perso_blob_t(uj, &perso_blob_from_host));
667 
668  /*****************************************************************************
669  * Rearrange certificates to prepare for writing to flash.
670  *
671  * All certificates are ordered in a buffer (all_certs) according to the order
672  * in which they will be written to flash. That order is:
673  * 1. UDS cert
674  * 2. CDI_0 cert
675  * 3. CDI_1 cert
676  * 4. Provision Extension certs
677  ****************************************************************************/
678  // We start scanning the perso LTV buffer we received from the host from the
679  // beginnging. We assume that the endorsed UDS cert is the first certificate
680  // in the buffer (even if preceeded by other types of perso LTV objects).
681  perso_blob_from_host.next_free = 0;
682  // Location where the next cert perso LTV object will be copied to in the
683  // `all_certs` buffer.
684  uint8_t *next_cert = all_certs;
685  // How much room left in the destination (`all_certs`) buffer.
686  size_t free_room = sizeof(all_certs);
687  // Helper structure caching certificate information from a certificate perso
688  // LTV object.
689  perso_tlv_cert_obj_t block;
690 
691  // CWT DICE doesn't need host to endorse any certificate for it, so all
692  // payload are in the "perso_blob_to_host".
693  // Default to this setting, and move to X509 setting if the flag is set.
694  size_t cert_offsets[3] = {uds_offset, cdi_0_offset, cdi_1_offset};
695  size_t cert_offsets_count = 3;
696  if (kDiceCertFormat == kDiceCertFormatX509TcbInfo) {
697  // Exract the UDS cert perso LTV object.
698  TRY(extract_next_cert(&next_cert, &free_room));
699  // Extract the two CDI cert perso LTV objects which were endorsed on-device
700  // and sent to the host.
701  cert_offsets[0] = cert_offsets[1];
702  cert_offsets[1] = cert_offsets[2];
703  cert_offsets_count = 2;
704  }
705  // Extract the cert perso LTV objects which were endorsed on-device and send
706  // to the host.
707  for (size_t i = 0; i < cert_offsets_count; i++) {
708  size_t offset = cert_offsets[i];
709  TRY(perso_tlv_get_cert_obj(perso_blob_to_host.body + offset,
710  sizeof(perso_blob_to_host.body) - offset,
711  &block));
712  if (block.obj_size > free_room)
713  return RESOURCE_EXHAUSTED();
714 
715  memcpy(next_cert, block.obj_p, block.obj_size);
716  LOG_INFO("Copied %s certificate", block.name);
717  next_cert += block.obj_size;
718  free_room -= block.obj_size;
719  }
720 
721  // Extract the remaining cert perso LTV objects received from the host.
722  while (perso_blob_from_host.num_objs)
723  TRY(extract_next_cert(&next_cert, &free_room));
724 
725  /*****************************************************************************
726  * Save Certificates to Flash.
727  ****************************************************************************/
728  // This is where the certificates to be copied are stored, each one encoded as
729  // a perso LTV object. Reset the `next_cert` pointer and `free_room` size.
730  next_cert = all_certs;
731  free_room = sizeof(all_certs);
732  for (size_t i = 0; i < ARRAYSIZE(cert_flash_layout); i++) {
733  const cert_flash_info_layout_t curr_layout = cert_flash_layout[i];
734  uint32_t page_offset = 0;
735 
736  // Skip the page if it is not in use.
737  if (!curr_layout.used) {
738  continue;
739  }
740 
741  // This is a bit brittle, but we expect the sum of {layout}.num_certs values
742  // in the following flash layout sections to be equal to the number of
743  // endorsed extension certificates received from the host.
744  for (size_t j = 0; j < curr_layout.num_certs; j++) {
745  // Extract the cert block from the `all_certs` buffer.
746  TRY(perso_tlv_get_cert_obj(next_cert, free_room, &block));
747  // Round up the size to the nearest word boundary.
748  uint32_t cert_size_words = util_size_to_words(block.obj_size);
749  uint32_t cert_size_bytes_ru = cert_size_words * sizeof(uint32_t);
750  TRY(write_cert_to_flash_info_page(&curr_layout, &block, next_cert,
751  page_offset, cert_size_bytes_ru,
752  cert_size_words));
753  LOG_INFO("Imported %s %s certificate.", curr_layout.group_name,
754  block.name);
755  page_offset += cert_size_bytes_ru;
756  next_cert += block.obj_size;
757 
758  // Each certificate must be 8 bytes aligned (flash word size).
759  page_offset = util_round_up_to(page_offset, 3);
760  }
761  }
762 
763  // DO NOT CHANGE THE BELOW STRING without modifying the host code in
764  // sw/host/provisioning/ft_lib/src/lib.rs
765  LOG_INFO("Finished importing certificates.");
766 
767  return OK_STATUS();
768 }
769 
770 static status_t send_final_hash(ujson_t *uj, serdes_sha256_hash_t *hash) {
771  return RESP_OK(ujson_serialize_serdes_sha256_hash_t, uj, hash);
772 }
773 
774 /**
775  * Compare the OTP measurement used during certificate generation with the OTP
776  * measurment calculated from the final OTP values. Ensure that the UDS
777  * certificate was generated using the correct OTP values.
778  */
779 static status_t check_otp_measurement_pre_lock(hmac_digest_t *measurement,
780  otp_partition_t partition) {
781  hmac_digest_t final_measurement;
782  TRY(measure_otp_partition(partition, &final_measurement,
783  /*use_expected_values=*/false));
784 
785  TRY_CHECK(final_measurement.digest[1] == measurement->digest[1]);
786  TRY_CHECK(final_measurement.digest[0] == measurement->digest[0]);
787  return OK_STATUS();
788 }
789 
790 /**
791  * Compare the OTP measurement used during certificate generation with the
792  * digest stored in the OTP. Ensure that the UDS certificate was generated using
793  * the correct OTP values.
794  */
795 static status_t check_otp_measurement_post_lock(hmac_digest_t *measurement,
796  uint32_t offset) {
797  uint64_t expected_digest = otp_read64(offset);
798  uint32_t digest_hi = expected_digest >> 32;
799  uint32_t digest_lo = expected_digest & UINT32_MAX;
800  TRY_CHECK(digest_hi == measurement->digest[1]);
801  TRY_CHECK(digest_lo == measurement->digest[0]);
802  return OK_STATUS();
803 }
804 
805 static status_t finalize_otp_partitions(void) {
806  // TODO(#21554): Complete the provisioning of the root keys and key policies.
807 
808  TRY(check_next_slot_bootable());
809 
810  // Complete the provisioning of OTP OwnerSwCfg partition.
811  if (!status_ok(manuf_individualize_device_owner_sw_cfg_check(&otp_ctrl))) {
812  TRY(manuf_individualize_device_field_cfg(
813  &otp_ctrl, OTP_CTRL_PARAM_OWNER_SW_CFG_ROM_BOOTSTRAP_DIS_OFFSET));
814  TRY(check_otp_measurement_pre_lock(&otp_owner_sw_cfg_measurement,
815  kOtpPartitionOwnerSwCfg));
816  TRY(manuf_individualize_device_owner_sw_cfg_lock(&otp_ctrl));
817  }
818  TRY(check_otp_measurement_post_lock(
819  &otp_owner_sw_cfg_measurement,
820  OTP_CTRL_PARAM_OWNER_SW_CFG_DIGEST_OFFSET));
821 
822  // Complete the provisioning of OTP CreatorSwCfg partition.
823  if (!status_ok(manuf_individualize_device_creator_sw_cfg_check(&otp_ctrl))) {
824  TRY(manuf_individualize_device_field_cfg(
825  &otp_ctrl, OTP_CTRL_PARAM_CREATOR_SW_CFG_MANUF_STATE_OFFSET));
826  TRY(manuf_individualize_device_field_cfg(
827  &otp_ctrl, OTP_CTRL_PARAM_CREATOR_SW_CFG_IMMUTABLE_ROM_EXT_EN_OFFSET));
828  TRY(check_otp_measurement_pre_lock(&otp_creator_sw_cfg_measurement,
829  kOtpPartitionCreatorSwCfg));
830  TRY(manuf_individualize_device_creator_sw_cfg_lock(&otp_ctrl));
831  }
832  TRY(check_otp_measurement_post_lock(
833  &otp_creator_sw_cfg_measurement,
834  OTP_CTRL_PARAM_CREATOR_SW_CFG_DIGEST_OFFSET));
835 
836  return OK_STATUS();
837 }
838 
839 bool test_main(void) {
840  CHECK_STATUS_OK(peripheral_handles_init());
841  ujson_t uj = ujson_ottf_console();
842  log_self_hash();
843  CHECK_STATUS_OK(lc_ctrl_testutils_operational_state_check(&lc_ctrl));
844  CHECK_STATUS_OK(personalize_otp_and_flash_secrets(&uj));
845  CHECK_STATUS_OK(personalize_gen_dice_certificates(&uj));
846 
848  .uj = &uj,
849  .certgen_inputs = &certgen_inputs,
850  .perso_blob_to_host = &perso_blob_to_host,
851  .cert_flash_layout = cert_flash_layout,
852  .flash_ctrl_handle = &flash_ctrl_state,
853  .uds_pubkey = &uds_pubkey,
854  .uds_pubkey_id = &uds_pubkey_id,
855  .otp_creator_sw_cfg_measurement = &otp_creator_sw_cfg_measurement,
856  .otp_owner_sw_cfg_measurement = &otp_owner_sw_cfg_measurement,
857  .otp_rot_creator_auth_codesign_measurement =
858  &otp_rot_creator_auth_codesign_measurement,
859  .otp_rot_creator_auth_state_measurement =
860  &otp_rot_creator_auth_state_measurement};
861  CHECK_STATUS_OK(personalize_extension_pre_cert_endorse(&pre_endorse));
862 
863  CHECK_STATUS_OK(personalize_endorse_certificates(&uj));
864  CHECK_STATUS_OK(hash_all_certs());
865 
866  personalize_extension_post_endorse_t post_endorse = {
867  .uj = &uj,
868  .perso_blob_from_host = &perso_blob_from_host,
869  .cert_flash_layout = cert_flash_layout};
870  CHECK_STATUS_OK(personalize_extension_post_cert_endorse(&post_endorse));
871 
872  // Log the hash of all perso objects to the host and console.
873  serdes_sha256_hash_t hash;
874  hmac_sha256_process();
875  hmac_sha256_final((hmac_digest_t *)&hash);
876  CHECK_STATUS_OK(send_final_hash(&uj, &hash));
877  LOG_INFO("SHA256 hash of all perso objects: %08x%08x%08x%08x%08x%08x%08x%08x",
878  hash.data[7], hash.data[6], hash.data[5], hash.data[4], hash.data[3],
879  hash.data[2], hash.data[1], hash.data[0]);
880 
881  CHECK_STATUS_OK(finalize_otp_partitions());
882  // DO NOT CHANGE THE BELOW STRING without modifying the host code in
883  // sw/host/provisioning/ft_lib/src/lib.rs
884  LOG_INFO("Personalization done.");
885 
886  return true;
887 }