Software APIs
ownership_key.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 "sw/device/silicon_creator/lib/ownership/ownership_key.h"
6 
9 #include "sw/device/silicon_creator/lib/drivers/flash_ctrl.h"
10 #include "sw/device/silicon_creator/lib/drivers/keymgr.h"
11 #include "sw/device/silicon_creator/lib/drivers/kmac.h"
12 #include "sw/device/silicon_creator/lib/ownership/ecdsa.h"
13 
14 // RAM copy of the owner INFO pages from flash.
15 extern owner_block_t owner_page[2];
16 
17 OT_WEAK const owner_key_t *const kNoOwnerRecoveryKey;
18 
19 hardened_bool_t ownership_key_validate(size_t page, ownership_key_t key,
20  const owner_signature_t *signature,
21  const void *message, size_t len) {
22  if ((key & kOwnershipKeyUnlock) == kOwnershipKeyUnlock) {
23  if (ecdsa_verify_message(&owner_page[page].unlock_key.ecdsa,
24  &signature->ecdsa, message,
25  len) == kHardenedBoolTrue) {
26  return kHardenedBoolTrue;
27  }
28  }
29  if ((key & kOwnershipKeyActivate) == kOwnershipKeyActivate) {
30  if (ecdsa_verify_message(&owner_page[page].activate_key.ecdsa,
31  &signature->ecdsa, message,
32  len) == kHardenedBoolTrue) {
33  return kHardenedBoolTrue;
34  }
35  }
36  if (kNoOwnerRecoveryKey &&
37  (key & kOwnershipKeyRecovery) == kOwnershipKeyRecovery) {
38  if (ecdsa_verify_message(&kNoOwnerRecoveryKey->ecdsa, &signature->ecdsa,
39  message, len) == kHardenedBoolTrue) {
40  return kHardenedBoolTrue;
41  }
42  }
43  return ecdsa_verify_message(&owner_page[page].owner_key.ecdsa,
44  &signature->ecdsa, message, len);
45 }
46 
47 rom_error_t ownership_seal_init(void) {
48  const sc_keymgr_diversification_t diversifier = {
49  .salt = {4004, 8008, 8080, 1802, 6800, 6502, 6809, 8088},
50  .version = 0,
51  };
52  HARDENED_RETURN_IF_ERROR(sc_keymgr_generate_key(
53  kScKeymgrDestKmac, kScKeymgrKeyTypeSealing, diversifier));
54  HARDENED_RETURN_IF_ERROR(kmac_kmac256_hw_configure());
55  kmac_kmac256_set_prefix("Ownership", 9);
56  return kErrorOk;
57 }
58 
59 static rom_error_t seal_generate(const owner_block_t *page, uint32_t *seal) {
60  size_t sealed_len = offsetof(owner_block_t, seal);
61  HARDENED_RETURN_IF_ERROR(kmac_kmac256_start());
62  kmac_kmac256_absorb(page, sealed_len);
63  return kmac_kmac256_final(seal, ARRAYSIZE(page->seal));
64 }
65 
66 rom_error_t ownership_seal_page(size_t page) {
67  owner_block_t *data = &owner_page[page];
68  return seal_generate(data, data->seal);
69 }
70 
71 rom_error_t ownership_seal_check(size_t page) {
72  owner_block_t *data = &owner_page[page];
73  uint32_t check[ARRAYSIZE(data->seal)];
74  HARDENED_RETURN_IF_ERROR(seal_generate(data, check));
75  hardened_bool_t result =
76  hardened_memeq(data->seal, check, ARRAYSIZE(data->seal));
77  if (result == kHardenedBoolTrue) {
78  // Translate to kErrorOk. A cast is sufficient because kHardenedBoolTrue
79  // and kErrorOk have the same bit pattern.
80  return (rom_error_t)result;
81  }
82  return kErrorOwnershipInvalidInfoPage;
83 }
84 
85 static void reverse(void *buf, size_t len) {
86  char *x = (char *)buf;
87  char *y = x + len - 1;
88  for (; x < y; ++x, --y) {
89  char t = *x;
90  *x = *y;
91  *y = t;
92  }
93 }
94 
95 static void secret_page_enable(multi_bit_bool_t read, multi_bit_bool_t write) {
96  flash_ctrl_perms_t perm = {
97  .read = read,
98  .write = write,
99  .erase = write,
100  };
101  flash_ctrl_info_perms_set(&kFlashCtrlInfoPageOwnerSecret, perm);
102 }
103 
104 rom_error_t ownership_secret_new(void) {
105  owner_secret_page_t secret;
106 
107  secret_page_enable(/*read=*/kMultiBitBool4True, /*write=*/kMultiBitBool4True);
108  rom_error_t error =
109  flash_ctrl_info_read(&kFlashCtrlInfoPageOwnerSecret, 0,
110  sizeof(secret) / sizeof(uint32_t), &secret);
111  if (error != kErrorOk) {
112  HARDENED_CHECK_NE(error, kErrorOk);
113  // This should only happen on the FPGA during the first ownership transfer.
114  // TODO: What should we do if we ever encounter this error on silicon?
115  // A successful erase and reprogram will "heal" the chip, but any
116  // ownership history will be lost.
117  error = flash_ctrl_info_erase(&kFlashCtrlInfoPageOwnerSecret,
118  kFlashCtrlEraseTypePage);
119  memset(&secret, 0xFF, sizeof(secret));
120  }
121  if (error != kErrorOk)
122  goto exitproc;
123 
124  // Compute the ownership hash chain:
125  // owner_history = HASH(owner_history || new_owner_key)
126  hmac_sha256_init();
127  hmac_sha256_update(&secret.owner_history, sizeof(secret.owner_history));
128  size_t keysz = sizeof(owner_page[0].owner_key);
129  switch (owner_page[0].ownership_key_alg) {
130  case kOwnershipKeyAlgEcdsaP256:
131  keysz = sizeof(owner_page[0].owner_key.ecdsa);
132  break;
133  default:;
134  }
135  hmac_sha256_update(&owner_page[0].owner_key, keysz);
136  hmac_sha256_process();
137  hmac_sha256_final(&secret.owner_history);
138  // TODO(cfrantz): when merging to master, use the big-endian form of
139  // the sha256 function to avoid the reversal operation at the end.
140  reverse(&secret.owner_history, sizeof(secret.owner_history));
141 
142  // Generate a new owner secret seed. This will completely disconnect
143  // the keymgr state from the previous owner's keymgr state.
144  // We hash the previous owner entropy with the new owner key.
145  // owner_secret = HASH(owner_secret || new_owner_key)
146  // TODO: is this sufficient, or should we generate new entropy?
147  hmac_sha256_init();
148  hmac_sha256_update(&secret.owner_secret, sizeof(secret.owner_secret));
149  hmac_sha256_update(&owner_page[0].owner_key, keysz);
150  hmac_sha256_process();
151  hmac_sha256_final(&secret.owner_secret);
152 
153  error = flash_ctrl_info_erase(&kFlashCtrlInfoPageOwnerSecret,
154  kFlashCtrlEraseTypePage);
155  if (error != kErrorOk)
156  goto exitproc;
157  error = flash_ctrl_info_write(&kFlashCtrlInfoPageOwnerSecret, 0,
158  sizeof(secret) / sizeof(uint32_t), &secret);
159 
160 exitproc:
161  secret_page_enable(/*read=*/kMultiBitBool4False,
162  /*write=*/kMultiBitBool4False);
163  return error;
164 }
165 
166 rom_error_t ownership_history_get(hmac_digest_t *history) {
167  secret_page_enable(/*read=*/kMultiBitBool4True,
168  /*write=*/kMultiBitBool4False);
169  rom_error_t error =
170  flash_ctrl_info_read(&kFlashCtrlInfoPageOwnerSecret,
171  offsetof(owner_secret_page_t, owner_history),
172  sizeof(*history) / sizeof(uint32_t), history);
173  secret_page_enable(/*read=*/kMultiBitBool4False,
174  /*write=*/kMultiBitBool4False);
175  return error;
176 }