Software APIs
sigverify_otp_keys.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/rom/sigverify_otp_keys.h"
6 
7 #include "sw/device/silicon_creator/lib/drivers/hmac.h"
8 #include "sw/device/silicon_creator/lib/drivers/otp.h"
9 #include "sw/device/silicon_creator/lib/drivers/rnd.h"
10 #include "sw/device/silicon_creator/lib/error.h"
11 
12 #include "otp_ctrl_regs.h"
13 
14 enum {
15  // The size of the `ROT_CREATOR_AUTH_CODESIGN` partition ignoring the size of
16  // the partition digest.
17  kAuthCodesignParitionSize =
18  OTP_CTRL_PARAM_ROT_CREATOR_AUTH_CODESIGN_SIZE -
19  OTP_CTRL_PARAM_ROT_CREATOR_AUTH_CODESIGN_DIGEST_SIZE,
20 
21  kAuthCodesignParitionSizeInWords =
22  kAuthCodesignParitionSize / sizeof(uint32_t),
23 
24  // The size of the `ROT_CREATOR_AUTH_CODESIGN` region used to store the key
25  // material. This is the size of the partition minus the size of the HMAC
26  // digest used to measure the integrity of the keys.
27  kAuthcodesignPartitionMsgSize =
28  kAuthCodesignParitionSize - sizeof(hmac_digest_t),
29 
30  kAuthcodesignPartitionMsgSizeInWords =
31  kAuthcodesignPartitionMsgSize / sizeof(uint32_t),
32 
33  // The size of the `ROT_CREATOR_AUTH_STATE` partition ignoring the size of the
34  // partition digest.
35  kAuthStatePartitionSize = OTP_CTRL_PARAM_ROT_CREATOR_AUTH_STATE_SIZE -
36  OTP_CTRL_PARAM_ROT_CREATOR_AUTH_STATE_DIGEST_SIZE,
37 
38  kAuthStatePartitionSizeInWords = kAuthStatePartitionSize / sizeof(uint32_t),
39 };
40 
41 static_assert(sizeof(sigverify_otp_keys_t) == kAuthCodesignParitionSize,
42  "Size of sigverify_otp_keys_t must match the size of the OTP "
43  "partition");
44 static_assert(
45  sizeof(sigverify_otp_key_states_t) == kAuthStatePartitionSize,
46  "Size of sigverify_otp_key_states_t must match the size of the OTP "
47  "partition");
48 
49 /**
50  * Determines whether a key is valid in the RMA life cycle state.
51  *
52  * Only test and production keys that are valid in the RMA life cycle state.
53  *
54  * @param key_type Type of the key.
55  * @return The result of the operation.
56  */
58 static rom_error_t key_is_valid_in_lc_state_rma(sigverify_key_type_t key_type) {
59  switch (launder32(key_type)) {
60  case kSigverifyKeyTypeTest:
61  HARDENED_CHECK_EQ(key_type, kSigverifyKeyTypeTest);
62  return kErrorOk;
63  case kSigverifyKeyTypeProd:
64  HARDENED_CHECK_EQ(key_type, kSigverifyKeyTypeProd);
65  return kErrorOk;
66  case kSigverifyKeyTypeDev:
67  HARDENED_CHECK_EQ(key_type, kSigverifyKeyTypeDev);
68  return kErrorSigverifyBadKey;
69  default:
70  HARDENED_TRAP();
72  }
73 }
74 
75 /**
76  * Determines whether a key is valid in the DEV life cycle state.
77  *
78  * Only production and development keys are valid in the DEV life cycle state.
79  *
80  * @param key_type Type of the key.
81  * @return The result of the operation.
82  */
84 static rom_error_t key_is_valid_in_lc_state_dev(sigverify_key_type_t key_type) {
85  switch (launder32(key_type)) {
86  case kSigverifyKeyTypeTest:
87  HARDENED_CHECK_EQ(key_type, kSigverifyKeyTypeTest);
88  return kErrorSigverifyBadKey;
89  case kSigverifyKeyTypeProd:
90  HARDENED_CHECK_EQ(key_type, kSigverifyKeyTypeProd);
91  return kErrorOk;
92  case kSigverifyKeyTypeDev:
93  HARDENED_CHECK_EQ(key_type, kSigverifyKeyTypeDev);
94  return kErrorOk;
95  default:
96  HARDENED_TRAP();
98  }
99 }
100 
101 /**
102  * Determines whether a key is valid in PROD and PROD_END life cycle states.
103  *
104  * Only production keys are valid in PROD and PROD_END life cycle states.
105  *
106  * @param key_type Type of the key.
107  * @return The result of the operation.
108  */
110 static rom_error_t key_is_valid_in_lc_state_prod(
111  sigverify_key_type_t key_type) {
112  switch (launder32(key_type)) {
113  case kSigverifyKeyTypeTest:
114  HARDENED_CHECK_EQ(key_type, kSigverifyKeyTypeTest);
115  return kErrorSigverifyBadKey;
116  case kSigverifyKeyTypeProd:
117  HARDENED_CHECK_EQ(key_type, kSigverifyKeyTypeProd);
118  return kErrorOk;
119  case kSigverifyKeyTypeDev:
120  HARDENED_CHECK_EQ(key_type, kSigverifyKeyTypeDev);
121  return kErrorSigverifyBadKey;
122  default:
123  HARDENED_TRAP();
124  OT_UNREACHABLE();
125  }
126 }
127 
128 /**
129  * Determines whether a key is valid in TEST_UNLOCKED_* life cycle states.
130  *
131  * Only test and production keys are valid in TEST_UNLOCKED_* states.
132  *
133  * @param key_type Type of the key.
134  * @return The result of the operation.
135  */
137 static rom_error_t key_is_valid_in_lc_state_test(
138  sigverify_key_type_t key_type) {
139  switch (launder32(key_type)) {
140  case kSigverifyKeyTypeTest:
141  HARDENED_CHECK_EQ(key_type, kSigverifyKeyTypeTest);
142  return kErrorOk;
143  case kSigverifyKeyTypeProd:
144  HARDENED_CHECK_EQ(key_type, kSigverifyKeyTypeProd);
145  return kErrorOk;
146  case kSigverifyKeyTypeDev:
147  HARDENED_CHECK_EQ(key_type, kSigverifyKeyTypeDev);
148  return kErrorSigverifyBadKey;
149  default:
150  HARDENED_TRAP();
151  OT_UNREACHABLE();
152  }
153 }
154 
155 /**
156  * Determines whether a given key is valid in the given life cycle state.
157  *
158  * @param key_type Type of the key.
159  * @param lc_state Life cycle state of the device.
160  * @return The result of the operation.
161  */
163 static rom_error_t key_is_valid(sigverify_key_type_t key_type,
164  lifecycle_state_t lc_state) {
165  switch (launder32(lc_state)) {
166  case kLcStateTest:
167  HARDENED_CHECK_EQ(lc_state, kLcStateTest);
168  return key_is_valid_in_lc_state_test(key_type);
169  case kLcStateProd:
170  HARDENED_CHECK_EQ(lc_state, kLcStateProd);
171  return key_is_valid_in_lc_state_prod(key_type);
172  case kLcStateProdEnd:
173  HARDENED_CHECK_EQ(lc_state, kLcStateProdEnd);
174  return key_is_valid_in_lc_state_prod(key_type);
175  case kLcStateDev:
176  HARDENED_CHECK_EQ(lc_state, kLcStateDev);
177  return key_is_valid_in_lc_state_dev(key_type);
178  case kLcStateRma:
179  HARDENED_CHECK_EQ(lc_state, kLcStateRma);
180  return key_is_valid_in_lc_state_rma(key_type);
181  default:
182  HARDENED_TRAP();
183  OT_UNREACHABLE();
184  }
185 }
186 
187 rom_error_t sigverify_otp_keys_init(sigverify_otp_key_ctx_t *ctx) {
188  uint32_t *raw_buffer = (uint32_t *)&ctx->keys;
189  size_t i;
190  for (i = 0; launder32(i) < kAuthCodesignParitionSizeInWords; ++i) {
191  raw_buffer[i] = otp_read32(OTP_CTRL_PARAM_ROT_CREATOR_AUTH_CODESIGN_OFFSET +
192  i * sizeof(uint32_t));
193  }
194  HARDENED_CHECK_EQ(i, kAuthCodesignParitionSizeInWords);
195 
196  uint32_t *raw_state = (uint32_t *)&ctx->states;
197  for (i = 0; launder32(i) < kAuthStatePartitionSizeInWords; ++i) {
198  raw_state[i] = otp_read32(OTP_CTRL_PARAM_ROT_CREATOR_AUTH_STATE_OFFSET +
199  i * sizeof(uint32_t));
200  }
201  HARDENED_CHECK_EQ(i, kAuthStatePartitionSizeInWords);
202  return sigverify_otp_keys_check(ctx);
203 }
204 
205 rom_error_t sigverify_otp_keys_check(sigverify_otp_key_ctx_t *ctx) {
206  hmac_digest_t got;
207  hmac_sha256(&ctx->keys, kAuthcodesignPartitionMsgSize, &got);
208  size_t i = 0;
209  for (; launder32(i) < kHmacDigestNumWords; ++i) {
210  if (got.digest[i] != ctx->keys.integrity_measurement.digest[i]) {
211  return kErrorSigverifyBadAuthPartition;
212  }
213  }
214  HARDENED_CHECK_EQ(i, kHmacDigestNumWords);
215  return kErrorOk;
216 }
217 
218 /**
219  * Utility function to get a key entry from any array.
220  *
221  * @param array An array.
222  * @param entry_size Size of each entry in `array`.
223  * @param entry_index Index of the entry to get.
224  * @return Requested entry.
225  */
227 static inline const sigverify_rom_key_header_t *array_get_generic(
228  const sigverify_rom_key_header_t *array, size_t entry_size,
229  size_t entry_index) {
230  return (const sigverify_rom_key_header_t *)((const char *)array +
231  entry_size * entry_index);
232 }
233 
234 rom_error_t sigverify_otp_keys_get(sigverify_otp_keys_get_params_t params,
235  const sigverify_rom_key_header_t **key) {
236  size_t cand_key_index = UINT32_MAX;
237 
238  // Randomize the start index to avoid always picking the first key. A
239  // potential attacker will have a hardtime predicting the timing in which the
240  // key will be selected.
241  size_t i = ((uint64_t)rnd_uint32() * (uint64_t)params.key_cnt) >> 32;
242 
243  // Use forward and backwards iteration counters to ensure that the loop was
244  // executed exactly `params.key_cnt` times. This is to prevent faults causing
245  // the loop to skip inner iterations.
246  size_t iter_cnt = 0, r_iter_cnt = params.key_cnt - 1;
247  for (; launder32(iter_cnt) < params.key_cnt &&
248  launder32(r_iter_cnt) < params.key_cnt;
249  ++iter_cnt, --r_iter_cnt) {
250  const sigverify_rom_key_header_t *k =
251  array_get_generic(params.key_array, params.key_size, i);
252  if (k->key_id == params.key_id) {
253  HARDENED_CHECK_EQ(k->key_id, params.key_id);
254  if (params.key_states[i] == kSigVerifyKeyAuthStateProvisioned) {
255  rom_error_t error = key_is_valid(k->key_type, params.lc_state);
256  if (launder32(error) == kErrorOk) {
257  HARDENED_CHECK_EQ(error, kErrorOk);
258  // Store the index of the valid key rather than returning early. This
259  // is to make it harder for an attacker to predict the timing of the
260  // function. This will also allow us to perform a redundant check to
261  // ensure that the key is valid.
262  cand_key_index = i;
263  }
264  }
265  }
266  i++;
267  if (launder32(i) >= params.key_cnt) {
268  i -= params.key_cnt;
269  }
270  HARDENED_CHECK_LT(i, params.key_cnt);
271  }
272  // Ensure that the loop was executed exactly `params.key_cnt` times.
273  HARDENED_CHECK_EQ(iter_cnt, params.key_cnt);
274  HARDENED_CHECK_EQ(r_iter_cnt, SIZE_MAX);
275 
276  // Verify the key a second time and only return it if it passes all checks.
277  // The hardened check macros create barriers in the code, causing the binary
278  // to perform the checks as written in the code (i.e. the checks, or their
279  // order, cannot be optimized out by the compiler). This is a security measure
280  // to ensure that the checks are performed as intended.
281  if (launder32(cand_key_index) < params.key_cnt) {
282  HARDENED_CHECK_LT(cand_key_index, params.key_cnt);
283  const sigverify_rom_key_header_t *cand_key =
284  array_get_generic(params.key_array, params.key_size, cand_key_index);
285  if (params.key_states[cand_key_index] ==
286  kSigVerifyKeyAuthStateProvisioned) {
287  rom_error_t error = key_is_valid(cand_key->key_type, params.lc_state);
288  HARDENED_CHECK_EQ(error, kErrorOk);
289  *key = cand_key;
290  return error;
291  }
292  }
293  return kErrorSigverifyBadKey;
294 }