Software APIs
keymgr.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/lib/crypto/drivers/keymgr.h"
6 
10 #include "sw/device/lib/crypto/drivers/entropy.h"
11 #include "sw/device/lib/crypto/impl/status.h"
13 
15 #include "keymgr_regs.h"
16 
17 // Module ID for status codes.
18 #define MODULE_ID MAKE_MODULE_ID('d', 'k', 'r')
19 
20 enum {
22 };
23 static_assert(kKeymgrSaltNumWords == KEYMGR_SALT_MULTIREG_COUNT,
24  "Number of salt registers does not match.");
25 static_assert(kKeymgrOutputShareNumWords ==
26  KEYMGR_SW_SHARE0_OUTPUT_MULTIREG_COUNT,
27  "Number of output share 0 registers does not match.");
28 static_assert(kKeymgrOutputShareNumWords ==
29  KEYMGR_SW_SHARE1_OUTPUT_MULTIREG_COUNT,
30  "Number of output share 1 registers does not match.");
31 
32 /**
33  * Fails if the keymgr is not idle.
34  *
35  * @return OK if the key manager is idle, OTCRYPTO_RECOV_ERR otherwise.
36  */
38 static status_t keymgr_is_idle(void) {
39  uint32_t reg = abs_mmio_read32(kBaseAddr + KEYMGR_OP_STATUS_REG_OFFSET);
40  uint32_t status = bitfield_field32_read(reg, KEYMGR_OP_STATUS_STATUS_FIELD);
41  if (launder32(status) == KEYMGR_OP_STATUS_STATUS_VALUE_IDLE) {
42  HARDENED_CHECK_EQ(status, KEYMGR_OP_STATUS_STATUS_VALUE_IDLE);
43  return OTCRYPTO_OK;
44  }
45  return OTCRYPTO_RECOV_ERR;
46 }
47 
48 /**
49  * Set diversification input and start the key manager operation.
50  *
51  * Ensure the key manager is idle before calling this function.
52  *
53  * @param diversification Diversification input for the key derivation.
54  */
55 static void keymgr_start(keymgr_diversification_t diversification) {
56  // Set the version.
57  abs_mmio_write32(kBaseAddr + KEYMGR_KEY_VERSION_REG_OFFSET,
58  diversification.version);
59  // Set the salt.
60  for (size_t i = 0; i < kKeymgrSaltNumWords; i++) {
61  abs_mmio_write32(
62  kBaseAddr + KEYMGR_SALT_0_REG_OFFSET + (i * sizeof(uint32_t)),
63  diversification.salt[i]);
64  }
65 
66  // Issue the start command.
67  abs_mmio_write32(kBaseAddr + KEYMGR_START_REG_OFFSET,
68  1 << KEYMGR_START_EN_BIT);
69 }
70 
71 /**
72  * Wait for the key manager to finish an operation.
73  *
74  * Polls the key manager until it is no longer busy. If the operation completed
75  * successfully or the key manager was already idle, returns OTCRYPTO_OK. If
76  * there was an error during the operation, reads and clears the error code
77  * and returns OTCRYPTO_RECOV_ERR; the operation can be retried afterwards.
78  *
79  * @return OK or error.
80  */
82 static status_t keymgr_wait_until_done(void) {
83  // Poll the OP_STATUS register until it is something other than "WIP".
84  uint32_t reg;
85  uint32_t status;
86  do {
87  reg = abs_mmio_read32(kBaseAddr + KEYMGR_OP_STATUS_REG_OFFSET);
88  status = bitfield_field32_read(reg, KEYMGR_OP_STATUS_STATUS_FIELD);
89  } while (status == KEYMGR_OP_STATUS_STATUS_VALUE_WIP);
90 
91  // Clear OP_STATUS by writing back the value we read.
92  abs_mmio_write32(kBaseAddr + KEYMGR_OP_STATUS_REG_OFFSET, reg);
93 
94  // Check if the key manager reported errors. If it is already idle or
95  // completed an operation successfully, return an OK status. No other
96  // statuses (e.g. WIP) should be possible.
97  switch (status) {
98  case KEYMGR_OP_STATUS_STATUS_VALUE_IDLE:
99  return OTCRYPTO_OK;
100  case KEYMGR_OP_STATUS_STATUS_VALUE_DONE_SUCCESS:
101  return OTCRYPTO_OK;
102  case KEYMGR_OP_STATUS_STATUS_VALUE_DONE_ERROR: {
103  // Clear the ERR_CODE register before returning.
104  uint32_t err_code =
105  abs_mmio_read32(kBaseAddr + KEYMGR_ERR_CODE_REG_OFFSET);
106  abs_mmio_write32(kBaseAddr + KEYMGR_ERR_CODE_REG_OFFSET, err_code);
107  return OTCRYPTO_RECOV_ERR;
108  }
109  }
110 
111  // Should be unreachable.
112  HARDENED_TRAP();
113  return OTCRYPTO_FATAL_ERR;
114 }
115 
116 /**
117  * Set the control register of the key manager.
118  *
119  * The CDI select bit is always set to false for this driver (i.e. Sealing
120  * CDI). The driver does not support attestation CDI.
121  *
122  * @param dest (NONE, AES, OTBN, or KMAC)
123  * @param operation (GENERATE_SW or GENERATE_HW)
124  */
125 #define WRITE_CTRL(dest, operation) \
126  do { \
127  uint32_t ctrl = \
128  bitfield_field32_write(0, KEYMGR_CONTROL_SHADOWED_DEST_SEL_FIELD, \
129  KEYMGR_CONTROL_SHADOWED_DEST_SEL_VALUE_##dest); \
130  ctrl = bitfield_bit32_write(ctrl, KEYMGR_CONTROL_SHADOWED_CDI_SEL_BIT, \
131  false); \
132  ctrl = bitfield_field32_write( \
133  ctrl, KEYMGR_CONTROL_SHADOWED_OPERATION_FIELD, \
134  KEYMGR_CONTROL_SHADOWED_OPERATION_VALUE_##operation##_OUTPUT); \
135  abs_mmio_write32_shadowed(kBaseAddr + KEYMGR_CONTROL_SHADOWED_REG_OFFSET, \
136  ctrl); \
137  } while (false);
138 
139 status_t keymgr_generate_key_sw(keymgr_diversification_t diversification,
140  keymgr_output_t *key) {
141  // Ensure that the entropy complex has been initialized and keymgr is idle.
142  HARDENED_TRY(entropy_complex_check());
143  HARDENED_TRY(keymgr_is_idle());
144 
145  // Set the control register to generate a software-visible key.
146  WRITE_CTRL(NONE, GENERATE_SW);
147 
148  // Start the operation and wait for it to complete.
149  keymgr_start(diversification);
150  HARDENED_TRY(keymgr_wait_until_done());
151 
152  // Collect output.
153  // TODO: for SCA hardening, randomize the order of these reads.
154  for (size_t i = 0; i < kKeymgrOutputShareNumWords; i++) {
155  key->share0[i] =
156  abs_mmio_read32(kBaseAddr + KEYMGR_SW_SHARE0_OUTPUT_0_REG_OFFSET +
157  (i * sizeof(uint32_t)));
158  }
159  for (size_t i = 0; i < kKeymgrOutputShareNumWords; i++) {
160  key->share1[i] =
161  abs_mmio_read32(kBaseAddr + KEYMGR_SW_SHARE1_OUTPUT_0_REG_OFFSET +
162  (i * sizeof(uint32_t)));
163  }
164 
165  return OTCRYPTO_OK;
166 }
167 
168 status_t keymgr_generate_key_aes(keymgr_diversification_t diversification) {
169  // Ensure that the entropy complex has been initialized and keymgr is idle.
170  HARDENED_TRY(entropy_complex_check());
171  HARDENED_TRY(keymgr_is_idle());
172 
173  // Set the control register to generate an AES key.
174  WRITE_CTRL(AES, GENERATE_HW);
175 
176  // Start the operation and wait for it to complete.
177  keymgr_start(diversification);
178  return keymgr_wait_until_done();
179 }
180 
181 status_t keymgr_generate_key_kmac(keymgr_diversification_t diversification) {
182  // Ensure that the entropy complex has been initialized and keymgr is idle.
183  HARDENED_TRY(entropy_complex_check());
184  HARDENED_TRY(keymgr_is_idle());
185 
186  // Set the control register to generate a KMAC key.
187  WRITE_CTRL(KMAC, GENERATE_HW);
188 
189  // Start the operation and wait for it to complete.
190  keymgr_start(diversification);
191  return keymgr_wait_until_done();
192 }
193 
194 status_t keymgr_generate_key_otbn(keymgr_diversification_t diversification) {
195  // Ensure that the entropy complex has been initialized and keymgr is idle.
196  HARDENED_TRY(entropy_complex_check());
197  HARDENED_TRY(keymgr_is_idle());
198 
199  // Set the control register to generate an OTBN key.
200  WRITE_CTRL(OTBN, GENERATE_HW);
201 
202  // Start the operation and wait for it to complete.
203  keymgr_start(diversification);
204  return keymgr_wait_until_done();
205 }
206 
207 /**
208  * Clear the requested sideload slot.
209  *
210  * The `slot` parameter should be one of:
211  * - KEYMGR_SIDELOAD_CLEAR_VAL_VALUE_AES
212  * - KEYMGR_SIDELOAD_CLEAR_VAL_VALUE_KMAC
213  * - KEYMGR_SIDELOAD_CLEAR_VAL_VALUE_OTBN
214  *
215  * @param slot Value to write to the SIDELOAD_CLEAR register.
216  */
217 static status_t keymgr_sideload_clear(uint32_t slot) {
218  // Ensure that the entropy complex has been initialized and keymgr is idle.
219  HARDENED_TRY(entropy_complex_check());
220  HARDENED_TRY(keymgr_is_idle());
221 
222  // Set SIDELOAD_CLEAR to begin continuously clearing the requested slot.
223  abs_mmio_write32(
224  kBaseAddr + KEYMGR_SIDELOAD_CLEAR_REG_OFFSET,
225  bitfield_field32_write(0, KEYMGR_SIDELOAD_CLEAR_VAL_FIELD, slot));
226 
227  // Read back the value (hardening measure).
228  uint32_t sideload_clear =
229  abs_mmio_read32(kBaseAddr + KEYMGR_SIDELOAD_CLEAR_REG_OFFSET);
230  if (bitfield_field32_read(sideload_clear, KEYMGR_SIDELOAD_CLEAR_VAL_FIELD) !=
231  slot) {
232  return OTCRYPTO_FATAL_ERR;
233  }
234 
235  // Spin for 100 microseconds.
236  // TODO: this value seems to work for tests, but it would be good to run a
237  // more principled analysis.
238  busy_spin_micros(100);
239 
240  // Stop continuous clearing.
241  abs_mmio_write32(
242  kBaseAddr + KEYMGR_SIDELOAD_CLEAR_REG_OFFSET,
243  bitfield_field32_write(0, KEYMGR_SIDELOAD_CLEAR_VAL_FIELD,
244  KEYMGR_SIDELOAD_CLEAR_VAL_VALUE_NONE));
245 
246  return OTCRYPTO_OK;
247 }
248 
249 status_t keymgr_sideload_clear_aes(void) {
250  return keymgr_sideload_clear(KEYMGR_SIDELOAD_CLEAR_VAL_VALUE_AES);
251 }
252 
253 status_t keymgr_sideload_clear_kmac(void) {
254  return keymgr_sideload_clear(KEYMGR_SIDELOAD_CLEAR_VAL_VALUE_KMAC);
255 }
256 
257 status_t keymgr_sideload_clear_otbn(void) {
258  return keymgr_sideload_clear(KEYMGR_SIDELOAD_CLEAR_VAL_VALUE_OTBN);
259 }