Skip to content

Commit fce0466

Browse files
committed
[crypto/entropy] Set FIPS thresholds
Set the entropy source driver to align with certified NIST SP 800-90B requirements. Specific changes include: - NIST 800-90B Health Test Thresholds: Increased the `fips_test_window_size` to 2048 bits to comply with FIPS standards for binary noise sources. - Bypass Register Configuration: Updated the `SET_FIPS_THRESH` and `VERIFY_FIPS_THRESH` macros to write and verify both the `FIPS_THRESH` and `BYPASS_THRESH` fields simultaneously. Note: CSRNG `FIPS_FORCE_ENABLE` and EDN continuous polling rates remain at their defaults to ensure the FIFO does not run empty with, for exmaple, the OTBN during the initial TRNG FIPS warm-up phase. Signed-off-by: Siemen Dhooghe <sdhooghe@google.com>
1 parent 0898d6f commit fce0466

17 files changed

+142
-135
lines changed

sw/device/lib/crypto/drivers/entropy.c

Lines changed: 106 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ enum {
3636
kEntropyCsrngBitsBufferNumWords = 4,
3737

3838
// Fast timeout for checking if hardware is ready to accept a command word
39-
kEntropyPollReadyTimeout = 100,
39+
kEntropyPollReadyTimeout = 1000000,
4040
// Longer timeout for waiting for a command to finish executing
4141
kEntropyPollCmdDoneTimeout = 1000000,
4242
// Timeout for waiting for GenBits to become valid
@@ -228,80 +228,82 @@ typedef struct entropy_complex_config {
228228
static const entropy_complex_config_t
229229
kEntropyComplexConfigs[kEntropyComplexConfigIdNumEntries] = {
230230
[kEntropyComplexConfigIdContinuous] =
231-
{
232-
.entropy_src =
233-
{
234-
.fips_enable = kMultiBitBool4True,
235-
.fips_flag = kMultiBitBool4True,
236-
.rng_fips = kMultiBitBool4True,
237-
.route_to_firmware = kMultiBitBool4False,
238-
.bypass_conditioner = kMultiBitBool4False,
239-
.single_bit_mode = kMultiBitBool4False,
240-
.fips_test_window_size = 0x200,
241-
.alert_threshold = 2,
242-
// TODO(#19392): Figure out appropriate thresholds.
243-
.repcnt_threshold = 0xffff,
244-
.repcnts_threshold = 0xffff,
245-
.adaptp_hi_threshold = 0xffff,
246-
.adaptp_lo_threshold = 0x0,
247-
.bucket_threshold = 0xffff,
248-
.markov_hi_threshold = 0xffff,
249-
.markov_lo_threshold = 0x0,
250-
.extht_hi_threshold = 0xffff,
251-
.extht_lo_threshold = 0x0,
252-
},
253-
.edn0 =
254-
{
255-
.base_address = kBaseEdn0,
256-
.reseed_interval = 128,
257-
.instantiate =
258-
{
259-
.id = kEntropyDrbgOpInstantiate,
260-
.disable_trng_input = kHardenedBoolFalse,
261-
.seed_material = NULL,
262-
.generate_len = 0,
263-
},
264-
.generate =
265-
{
266-
.id = kEntropyDrbgOpGenerate,
267-
.disable_trng_input = kHardenedBoolFalse,
268-
.seed_material = NULL,
269-
.generate_len = 32,
270-
},
271-
.reseed =
272-
{
273-
.id = kEntropyDrbgOpReseed,
274-
.disable_trng_input = kHardenedBoolFalse,
275-
.seed_material = NULL,
276-
.generate_len = 0,
277-
},
278-
},
279-
.edn1 =
280-
{
281-
.base_address = kBaseEdn1,
282-
.reseed_interval = 4,
283-
.instantiate =
284-
{
285-
.id = kEntropyDrbgOpInstantiate,
286-
.disable_trng_input = kHardenedBoolFalse,
287-
.seed_material = NULL,
288-
.generate_len = 0,
289-
},
290-
.generate =
291-
{
292-
.id = kEntropyDrbgOpGenerate,
293-
.seed_material = NULL,
294-
.generate_len = 4,
295-
},
296-
.reseed =
297-
{
298-
.id = kEntropyDrbgOpReseed,
299-
.disable_trng_input = kHardenedBoolFalse,
300-
.seed_material = NULL,
301-
.generate_len = 0,
302-
},
303-
},
304-
},
231+
// All cut off values are calculated with the assumption that:
232+
// H=0.5 per bit => H=2 for 4-bit symbols
233+
// α = 2⁻⁴⁰ (alpha = 2^-40), false positive probability
234+
{
235+
.entropy_src =
236+
{
237+
.fips_enable = kMultiBitBool4True,
238+
.fips_flag = kMultiBitBool4True,
239+
.rng_fips = kMultiBitBool4True,
240+
.route_to_firmware = kMultiBitBool4False,
241+
.bypass_conditioner = kMultiBitBool4False,
242+
.single_bit_mode = kMultiBitBool4False,
243+
.fips_test_window_size = 2048,
244+
.alert_threshold = 4,
245+
.repcnt_threshold = 81,
246+
.repcnts_threshold = 21,
247+
.adaptp_hi_threshold = 1591,
248+
.adaptp_lo_threshold = 2048 - 1591, // 457
249+
.bucket_threshold = 201,
250+
.markov_hi_threshold = 824,
251+
.markov_lo_threshold = 1024 - 824, // 200
252+
.extht_hi_threshold = 0xffff,
253+
.extht_lo_threshold = 0x0,
254+
},
255+
.edn0 =
256+
{
257+
.base_address = kBaseEdn0,
258+
.reseed_interval = 128,
259+
.instantiate =
260+
{
261+
.id = kEntropyDrbgOpInstantiate,
262+
.disable_trng_input = kHardenedBoolFalse,
263+
.seed_material = NULL,
264+
.generate_len = 0,
265+
},
266+
.generate =
267+
{
268+
.id = kEntropyDrbgOpGenerate,
269+
.disable_trng_input = kHardenedBoolFalse,
270+
.seed_material = NULL,
271+
.generate_len = 32,
272+
},
273+
.reseed =
274+
{
275+
.id = kEntropyDrbgOpReseed,
276+
.disable_trng_input = kHardenedBoolFalse,
277+
.seed_material = NULL,
278+
.generate_len = 0,
279+
},
280+
},
281+
.edn1 =
282+
{
283+
.base_address = kBaseEdn1,
284+
.reseed_interval = 4,
285+
.instantiate =
286+
{
287+
.id = kEntropyDrbgOpInstantiate,
288+
.disable_trng_input = kHardenedBoolFalse,
289+
.seed_material = NULL,
290+
.generate_len = 0,
291+
},
292+
.generate =
293+
{
294+
.id = kEntropyDrbgOpGenerate,
295+
.seed_material = NULL,
296+
.generate_len = 4,
297+
},
298+
.reseed =
299+
{
300+
.id = kEntropyDrbgOpReseed,
301+
.disable_trng_input = kHardenedBoolFalse,
302+
.seed_material = NULL,
303+
.generate_len = 0,
304+
},
305+
},
306+
},
305307
};
306308

307309
// Write a CSRNG command to a register. That register can be the SW interface
@@ -464,9 +466,7 @@ static status_t csrng_send_app_cmd(uint32_t base_address,
464466
// The non-Generate commands complete earlier, so poll the "command
465467
// request done" interrupt bit. Once it is set, the "status" bit is
466468
// updated.
467-
uint32_t timeout = (cmd.id == kEntropyDrbgOpInstantiate)
468-
? kEntropyPollCmdDoneTimeout
469-
: kEntropyPollReadyTimeout;
469+
uint32_t timeout = kEntropyPollCmdDoneTimeout;
470470
do {
471471
reg = abs_mmio_read32(kBaseCsrng + CSRNG_INTR_STATE_REG_OFFSET);
472472
} while (
@@ -668,19 +668,19 @@ static void entropy_complex_stop_all(void) {
668668
/**
669669
* Set the value of an entropy_src threshold register.
670670
*
671-
* Only sets the FIPS threshold value, not the bypass threshold field; for the
672-
* bypass threshold we use the reset value, which is ignored if looser than the
673-
* thresholds already set.
671+
* Sets both the FIPS and BYPASS threshold fields to the same value.
674672
*
675673
* @param name Name of register (e.g. REPCNT, BUCKET).
676-
* @param value Value to set for the FIPS_THRESH field.
674+
* @param value Value to set for the FIPS_THRESH and BYPASS_THRESH fields.
677675
*/
678-
#define SET_FIPS_THRESH(name, value) \
679-
abs_mmio_write32( \
680-
kBaseEntropySrc + ENTROPY_SRC_##name##_THRESHOLDS_REG_OFFSET, \
681-
bitfield_field32_write( \
682-
ENTROPY_SRC_##name##_THRESHOLDS_REG_RESVAL, \
683-
ENTROPY_SRC_##name##_THRESHOLDS_FIPS_THRESH_FIELD, value));
676+
#define SET_FIPS_THRESH(name, value) \
677+
abs_mmio_write32( \
678+
kBaseEntropySrc + ENTROPY_SRC_##name##_THRESHOLDS_REG_OFFSET, \
679+
bitfield_field32_write( \
680+
bitfield_field32_write( \
681+
ENTROPY_SRC_##name##_THRESHOLDS_REG_RESVAL, \
682+
ENTROPY_SRC_##name##_THRESHOLDS_FIPS_THRESH_FIELD, value), \
683+
ENTROPY_SRC_##name##_THRESHOLDS_BYPASS_THRESH_FIELD, value));
684684

685685
/**
686686
* Configures the entropy_src with based on `config` options.
@@ -727,6 +727,10 @@ static status_t entropy_src_configure(const entropy_src_config_t *config) {
727727
bitfield_field32_write(ENTROPY_SRC_HEALTH_TEST_WINDOWS_REG_RESVAL,
728728
ENTROPY_SRC_HEALTH_TEST_WINDOWS_FIPS_WINDOW_FIELD,
729729
config->fips_test_window_size);
730+
health_test_windows = bitfield_field32_write(
731+
health_test_windows, ENTROPY_SRC_HEALTH_TEST_WINDOWS_BYPASS_WINDOW_FIELD,
732+
0x60);
733+
730734
abs_mmio_write32(kBaseEntropySrc + ENTROPY_SRC_HEALTH_TEST_WINDOWS_REG_OFFSET,
731735
health_test_windows);
732736

@@ -777,18 +781,20 @@ static status_t entropy_src_configure(const entropy_src_config_t *config) {
777781
/**
778782
* Verify the value of an entropy_src threshold register.
779783
*
780-
* Only checks the FIPS threshold value, not the bypass threshold field.
784+
* Checks both the FIPS and BYPASS threshold values.
781785
*
782786
* @param name Name of register (e.g. REPCNT, BUCKET).
783-
* @param exp Expected value of the FIPS_THRESH field.
787+
* @param exp Expected value of the FIPS_THRESH and BYPASS_THRESH fields.
784788
*/
785789
#define VERIFY_FIPS_THRESH(name, exp) \
786790
do { \
787791
uint32_t reg = abs_mmio_read32( \
788792
kBaseEntropySrc + ENTROPY_SRC_##name##_THRESHOLDS_REG_OFFSET); \
789-
uint32_t act = bitfield_field32_read( \
793+
uint32_t act_fips = bitfield_field32_read( \
790794
reg, ENTROPY_SRC_##name##_THRESHOLDS_FIPS_THRESH_FIELD); \
791-
if (act != exp) { \
795+
uint32_t act_bypass = bitfield_field32_read( \
796+
reg, ENTROPY_SRC_##name##_THRESHOLDS_BYPASS_THRESH_FIELD); \
797+
if (act_fips != exp || act_bypass != exp) { \
792798
return OTCRYPTO_RECOV_ERR; \
793799
} \
794800
} while (false);
@@ -847,12 +853,16 @@ static status_t entropy_src_check(const entropy_src_config_t *config) {
847853
return OTCRYPTO_RECOV_ERR;
848854
}
849855

850-
// Check health test window register.
856+
// Check health test window register for fips and bypass.
851857
reg = abs_mmio_read32(kBaseEntropySrc +
852858
ENTROPY_SRC_HEALTH_TEST_WINDOWS_REG_OFFSET);
853-
if (bitfield_field32_read(
854-
reg, ENTROPY_SRC_HEALTH_TEST_WINDOWS_FIPS_WINDOW_FIELD) !=
855-
config->fips_test_window_size) {
859+
uint32_t act_fips_window = bitfield_field32_read(
860+
reg, ENTROPY_SRC_HEALTH_TEST_WINDOWS_FIPS_WINDOW_FIELD);
861+
uint32_t act_bypass_window = bitfield_field32_read(
862+
reg, ENTROPY_SRC_HEALTH_TEST_WINDOWS_BYPASS_WINDOW_FIELD);
863+
864+
if (act_fips_window != config->fips_test_window_size ||
865+
act_bypass_window != 0x60) {
856866
return OTCRYPTO_RECOV_ERR;
857867
}
858868

0 commit comments

Comments
 (0)