Software APIs
entropy.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/entropy.h"
6 
11 #include "sw/device/lib/base/multibits.h"
12 #include "sw/device/lib/crypto/impl/status.h"
13 
14 #include "csrng_regs.h" // Generated
15 #include "edn_regs.h" // Generated
16 #include "entropy_src_regs.h" // Generated
18 
19 // Module ID for status codes.
20 #define MODULE_ID MAKE_MODULE_ID('d', 'e', 'n')
21 
22 const entropy_seed_material_t kEntropyEmptySeed = {
23  .len = 0,
24  .data = {0},
25 };
26 
27 enum {
28  kBaseCsrng = TOP_EARLGREY_CSRNG_BASE_ADDR,
29  kBaseEntropySrc = TOP_EARLGREY_ENTROPY_SRC_BASE_ADDR,
30  kBaseEdn0 = TOP_EARLGREY_EDN0_BASE_ADDR,
31  kBaseEdn1 = TOP_EARLGREY_EDN1_BASE_ADDR,
32 
33  /**
34  * CSRNG genbits buffer size in uint32_t words.
35  */
36  kEntropyCsrngBitsBufferNumWords = 4,
37 };
38 
39 /**
40  * Supported CSRNG application commands.
41  * See https://docs.opentitan.org/hw/ip/csrng/doc/#command-header for
42  * details.
43  */
44 // TODO(#14542): Harden csrng/edn command fields.
45 typedef enum entropy_csrng_op {
46  kEntropyDrbgOpInstantiate = 1,
47  kEntropyDrbgOpReseed = 2,
48  kEntropyDrbgOpGenerate = 3,
49  kEntropyDrbgOpUpdate = 4,
50  kEntropyDrbgOpUninstantiate = 5,
51 } entropy_csrng_op_t;
52 
53 /**
54  * CSRNG application interface command header parameters.
55  */
56 typedef struct entropy_csrng_cmd {
57  /**
58  * Application command ID.
59  */
60  entropy_csrng_op_t id;
61  /**
62  * Entropy source enable.
63  *
64  * Mapped to flag0 in the hardware command interface.
65  */
67  const entropy_seed_material_t *seed_material;
68  /**
69  * Generate length. Specified as number of 128bit blocks.
70  */
71  uint32_t generate_len;
73 
74 /**
75  * Entropy complex configuration modes.
76  *
77  * Each enum value is used a confiugration index in `kEntropyComplexConfigs`.
78  */
79 typedef enum entropy_complex_config_id {
80  /**
81  * Entropy complex in continuous mode. This is the default runtime
82  * configuration.
83  */
84  kEntropyComplexConfigIdContinuous,
85  kEntropyComplexConfigIdNumEntries,
86 } entropy_complex_config_id_t;
87 
88 /**
89  * EDN configuration settings.
90  */
91 typedef struct edn_config {
92  /**
93  * Base address of the EDN block.
94  */
95  uint32_t base_address;
96  /**
97  * Number of generate calls between reseed commands.
98  */
99  uint32_t reseed_interval;
100  /**
101  * Downstream CSRNG instantiate command configuration.
102  */
104  /**
105  * Downstream CSRNG generate command configuration.
106  */
108  /**
109  * Downstream CSRNG reseed command configuration.
110  */
112 } edn_config_t;
113 
114 /**
115  * Entropy source configuration settings.
116  */
117 typedef struct entropy_src_config {
118  /**
119  * If set, FIPS compliant entropy will be generated by this module after being
120  * processed by an SP 800-90B compliant conditioning function.
121  */
122  multi_bit_bool_t fips_enable;
123  /**
124  * If set, the produced output entropy is marked as FIPS compliant
125  * through the FIPS bit being set to high.
126  */
127  multi_bit_bool_t fips_flag;
128  /**
129  * If set, the noise source is instructed to produce high quality entropy.
130  */
131  multi_bit_bool_t rng_fips;
132  /**
133  * If set, entropy will be routed to a firmware-visible register instead of
134  * being distributed to other hardware IPs.
135  */
136  multi_bit_bool_t route_to_firmware;
137  /**
138  * If set, raw entropy will be sent to CSRNG, bypassing the conditioner block
139  * and disabling the FIPS hardware generated flag.
140  */
141  multi_bit_bool_t bypass_conditioner;
142  /**
143  * Enables single bit entropy mode.
144  */
145  multi_bit_bool_t single_bit_mode;
146  /**
147  * The size of the window used for health tests.
148  */
150  /**
151  * The number of health test failures that must occur before an alert is
152  * triggered. When set to 0, alerts are disabled.
153  */
154  uint16_t alert_threshold;
155  /**
156  * Repetition count test threshold.
157  */
159  /**
160  * Repetition count symbol test threshold.
161  */
163  /**
164  * Adaptive proportion test high threshold.
165  */
167  /**
168  * Adaptive proportion test low threshold.
169  */
171  /**
172  * Bucket test threshold.
173  */
175  /**
176  * Markov test high threshold.
177  */
179  /**
180  * Markov test low threshold.
181  */
183  /**
184  * External health test high threshold.
185  */
187  /**
188  * External health test low threshold.
189  */
192 
193 /**
194  * Entropy complex configuration settings.
195  *
196  * Contains configuration paramenters for entropy_src, csrng, edn0 and edn1.
197  */
198 typedef struct entropy_complex_config {
199  /**
200  * Configuration identifier.
201  */
202  entropy_complex_config_id_t id;
203  /**
204  * ENTROPY_SRC configuration.
205  */
207  /**
208  * EDN0 configuration.
209  */
211  /**
212  * EDN1 configuration.
213  */
216 
217 // Entropy complex configuration table. This is expected to be fixed at build
218 // time. For this reason, it is not recommended to use this table in a ROM
219 // target unless the values are known to work. In other words, only use in
220 // mutable code partitions.
221 static const entropy_complex_config_t
222  kEntropyComplexConfigs[kEntropyComplexConfigIdNumEntries] = {
223  [kEntropyComplexConfigIdContinuous] =
224  {
225  .entropy_src =
226  {
227  .fips_enable = kMultiBitBool4True,
228  .fips_flag = kMultiBitBool4True,
229  .rng_fips = kMultiBitBool4True,
230  .route_to_firmware = kMultiBitBool4False,
231  .bypass_conditioner = kMultiBitBool4False,
232  .single_bit_mode = kMultiBitBool4False,
233  .fips_test_window_size = 0x200,
234  .alert_threshold = 2,
235  // TODO(#19392): Figure out appropriate thresholds.
236  .repcnt_threshold = 0xffff,
237  .repcnts_threshold = 0xffff,
238  .adaptp_hi_threshold = 0xffff,
239  .adaptp_lo_threshold = 0x0,
240  .bucket_threshold = 0xffff,
241  .markov_hi_threshold = 0xffff,
242  .markov_lo_threshold = 0x0,
243  .extht_hi_threshold = 0xffff,
244  .extht_lo_threshold = 0x0,
245  },
246  .edn0 =
247  {
248  .base_address = kBaseEdn0,
249  .reseed_interval = 128,
250  .instantiate =
251  {
252  .id = kEntropyDrbgOpInstantiate,
253  .disable_trng_input = kHardenedBoolFalse,
254  .seed_material = NULL,
255  .generate_len = 0,
256  },
257  .generate =
258  {
259  .id = kEntropyDrbgOpGenerate,
260  .disable_trng_input = kHardenedBoolFalse,
261  .seed_material = NULL,
262  .generate_len = 32,
263  },
264  .reseed =
265  {
266  .id = kEntropyDrbgOpReseed,
267  .disable_trng_input = kHardenedBoolFalse,
268  .seed_material = NULL,
269  .generate_len = 0,
270  },
271  },
272  .edn1 =
273  {
274  .base_address = kBaseEdn1,
275  .reseed_interval = 4,
276  .instantiate =
277  {
278  .id = kEntropyDrbgOpInstantiate,
279  .disable_trng_input = kHardenedBoolFalse,
280  .seed_material = NULL,
281  .generate_len = 0,
282  },
283  .generate =
284  {
285  .id = kEntropyDrbgOpGenerate,
286  .seed_material = NULL,
287  .generate_len = 4,
288  },
289  .reseed =
290  {
291  .id = kEntropyDrbgOpReseed,
292  .disable_trng_input = kHardenedBoolFalse,
293  .seed_material = NULL,
294  .generate_len = 0,
295  },
296  },
297  },
298 };
299 
300 // Write a CSRNG command to a register. That register can be the SW interface
301 // of CSRNG, in which case the `check_completion` argument should be `true`.
302 // That register can alternatively be one of EDN's that holds commands that EDN
303 // passes to CSRNG. In this case, the check_completion argument should only be
304 // true for non-generate commands issued to the SW register.
306 static status_t csrng_send_app_cmd(uint32_t base_address,
308  entropy_csrng_send_app_cmd_type_t cmd_type,
309  bool check_completion) {
310  enum {
311  // This is to maintain full compliance with NIST SP 800-90A, which requires
312  // the max generate output to be constrained to gen < 2 ^ 12 bits or 0x800
313  // 128-bit blocks.
314  kMaxGenerateSizeIn128BitBlocks = 0x800,
315  };
316  if (cmd.generate_len > kMaxGenerateSizeIn128BitBlocks) {
317  return OTCRYPTO_BAD_ARGS;
318  }
319 
320  uint32_t cmd_reg_addr;
321  uint32_t sts_reg_addr;
322  uint32_t rdy_bit_offset;
323  uint32_t reg_rdy_bit_offset;
324  uint32_t reg;
325  bool ready;
326 
327  switch (cmd_type) {
328  case kEntropyCsrngSendAppCmdTypeCsrng:
329  cmd_reg_addr = base_address + CSRNG_CMD_REQ_REG_OFFSET;
330  sts_reg_addr = base_address + CSRNG_SW_CMD_STS_REG_OFFSET;
331  rdy_bit_offset = CSRNG_SW_CMD_STS_CMD_RDY_BIT;
332  reg_rdy_bit_offset = CSRNG_SW_CMD_STS_CMD_RDY_BIT;
333  break;
334  case kEntropyCsrngSendAppCmdTypeEdnSw:
335  cmd_reg_addr = base_address + EDN_SW_CMD_REQ_REG_OFFSET;
336  sts_reg_addr = base_address + EDN_SW_CMD_STS_REG_OFFSET;
337  rdy_bit_offset = EDN_SW_CMD_STS_CMD_RDY_BIT;
338  reg_rdy_bit_offset = EDN_SW_CMD_STS_CMD_REG_RDY_BIT;
339  break;
340  case kEntropyCsrngSendAppCmdTypeEdnGen:
341  cmd_reg_addr = base_address + EDN_GENERATE_CMD_REG_OFFSET;
342  break;
343  case kEntropyCsrngSendAppCmdTypeEdnRes:
344  cmd_reg_addr = base_address + EDN_RESEED_CMD_REG_OFFSET;
345  break;
346  default:
347  return OTCRYPTO_BAD_ARGS;
348  }
349 
350  if ((cmd_type == kEntropyCsrngSendAppCmdTypeCsrng) ||
351  (cmd_type == kEntropyCsrngSendAppCmdTypeEdnSw)) {
352  // Wait for the status register to be ready to accept the next command.
353  do {
354  reg = abs_mmio_read32(sts_reg_addr);
355  ready = bitfield_bit32_read(reg, rdy_bit_offset);
356  } while (!ready);
357  }
358 
359 #define ENTROPY_CMD(m, i) ((bitfield_field32_t){.mask = m, .index = i})
360  // The application command header is not specified as a register in the
361  // hardware specification, so the fields are mapped here by hand. The
362  // command register also accepts arbitrary 32bit data.
363  static const bitfield_field32_t kAppCmdFieldFlag0 = ENTROPY_CMD(0xf, 8);
364  static const bitfield_field32_t kAppCmdFieldCmdId = ENTROPY_CMD(0xf, 0);
365  static const bitfield_field32_t kAppCmdFieldCmdLen = ENTROPY_CMD(0xf, 4);
366  static const bitfield_field32_t kAppCmdFieldGlen = ENTROPY_CMD(0x7ffff, 12);
367 #undef ENTROPY_CMD
368 
369  uint32_t cmd_len = cmd.seed_material == NULL ? 0 : cmd.seed_material->len;
370 
371  if (cmd_len & ~kAppCmdFieldCmdLen.mask) {
372  return OTCRYPTO_RECOV_ERR;
373  }
374 
375  // TODO: Consider removing this since the driver will be constructing these
376  // commands internally.
377  // Ensure the `seed_material` array is word-aligned, so it can be loaded to a
378  // CPU register with natively aligned loads.
379  if (cmd.seed_material != NULL &&
380  misalignment32_of((uintptr_t)cmd.seed_material->data) != 0) {
381  return OTCRYPTO_RECOV_ERR;
382  }
383 
384  if (check_completion && (cmd_type == kEntropyCsrngSendAppCmdTypeCsrng)) {
385  // Clear the `cs_cmd_req_done` bit, which is asserted whenever a command
386  // request is completed, because that bit will be used below to determine if
387  // this command request is completed. EDN automatically clears the
388  // acknowledgement bit upon writing the command.
389  reg = bitfield_bit32_write(0, CSRNG_INTR_STATE_CS_CMD_REQ_DONE_BIT, true);
390  abs_mmio_write32(kBaseCsrng + CSRNG_INTR_STATE_REG_OFFSET, reg);
391  }
392 
393  // Build and write application command header.
394  reg = bitfield_field32_write(0, kAppCmdFieldCmdId, cmd.id);
395  reg = bitfield_field32_write(reg, kAppCmdFieldCmdLen, cmd_len);
396  reg = bitfield_field32_write(reg, kAppCmdFieldGlen, cmd.generate_len);
397  reg = bitfield_field32_write(reg, kAppCmdFieldFlag0, kMultiBitBool4False);
398 
399  if (launder32(cmd.disable_trng_input) == kHardenedBoolTrue) {
400  reg = bitfield_field32_write(reg, kAppCmdFieldFlag0, kMultiBitBool4True);
401  }
402 
403  abs_mmio_write32(cmd_reg_addr, reg);
404 
405  for (size_t i = 0; i < cmd_len; ++i) {
406  // Before writing each word of additional data, the command ready or command
407  // reg ready bit needs to be polled if the command is issued to CSRNG or the
408  // SW register of EDN, respectively.
409  if (cmd_type == kEntropyCsrngSendAppCmdTypeCsrng ||
410  cmd_type == kEntropyCsrngSendAppCmdTypeEdnSw) {
411  do {
412  reg = abs_mmio_read32(sts_reg_addr);
413  ready = bitfield_bit32_read(reg, reg_rdy_bit_offset);
414  } while (!ready);
415  }
416  abs_mmio_write32(cmd_reg_addr, cmd.seed_material->data[i]);
417  }
418 
419  if (check_completion && (cmd_type == kEntropyCsrngSendAppCmdTypeCsrng)) {
420  if (cmd.id == kEntropyDrbgOpGenerate) {
421  // The Generate command is complete only after all entropy bits have been
422  // consumed. Thus poll the register that indicates if entropy bits are
423  // available.
424  do {
425  reg = abs_mmio_read32(kBaseCsrng + CSRNG_GENBITS_VLD_REG_OFFSET);
426  } while (!bitfield_bit32_read(reg, CSRNG_GENBITS_VLD_GENBITS_VLD_BIT));
427 
428  } else {
429  // The non-Generate commands complete earlier, so poll the "command
430  // request done" interrupt bit. Once it is set, the "status" bit is
431  // updated.
432  do {
433  reg = abs_mmio_read32(kBaseCsrng + CSRNG_INTR_STATE_REG_OFFSET);
434  } while (!bitfield_bit32_read(reg, CSRNG_INTR_STATE_CS_CMD_REQ_DONE_BIT));
435 
436  // Check the "status" bit, which will be 0 unless there was an error.
437  reg = abs_mmio_read32(kBaseCsrng + CSRNG_SW_CMD_STS_REG_OFFSET);
438  if (bitfield_field32_read(reg, CSRNG_SW_CMD_STS_CMD_STS_FIELD)) {
439  return OTCRYPTO_RECOV_ERR;
440  }
441  }
442  }
443 
444  if (check_completion && (cmd_type == kEntropyCsrngSendAppCmdTypeEdnSw)) {
445  // Acknowledgements for generate commands are only sent after all the
446  // entropy is consumed. Thus the acknowledgement bit shall only be polled
447  // for non-generate commands.
448  if (cmd.id != kEntropyDrbgOpGenerate) {
449  do {
450  reg = abs_mmio_read32(sts_reg_addr);
451  } while (!bitfield_bit32_read(reg, EDN_SW_CMD_STS_CMD_ACK_BIT));
452 
453  // Check the "status" bit, which will be 0 unless there was an error.
454  if (bitfield_field32_read(reg, CSRNG_SW_CMD_STS_CMD_STS_FIELD)) {
455  return OTCRYPTO_RECOV_ERR;
456  }
457  }
458  }
459 
460  return OTCRYPTO_OK;
461 }
462 
463 /**
464  * Enables the CSRNG block with the SW application and internal state registers
465  * enabled, and FIPS flag forcing disabled.
466  */
467 static void csrng_configure(void) {
468  uint32_t reg =
469  bitfield_field32_write(0, CSRNG_CTRL_ENABLE_FIELD, kMultiBitBool4True);
470  reg = bitfield_field32_write(reg, CSRNG_CTRL_SW_APP_ENABLE_FIELD,
471  kMultiBitBool4True);
472  reg = bitfield_field32_write(reg, CSRNG_CTRL_READ_INT_STATE_FIELD,
473  kMultiBitBool4True);
474  reg = bitfield_field32_write(reg, CSRNG_CTRL_FIPS_FORCE_ENABLE_FIELD,
475  kMultiBitBool4False);
476  abs_mmio_write32(kBaseCsrng + CSRNG_CTRL_REG_OFFSET, reg);
477 }
478 
479 /**
480  * Stops a given EDN instance.
481  *
482  * It also resets the EDN CSRNG command buffer to avoid synchronization issues
483  * with the upstream CSRNG instance.
484  *
485  * @param edn_address The based address of the target EDN block.
486  */
487 static void edn_stop(uint32_t edn_address) {
488  // FIFO clear is only honored if edn is enabled. This is needed to avoid
489  // synchronization issues with the upstream CSRNG instance.
490  uint32_t reg = abs_mmio_read32(edn_address + EDN_CTRL_REG_OFFSET);
491  abs_mmio_write32(edn_address + EDN_CTRL_REG_OFFSET,
492  bitfield_field32_write(reg, EDN_CTRL_CMD_FIFO_RST_FIELD,
493  kMultiBitBool4True));
494 
495  // Disable EDN and restore the FIFO clear at the same time so that no rogue
496  // command can get in after the clear above.
497  abs_mmio_write32(edn_address + EDN_CTRL_REG_OFFSET, EDN_CTRL_REG_RESVAL);
498 }
499 
500 /**
501  * Blocks until EDN instance is ready to execute a new CSNRG command.
502  *
503  * @param edn_address EDN base address.
504  * @returns an error if the EDN error status bit is set.
505  */
507 static status_t edn_ready_block(uint32_t edn_address) {
508  uint32_t reg;
509  do {
510  reg = abs_mmio_read32(edn_address + EDN_SW_CMD_STS_REG_OFFSET);
511  } while (!bitfield_bit32_read(reg, EDN_SW_CMD_STS_CMD_RDY_BIT));
512 
513  if (bitfield_field32_read(reg, CSRNG_SW_CMD_STS_CMD_STS_FIELD)) {
514  return OTCRYPTO_RECOV_ERR;
515  }
516  return OTCRYPTO_OK;
517 }
518 
519 /**
520  * Configures EDN instance based on `config` options.
521  *
522  * @param config EDN configuration options.
523  * @returns error on failure.
524  */
526 static status_t edn_configure(const edn_config_t *config) {
527  HARDENED_TRY(csrng_send_app_cmd(config->base_address, config->reseed,
528  kEntropyCsrngSendAppCmdTypeEdnRes, false));
529  HARDENED_TRY(csrng_send_app_cmd(config->base_address, config->generate,
530  kEntropyCsrngSendAppCmdTypeEdnGen, false));
531  abs_mmio_write32(
532  config->base_address + EDN_MAX_NUM_REQS_BETWEEN_RESEEDS_REG_OFFSET,
533  config->reseed_interval);
534 
535  uint32_t reg =
536  bitfield_field32_write(0, EDN_CTRL_EDN_ENABLE_FIELD, kMultiBitBool4True);
537  reg = bitfield_field32_write(reg, EDN_CTRL_AUTO_REQ_MODE_FIELD,
538  kMultiBitBool4True);
539  abs_mmio_write32(config->base_address + EDN_CTRL_REG_OFFSET, reg);
540 
541  HARDENED_TRY(edn_ready_block(config->base_address));
542  HARDENED_TRY(csrng_send_app_cmd(config->base_address, config->instantiate,
543  kEntropyCsrngSendAppCmdTypeEdnSw, true));
544  return OTCRYPTO_OK;
545 }
546 
547 /**
548  * Stops the current mode of operation and disables the entropy_src module.
549  *
550  * All configuration registers are set to their reset values to avoid
551  * synchronization issues with internal FIFOs.
552  */
553 static void entropy_src_stop(void) {
554  abs_mmio_write32(kBaseEntropySrc + ENTROPY_SRC_MODULE_ENABLE_REG_OFFSET,
555  ENTROPY_SRC_MODULE_ENABLE_REG_RESVAL);
556 
557  // Set default values for other critical registers to avoid synchronization
558  // issues.
559  abs_mmio_write32(kBaseEntropySrc + ENTROPY_SRC_ENTROPY_CONTROL_REG_OFFSET,
560  ENTROPY_SRC_ENTROPY_CONTROL_REG_RESVAL);
561  abs_mmio_write32(kBaseEntropySrc + ENTROPY_SRC_CONF_REG_OFFSET,
562  ENTROPY_SRC_CONF_REG_RESVAL);
563  abs_mmio_write32(kBaseEntropySrc + ENTROPY_SRC_HEALTH_TEST_WINDOWS_REG_OFFSET,
564  ENTROPY_SRC_HEALTH_TEST_WINDOWS_REG_RESVAL);
565  abs_mmio_write32(kBaseEntropySrc + ENTROPY_SRC_ALERT_THRESHOLD_REG_OFFSET,
566  ENTROPY_SRC_ALERT_THRESHOLD_REG_RESVAL);
567 }
568 
569 /**
570  * Disables the entropy complex.
571  *
572  * The order of operations is important to avoid synchronization issues across
573  * blocks. For Example, EDN has FIFOs used to send commands to the downstream
574  * CSRNG instances. Such FIFOs are not cleared when EDN is reconfigured, and an
575  * explicit clear FIFO command needs to be set by software (see #14506). There
576  * may be additional race conditions for downstream blocks that are
577  * processing requests from an upstream endpoint (e.g. entropy_src processing a
578  * request from CSRNG, or CSRNG processing a request from EDN). To avoid these
579  * issues, it is recommended to first disable EDN, then CSRNG and entropy_src
580  * last.
581  *
582  * See hw/ip/csrng/doc/_index.md#module-enable-and-disable for more details.
583  */
584 static void entropy_complex_stop_all(void) {
585  edn_stop(kBaseEdn0);
586  edn_stop(kBaseEdn1);
587  abs_mmio_write32(kBaseCsrng + CSRNG_CTRL_REG_OFFSET, CSRNG_CTRL_REG_RESVAL);
588  entropy_src_stop();
589 }
590 
591 /**
592  * Set the value of an entropy_src threshold register.
593  *
594  * Only sets the FIPS threshold value, not the bypass threshold field; for the
595  * bypass threshold we use the reset value, which is ignored if looser than the
596  * thresholds already set.
597  *
598  * @param name Name of register (e.g. REPCNT, BUCKET).
599  * @param value Value to set for the FIPS_THRESH field.
600  */
601 #define SET_FIPS_THRESH(name, value) \
602  abs_mmio_write32( \
603  kBaseEntropySrc + ENTROPY_SRC_##name##_THRESHOLDS_REG_OFFSET, \
604  bitfield_field32_write( \
605  ENTROPY_SRC_##name##_THRESHOLDS_REG_RESVAL, \
606  ENTROPY_SRC_##name##_THRESHOLDS_FIPS_THRESH_FIELD, value));
607 
608 /**
609  * Configures the entropy_src with based on `config` options.
610  *
611  * @param config Entropy Source configuration options.
612  * @return error on failure.
613  */
615 static status_t entropy_src_configure(const entropy_src_config_t *config) {
616  if (config->bypass_conditioner != kMultiBitBool4False) {
617  // Bypassing the conditioner is not supported.
618  return OTCRYPTO_BAD_ARGS;
619  }
620 
621  // Control register configuration.
622  uint32_t reg = bitfield_field32_write(
623  0, ENTROPY_SRC_ENTROPY_CONTROL_ES_ROUTE_FIELD, config->route_to_firmware);
624  reg = bitfield_field32_write(reg, ENTROPY_SRC_ENTROPY_CONTROL_ES_TYPE_FIELD,
625  config->bypass_conditioner);
626  abs_mmio_write32(kBaseEntropySrc + ENTROPY_SRC_ENTROPY_CONTROL_REG_OFFSET,
627  reg);
628 
629  // Config register configuration
630  reg = bitfield_field32_write(0, ENTROPY_SRC_CONF_FIPS_ENABLE_FIELD,
631  config->fips_enable);
632  reg = bitfield_field32_write(reg, ENTROPY_SRC_CONF_FIPS_FLAG_FIELD,
633  config->fips_flag);
634  reg = bitfield_field32_write(reg, ENTROPY_SRC_CONF_RNG_FIPS_FIELD,
635  config->rng_fips);
636  reg = bitfield_field32_write(reg,
637  ENTROPY_SRC_CONF_ENTROPY_DATA_REG_ENABLE_FIELD,
638  config->route_to_firmware);
639  reg = bitfield_field32_write(reg, ENTROPY_SRC_CONF_THRESHOLD_SCOPE_FIELD,
640  kMultiBitBool4False);
641  reg = bitfield_field32_write(reg, ENTROPY_SRC_CONF_RNG_BIT_ENABLE_FIELD,
642  config->single_bit_mode);
643  reg = bitfield_field32_write(reg, ENTROPY_SRC_CONF_RNG_BIT_SEL_FIELD, 0);
644  abs_mmio_write32(kBaseEntropySrc + ENTROPY_SRC_CONF_REG_OFFSET, reg);
645 
646  // Configure health test window. Conditioning bypass is not supported.
647  abs_mmio_write32(
648  kBaseEntropySrc + ENTROPY_SRC_HEALTH_TEST_WINDOWS_REG_OFFSET,
649  bitfield_field32_write(ENTROPY_SRC_HEALTH_TEST_WINDOWS_REG_RESVAL,
650  ENTROPY_SRC_HEALTH_TEST_WINDOWS_FIPS_WINDOW_FIELD,
651  config->fips_test_window_size));
652 
653  // Configure alert threshold
655  0, ENTROPY_SRC_ALERT_THRESHOLD_ALERT_THRESHOLD_FIELD,
656  config->alert_threshold);
658  reg, ENTROPY_SRC_ALERT_THRESHOLD_ALERT_THRESHOLD_INV_FIELD,
659  ~config->alert_threshold);
660  abs_mmio_write32(kBaseEntropySrc + ENTROPY_SRC_ALERT_THRESHOLD_REG_OFFSET,
661  reg);
662 
663  // Configure health test thresholds. Conditioning bypass is not supported.
664  SET_FIPS_THRESH(REPCNT, config->repcnt_threshold);
665  SET_FIPS_THRESH(REPCNTS, config->repcnts_threshold);
666  SET_FIPS_THRESH(ADAPTP_HI, config->adaptp_hi_threshold);
667  SET_FIPS_THRESH(ADAPTP_LO, config->adaptp_lo_threshold);
668  SET_FIPS_THRESH(BUCKET, config->bucket_threshold);
669  SET_FIPS_THRESH(MARKOV_HI, config->markov_hi_threshold);
670  SET_FIPS_THRESH(MARKOV_LO, config->markov_lo_threshold);
671  SET_FIPS_THRESH(EXTHT_HI, config->extht_hi_threshold);
672  SET_FIPS_THRESH(EXTHT_LO, config->extht_lo_threshold);
673 
674  // Enable entropy_src.
675  abs_mmio_write32(kBaseEntropySrc + ENTROPY_SRC_MODULE_ENABLE_REG_OFFSET,
676  kMultiBitBool4True);
677 
678  // TODO: Add FI checks.
679  return OTCRYPTO_OK;
680 }
681 
682 /**
683  * Verify the value of an entropy_src threshold register.
684  *
685  * Only checks the FIPS threshold value, not the bypass threshold field.
686  *
687  * @param name Name of register (e.g. REPCNT, BUCKET).
688  * @param exp Expected value of the FIPS_THRESH field.
689  */
690 #define VERIFY_FIPS_THRESH(name, exp) \
691  do { \
692  uint32_t reg = abs_mmio_read32( \
693  kBaseEntropySrc + ENTROPY_SRC_##name##_THRESHOLDS_REG_OFFSET); \
694  uint32_t act = bitfield_field32_read( \
695  reg, ENTROPY_SRC_##name##_THRESHOLDS_FIPS_THRESH_FIELD); \
696  if (act != exp) { \
697  return OTCRYPTO_RECOV_ERR; \
698  } \
699  } while (false);
700 
701 /**
702  * Check the entropy_src configuration.
703  *
704  * Verifies that the entropy_src block is enabled and running in a
705  * FIPS-compatible mode that forwards results to hardware. Checks the threshold
706  * register values against the configuration provided.
707  *
708  * @param config Entropy Source configuration options.
709  * @return error on failure.
710  */
712 static status_t entropy_src_check(const entropy_src_config_t *config) {
713  if (config->fips_enable != kMultiBitBool4True ||
714  config->bypass_conditioner != kMultiBitBool4False ||
715  config->route_to_firmware != kMultiBitBool4False) {
716  // This check only supports FIPS-compatible configurations which do not
717  // bypass the conditioner or route to firmware.
718  return OTCRYPTO_BAD_ARGS;
719  }
720 
721  // Check that entropy_src is enabled.
722  uint32_t reg =
723  abs_mmio_read32(kBaseEntropySrc + ENTROPY_SRC_MODULE_ENABLE_REG_OFFSET);
724  if (reg != kMultiBitBool4True) {
725  return OTCRYPTO_RECOV_ERR;
726  }
727 
728  // Check that entropy_src is running in a FIPS-enabled mode without bypassing
729  // the conditioner (es_type) and while making results available to hardware
730  // (es_route):
731  // 1. CONF.FIPS_ENABLE = true
732  // 2. CONF.RNG_BIT_ENABLE = false
733  // 3. CONTROL.ES_TYPE = false
734  // 3. CONTROL.ES_ROUTE = false
735  reg = abs_mmio_read32(kBaseEntropySrc + ENTROPY_SRC_CONF_REG_OFFSET);
736  uint32_t conf_fips_enable =
737  bitfield_field32_read(reg, ENTROPY_SRC_CONF_FIPS_ENABLE_FIELD);
738  uint32_t conf_rng_bit_enable =
739  bitfield_field32_read(reg, ENTROPY_SRC_CONF_RNG_BIT_ENABLE_FIELD);
740  if (conf_fips_enable != kMultiBitBool4True ||
741  conf_rng_bit_enable != kMultiBitBool4False) {
742  return OTCRYPTO_RECOV_ERR;
743  }
744  reg =
745  abs_mmio_read32(kBaseEntropySrc + ENTROPY_SRC_ENTROPY_CONTROL_REG_OFFSET);
746  uint32_t control_es_type =
747  bitfield_field32_read(reg, ENTROPY_SRC_ENTROPY_CONTROL_ES_TYPE_FIELD);
748  uint32_t control_es_route =
749  bitfield_field32_read(reg, ENTROPY_SRC_ENTROPY_CONTROL_ES_ROUTE_FIELD);
750  if (control_es_type != kMultiBitBool4False ||
751  control_es_route != kMultiBitBool4False) {
752  return OTCRYPTO_RECOV_ERR;
753  }
754 
755  // Check health test window register.
756  reg = abs_mmio_read32(kBaseEntropySrc +
757  ENTROPY_SRC_HEALTH_TEST_WINDOWS_REG_OFFSET);
759  reg, ENTROPY_SRC_HEALTH_TEST_WINDOWS_FIPS_WINDOW_FIELD) !=
760  config->fips_test_window_size) {
761  return OTCRYPTO_RECOV_ERR;
762  }
763 
764  // Check alert threshold.
765  uint32_t exp_reg = bitfield_field32_write(
766  0, ENTROPY_SRC_ALERT_THRESHOLD_ALERT_THRESHOLD_FIELD,
767  config->alert_threshold);
768  exp_reg = bitfield_field32_write(
769  exp_reg, ENTROPY_SRC_ALERT_THRESHOLD_ALERT_THRESHOLD_INV_FIELD,
770  ~(uint32_t)config->alert_threshold);
771  if (exp_reg != abs_mmio_read32(kBaseEntropySrc +
772  ENTROPY_SRC_ALERT_THRESHOLD_REG_OFFSET)) {
773  return OTCRYPTO_RECOV_ERR;
774  }
775 
776  // Check health test thresholds.
777  VERIFY_FIPS_THRESH(REPCNT, config->repcnt_threshold);
778  VERIFY_FIPS_THRESH(REPCNTS, config->repcnts_threshold);
779  VERIFY_FIPS_THRESH(ADAPTP_HI, config->adaptp_hi_threshold);
780  VERIFY_FIPS_THRESH(ADAPTP_LO, config->adaptp_lo_threshold);
781  VERIFY_FIPS_THRESH(BUCKET, config->bucket_threshold);
782  VERIFY_FIPS_THRESH(MARKOV_HI, config->markov_hi_threshold);
783  VERIFY_FIPS_THRESH(MARKOV_LO, config->markov_lo_threshold);
784  VERIFY_FIPS_THRESH(EXTHT_HI, config->extht_hi_threshold);
785  VERIFY_FIPS_THRESH(EXTHT_LO, config->extht_lo_threshold);
786 
787  // TODO: more FI checks on comparisons here.
788  return OTCRYPTO_OK;
789 }
790 
791 /**
792  * Check the CSRNG configuration.
793  *
794  * This check simply ensures that the CSRNG is enabled.
795  *
796  * @param config EDN configuration.
797  * @return error on failure.
798  */
800 static status_t csrng_check(void) {
801  uint32_t reg = abs_mmio_read32(kBaseCsrng + CSRNG_CTRL_REG_OFFSET);
802  uint32_t enable = bitfield_field32_read(reg, CSRNG_CTRL_ENABLE_FIELD);
803  if (enable == kMultiBitBool4True) {
804  return OTCRYPTO_OK;
805  }
806  return OTCRYPTO_RECOV_ERR;
807 }
808 
809 /**
810  * Check the EDN configuration.
811  *
812  * This check simply ensures that the EDN is enabled and running in auto_req
813  * mode.
814  *
815  * @param config EDN configuration.
816  * @return error on failure.
817  */
819 static status_t edn_check(const edn_config_t *config) {
820  uint32_t reg = abs_mmio_read32(config->base_address + EDN_CTRL_REG_OFFSET);
821  uint32_t edn_enable = bitfield_field32_read(reg, EDN_CTRL_EDN_ENABLE_FIELD);
822  uint32_t auto_req_mode =
823  bitfield_field32_read(reg, EDN_CTRL_AUTO_REQ_MODE_FIELD);
824  if (edn_enable == kMultiBitBool4True && auto_req_mode == kMultiBitBool4True) {
825  return OTCRYPTO_OK;
826  }
827  return OTCRYPTO_RECOV_ERR;
828 }
829 
830 status_t entropy_complex_init(void) {
831  entropy_complex_stop_all();
832 
833  const entropy_complex_config_t *config =
834  &kEntropyComplexConfigs[kEntropyComplexConfigIdContinuous];
835  if (launder32(config->id) != kEntropyComplexConfigIdContinuous) {
836  return OTCRYPTO_RECOV_ERR;
837  }
838 
839  HARDENED_TRY(entropy_src_configure(&config->entropy_src));
840  csrng_configure();
841  HARDENED_TRY(edn_configure(&config->edn0));
842  return edn_configure(&config->edn1);
843 }
844 
845 status_t entropy_complex_check(void) {
846  const entropy_complex_config_t *config =
847  &kEntropyComplexConfigs[kEntropyComplexConfigIdContinuous];
848  if (launder32(config->id) != kEntropyComplexConfigIdContinuous) {
849  return OTCRYPTO_RECOV_ERR;
850  }
851 
852  HARDENED_TRY(entropy_src_check(&config->entropy_src));
853  HARDENED_TRY(csrng_check());
854  HARDENED_TRY(edn_check(&config->edn0));
855  return edn_check(&config->edn1);
856 }
857 
858 status_t entropy_csrng_instantiate(
859  hardened_bool_t disable_trng_input,
860  const entropy_seed_material_t *seed_material) {
861  return csrng_send_app_cmd(kBaseCsrng,
863  .id = kEntropyDrbgOpInstantiate,
864  .disable_trng_input = disable_trng_input,
865  .seed_material = seed_material,
866  .generate_len = 0,
867  },
868  kEntropyCsrngSendAppCmdTypeCsrng, true);
869 }
870 
871 status_t entropy_csrng_reseed(hardened_bool_t disable_trng_input,
872  const entropy_seed_material_t *seed_material) {
873  return csrng_send_app_cmd(kBaseCsrng,
875  .id = kEntropyDrbgOpReseed,
876  .disable_trng_input = disable_trng_input,
877  .seed_material = seed_material,
878  .generate_len = 0,
879  },
880  kEntropyCsrngSendAppCmdTypeCsrng, true);
881 }
882 
883 status_t entropy_csrng_update(const entropy_seed_material_t *seed_material) {
884  return csrng_send_app_cmd(kBaseCsrng,
886  .id = kEntropyDrbgOpUpdate,
887  .seed_material = seed_material,
888  .generate_len = 0,
889  },
890  kEntropyCsrngSendAppCmdTypeCsrng, true);
891 }
892 
893 status_t entropy_csrng_generate_start(
894  const entropy_seed_material_t *seed_material, size_t len) {
895  // Round up the number of 128bit blocks. Aligning with respect to uint32_t.
896  // TODO(#6112): Consider using a canonical reference for alignment operations.
897  const uint32_t num_128bit_blocks = ceil_div(len, 4);
898  return csrng_send_app_cmd(kBaseCsrng,
900  .id = kEntropyDrbgOpGenerate,
901  .seed_material = seed_material,
902  .generate_len = num_128bit_blocks,
903  },
904  kEntropyCsrngSendAppCmdTypeCsrng, true);
905 }
906 
907 status_t entropy_csrng_generate_data_get(uint32_t *buf, size_t len,
908  hardened_bool_t fips_check) {
909  static_assert(kEntropyCsrngBitsBufferNumWords == 4,
910  "kEntropyCsrngBitsBufferNumWords must be 4.");
911  size_t nblocks = ceil_div(len, 4);
912  status_t res = OTCRYPTO_OK;
913  for (size_t block_idx = 0; block_idx < nblocks; ++block_idx) {
914  // Block until there is more data available in the genbits buffer. CSRNG
915  // generates data in 128bit chunks (i.e. 4 words).
916  uint32_t reg;
917  do {
918  reg = abs_mmio_read32(kBaseCsrng + CSRNG_GENBITS_VLD_REG_OFFSET);
919  } while (!bitfield_bit32_read(reg, CSRNG_GENBITS_VLD_GENBITS_VLD_BIT));
920 
921  if (fips_check != kHardenedBoolFalse &&
922  !bitfield_bit32_read(reg, CSRNG_GENBITS_VLD_GENBITS_FIPS_BIT)) {
923  // Entropy isn't FIPS-compatible, so we should return an error when
924  // done. However, we still need to read the result to clear CSRNG's FIFO.
925  res = OTCRYPTO_RECOV_ERR;
926  }
927 
928  // Read the full 128-bit block, in reverse word order to match known-answer
929  // tests. To clear the FIFO, we need to read all blocks generated by the
930  // request even if we don't use them.
931  for (size_t offset = 0; offset < kEntropyCsrngBitsBufferNumWords;
932  ++offset) {
933  uint32_t word = abs_mmio_read32(kBaseCsrng + CSRNG_GENBITS_REG_OFFSET);
934  size_t word_idx = (block_idx * kEntropyCsrngBitsBufferNumWords) +
935  kEntropyCsrngBitsBufferNumWords - 1 - offset;
936  if (word_idx < len) {
937  buf[word_idx] = word;
938  }
939  }
940  }
941 
942  return res;
943 }
944 
945 status_t entropy_csrng_generate(const entropy_seed_material_t *seed_material,
946  uint32_t *buf, size_t len,
947  hardened_bool_t fips_check) {
948  HARDENED_TRY(entropy_csrng_generate_start(seed_material, len));
949  return entropy_csrng_generate_data_get(buf, len, fips_check);
950 }
951 
952 status_t entropy_csrng_uninstantiate(void) {
953  return csrng_send_app_cmd(kBaseCsrng,
955  .id = kEntropyDrbgOpUninstantiate,
956  .seed_material = NULL,
957  .generate_len = 0,
958  },
959  kEntropyCsrngSendAppCmdTypeCsrng, true);
960 }