Software APIs
test_owner.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 
8 #include "sw/device/silicon_creator/lib/dbg_print.h"
9 #include "sw/device/silicon_creator/lib/drivers/flash_ctrl.h"
10 #include "sw/device/silicon_creator/lib/error.h"
11 #include "sw/device/silicon_creator/lib/ownership/keys/fake/activate_ecdsa_p256.h"
12 #include "sw/device/silicon_creator/lib/ownership/keys/fake/app_dev_ecdsa_p256.h"
13 #include "sw/device/silicon_creator/lib/ownership/keys/fake/app_prod_ecdsa_p256.h"
14 #include "sw/device/silicon_creator/lib/ownership/keys/fake/app_test_ecdsa_p256.h"
15 #include "sw/device/silicon_creator/lib/ownership/keys/fake/owner_ecdsa_p256.h"
16 #include "sw/device/silicon_creator/lib/ownership/keys/fake/unlock_ecdsa_p256.h"
17 #include "sw/device/silicon_creator/lib/ownership/owner_block.h"
18 #include "sw/device/silicon_creator/lib/ownership/ownership.h"
19 #include "sw/device/silicon_creator/lib/ownership/ownership_key.h"
20 
21 /*
22  * This module overrides the weak `sku_creator_owner_init` symbol in
23  * ownership.c, thus allowing FPGA builds to boot in the `LockedOwner` state
24  * with a valid set of keys.
25  */
26 
27 // NOTE: if you update this version number, you must also update the version
28 // number in the test library `sw/host/tests/ownership/transfer_lib.rs`.
29 #define TEST_OWNER_CONFIG_VERSION 1
30 
31 #ifndef TEST_OWNER_UPDATE_MODE
32 #define TEST_OWNER_UPDATE_MODE kOwnershipUpdateModeOpen
33 #endif
34 
35 rom_error_t sku_creator_owner_init(boot_data_t *bootdata,
36  owner_config_t *config,
37  owner_application_keyring_t *keyring) {
38  owner_key_t owner = (owner_key_t){
39  // Although this is an ECDSA key, we initialize the `raw` member of the
40  // union to zero-initialize the unused space.
41  .raw = OWNER_ECDSA_P256};
42  ownership_state_t state = bootdata->ownership_state;
43 
44  if (state == kOwnershipStateUnlockedSelf ||
45  state == kOwnershipStateUnlockedAny ||
46  state == kOwnershipStateUnlockedEndorsed) {
47  // Nothing to do when in an unlocked state.
48  return kErrorOk;
49  } else if (state == kOwnershipStateLockedOwner) {
50  if (hardened_memeq(owner.raw, owner_page[0].owner_key.raw,
51  ARRAYSIZE(owner.raw)) != kHardenedBoolTrue ||
52  TEST_OWNER_CONFIG_VERSION <= owner_page[0].config_version) {
53  // Different owner or already newest config version; nothing to do.
54  return kErrorOk;
55  }
56  } else {
57  // State is an unknown value, which is the same as kOwnershipStateRecovery.
58  // We'll not return, thus allowing the owner config below to be programmed
59  // into flash.
60  }
61 
62  owner_page[0].header.tag = kTlvTagOwner;
63  owner_page[0].header.length = 2048;
64  owner_page[0].header.version = (struct_version_t){0, 0};
65  owner_page[0].config_version = TEST_OWNER_CONFIG_VERSION;
66  owner_page[0].sram_exec_mode = kOwnerSramExecModeDisabledLocked;
67  owner_page[0].ownership_key_alg = kOwnershipKeyAlgEcdsaP256;
68  owner_page[0].update_mode = TEST_OWNER_UPDATE_MODE;
69  owner_page[0].min_security_version_bl0 = UINT32_MAX;
70  owner_page[0].lock_constraint = 0;
71  memset(owner_page[0].device_id, kLockConstraintNone,
72  sizeof(owner_page[0].device_id));
73  owner_page[0].owner_key = owner;
74  owner_page[0].activate_key = (owner_key_t){
75  // Although this is an ECDSA key, we initialize the `raw` member of the
76  // union to zero-initialize the unused space.
77  .raw = ACTIVATE_ECDSA_P256};
78  owner_page[0].unlock_key = (owner_key_t){
79  // Although this is an ECDSA key, we initialize the `raw` member of the
80  // union to zero-initialize the unused space.
81  .raw = UNLOCK_ECDSA_P256};
82 
83  owner_application_key_t *app = (owner_application_key_t *)owner_page[0].data;
84  *app = (owner_application_key_t){
85  .header =
86  {
87  .tag = kTlvTagApplicationKey,
88  .length = kTlvLenApplicationKeyEcdsa,
89  },
90  .key_alg = kOwnershipKeyAlgEcdsaP256,
91  .key_domain = kOwnerAppDomainTest,
92  .key_diversifier = {0},
93  .usage_constraint = 0,
94  .data =
95  {
96  .ecdsa = APP_TEST_ECDSA_P256,
97  },
98  };
99 
100  app = (owner_application_key_t *)((uintptr_t)app + app->header.length);
101  *app = (owner_application_key_t){
102  .header =
103  {
104  .tag = kTlvTagApplicationKey,
105  .length = kTlvLenApplicationKeyEcdsa,
106  },
107  .key_alg = kOwnershipKeyAlgEcdsaP256,
108  .key_domain = kOwnerAppDomainDev,
109  .key_diversifier = {0},
110  .usage_constraint = 0,
111  .data =
112  {
113  .ecdsa = APP_DEV_ECDSA_P256,
114  },
115  };
116 
117  app = (owner_application_key_t *)((uintptr_t)app + app->header.length);
118  *app = (owner_application_key_t){
119  .header =
120  {
121  .tag = kTlvTagApplicationKey,
122  .length = kTlvLenApplicationKeyEcdsa,
123  },
124  .key_alg = kOwnershipKeyAlgEcdsaP256,
125  .key_domain = kOwnerAppDomainProd,
126  .key_diversifier = {0},
127  .usage_constraint = 0,
128  .data =
129  {
130  .ecdsa = APP_PROD_ECDSA_P256,
131  },
132  };
133 
134  // Fill the remainder of the data segment with the end tag (0x5a5a5a5a).
135  app = (owner_application_key_t *)((uintptr_t)app + app->header.length);
136  size_t len = (uintptr_t)(owner_page[0].data + sizeof(owner_page[0].data)) -
137  (uintptr_t)app;
138  memset(app, 0x5a, len);
139 
140  ownership_seal_page(/*page=*/0);
141  memcpy(&owner_page[1], &owner_page[0], sizeof(owner_page[0]));
142 
143  // Since this module should only get linked in to FPGA builds, we can simply
144  // thunk the ownership state to LockedOwner.
145  bootdata->ownership_state = kOwnershipStateLockedOwner;
146 
147  // Write the configuration to both owner pages.
148  OT_DISCARD(flash_ctrl_info_erase(&kFlashCtrlInfoPageOwnerSlot0,
149  kFlashCtrlEraseTypePage));
150  OT_DISCARD(flash_ctrl_info_write(&kFlashCtrlInfoPageOwnerSlot0, 0,
151  sizeof(owner_page[0]) / sizeof(uint32_t),
152  &owner_page[0]));
153  owner_page_valid[0] = kOwnerPageStatusSealed;
154 
155  OT_DISCARD(boot_data_write(bootdata));
156  dbg_printf("sku_creator_owner_init: saved to flash\r\n");
157  return kErrorOk;
158 }