summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/cr50/board.c52
-rw-r--r--board/cr50/board.h23
-rw-r--r--board/cr50/build.mk3
-rw-r--r--board/cr50/fips.c357
-rw-r--r--board/cr50/fips.h37
-rw-r--r--board/cr50/fips_cmd.c215
-rw-r--r--board/cr50/fips_rand.c2
-rw-r--r--board/cr50/wp.c14
-rw-r--r--include/config.h6
-rw-r--r--include/hooks.h6
10 files changed, 341 insertions, 374 deletions
diff --git a/board/cr50/board.c b/board/cr50/board.c
index 80ec7b623e..dfa05b8ef9 100644
--- a/board/cr50/board.c
+++ b/board/cr50/board.c
@@ -185,20 +185,6 @@ int board_get_ccd_rec_lid_pin(void)
return board_properties & BOARD_CCD_REC_LID_PIN_MASK;
}
-bool board_fips_power_up_done(void)
-{
- return !!(GREG32(PMU, PWRDN_SCRATCH22) == BOARD_FIPS_POWERUP_DONE);
-}
-
-/* Set status of FIPS power-up tests. */
-void board_set_fips_policy_test(bool asserted)
-{
- /* Enable writing to the long life register */
- if (asserted)
- GREG32(PMU, PWRDN_SCRATCH22) = BOARD_FIPS_POWERUP_DONE;
- else
- GREG32(PMU, PWRDN_SCRATCH22) = 0;
-}
/* Get header address of the backup RW copy. */
const struct SignedHeader *get_other_rw_addr(void)
@@ -1573,44 +1559,6 @@ static uint32_t get_properties(void)
return properties;
}
-/**
- * NVMEM variable name for FIPS config. This is complementary for FWMP policy
- * and used primarily for lab testing where FWMP would be complicated.
- */
-static const uint8_t k_fips_config = NVMEM_VAR_FIPS_CONFIG;
-void board_set_local_fips_policy(bool asserted)
-{
- setvar(&k_fips_config, sizeof(k_fips_config), (uint8_t *)&asserted,
- sizeof(asserted));
-}
-
-static bool board_get_local_fips_policy(void)
-{
- const struct tuple *t;
- bool fips;
-
- t = getvar(&k_fips_config, sizeof(k_fips_config));
- fips = (t) ? tuple_val(t)[0] : false;
- freevar(t);
-
- return fips;
-}
-
-bool board_fips_enforced(void)
-{
- /**
- * combined flag which caches fips state and the fact it was cached
- * bit 7 is set when bit 0 contains fips status
- */
- static uint8_t fips_state;
-
- if (!(fips_state & 128)) {
- fips_state = board_fwmp_fips_mode_enabled() ||
- board_get_local_fips_policy();
- fips_state |= 128;
- }
- return !!(fips_state & 1);
-}
static void init_board_properties(void)
{
diff --git a/board/cr50/board.h b/board/cr50/board.h
index 9519306be4..7a73753260 100644
--- a/board/cr50/board.h
+++ b/board/cr50/board.h
@@ -93,8 +93,10 @@
/* Also use the cr50 as a second factor authentication */
#define CONFIG_U2F
-#undef CONFIG_FIPS_RSA2048
-#undef CONFIG_FIPS_SW_HMAC_DRBG
+/* Additional FIPS KAT tests. */
+#define CONFIG_FIPS_RSA2048
+#define CONFIG_FIPS_SW_HMAC_DRBG
+#define CONFIG_FIPS_AES_CBC_256
/* USB configuration */
#define CONFIG_USB
@@ -252,7 +254,6 @@ enum nvmem_vars {
NVMEM_VAR_U2F_SALT,
NVMEM_VAR_CCD_CONFIG,
NVMEM_VAR_G2F_SALT,
- NVMEM_VAR_FIPS_CONFIG,
NVMEM_VARS_COUNT
};
@@ -330,16 +331,6 @@ int board_has_ec_cr50_comm_support(void);
int board_id_is_mismatched(void);
/* Allow for deep sleep to be enabled on AP shutdown */
int board_deep_sleep_allowed(void);
-/* indicates completion of power-up tests earlier */
-bool board_fips_power_up_done(void);
-
-/**
- * Set status of FIPS power-up tests on wake from sleep
- *
- * @param asserted: 0 power-up tests should run on resume, otherwise can be
- * skipped
- */
-void board_set_fips_policy_test(bool asserted);
void power_button_record(void);
@@ -365,12 +356,6 @@ void board_reboot_ec_deferred(int usec_delay);
void board_closed_loop_reset(void);
int board_wipe_tpm(int reset_required);
int board_is_first_factory_boot(void);
-int board_fwmp_fips_mode_enabled(void);
-
-/* set FIPS policy for board in NVRAM (independent of FWMP) */
-void board_set_local_fips_policy(bool asserted);
-/* return non zero if FIPS mode enforced in FWMP or NVRAM */
-bool board_fips_enforced(void);
int usb_i2c_board_enable(void);
void usb_i2c_board_disable(void);
diff --git a/board/cr50/build.mk b/board/cr50/build.mk
index 1656cf24c1..ed45ca2963 100644
--- a/board/cr50/build.mk
+++ b/board/cr50/build.mk
@@ -92,6 +92,9 @@ fips-${CONFIG_FIPS_UTIL} += dcrypto/util.o
custom-board-ro_objs-${CONFIG_FIPS_UTIL} = $(BDIR)/dcrypto/util.o
+# FIPS console and TPM2 commands are outside FIPS module
+board-y += fips_cmd.o
+
board-y += tpm2/NVMem.o
board-y += tpm2/aes.o
board-y += tpm2/ecc.o
diff --git a/board/cr50/fips.c b/board/cr50/fips.c
index 436e1588ae..9fd72d28c8 100644
--- a/board/cr50/fips.c
+++ b/board/cr50/fips.c
@@ -24,9 +24,6 @@
#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args)
-/* FIPS mode is temporarily disabled. */
-#define FIPS_MODE_ENABLED 0
-
/**
* Combined FIPS status & global FIPS error.
* default value is = FIPS_UNINITIALIZED
@@ -39,85 +36,18 @@ enum fips_status fips_status(void)
return _fips_status;
}
+#ifdef CRYPTO_TEST_SETUP
/* Flag to simulate specific error condition in power-up tests. */
uint8_t fips_break_cmd;
-
-void fips_set_status(enum fips_status status)
-{
- /**
- * if FIPS error took place, drop indication of FIPS approved mode.
- * Next cycle of sleep will power-cycle HW crypto components, so any
- * soft-errors will be recovered. In case of hard errors it
- * will be detected again.
- */
- /* accumulate status */
- _fips_status |= status;
-
- status = _fips_status;
- /* if we have error, require power up tests on resume */
- if (status & FIPS_ERROR_MASK)
- board_set_fips_policy_test(false);
-}
-
-bool fips_mode(void)
-{
- return (_fips_status & FIPS_MODE_ACTIVE);
-}
-
-#if FIPS_MODE_ENABLED
-static const uint8_t k_salt = NVMEM_VAR_G2F_SALT;
-
-/* Can't include TPM2 headers, so just define constant locally. */
-#define HR_NV_INDEX (1U << 24)
-
-/* Wipe old U2F keys. */
-static void u2f_zeroize(void)
-{
- const uint32_t u2fobjs[] = { TPM_HIDDEN_U2F_KEK | HR_NV_INDEX,
- TPM_HIDDEN_U2F_KH_SALT | HR_NV_INDEX, 0 };
- /* Delete NVMEM_VAR_G2F_SALT. */
- setvar(&k_salt, sizeof(k_salt), NULL, 0);
- /* Remove U2F keys and wipe all deleted objects. */
- nvmem_erase_tpm_data_selective(u2fobjs);
-}
+#else
+/* For production set it to zero, so check is eliminated. */
+#define fips_break_cmd 0
#endif
-/**
- * Return current status for U2F keys:
- * false - U2F keys require zeroization.
- * true - U2F keys are missing or created in FIPS mode.
- */
-static bool fips_u2f_compliant(void)
+static inline bool fips_is_no_crypto_error(void)
{
-/* Until U2F key gen switch to new code, don't enable FIPS mode. */
-#if FIPS_MODE_ENABLED
- uint8_t val_len = 0;
- const struct tuple *t_salt;
-
- /**
- * We are in FIPS mode if and only if:
- * 1) U2F keys were created in FIPS compliant way (board_fips_enforced)
- * 2) OR U2F keys weren't previously created
- */
- if (board_fips_enforced())
- return true;
-
- /* FIPS mode wasn't enforced, so check presence of U2F keys */
- t_salt = getvar(&k_salt, sizeof(k_salt));
- if (t_salt) {
- val_len = t_salt->val_len;
- freevar(t_salt);
- }
- /* If none of keys is present - we are in FIPS mode. */
- if (!val_len && !read_tpm_nvmem_size(TPM_HIDDEN_U2F_KEK) &&
- !read_tpm_nvmem_size(TPM_HIDDEN_U2F_KH_SALT)) {
- /* Apparently, board FIPS mode wasn't set yet, so set it. */
- board_set_local_fips_policy(true);
- return true;
- }
-#endif
- /* we still have old U2F keys, so not in FIPS until zeroized */
- return false;
+ return (_fips_status &
+ (FIPS_ERROR_MASK & (~FIPS_FATAL_SELF_INTEGRITY))) == 0;
}
/* Return true if crypto can be used (no failures detected). */
@@ -130,8 +60,7 @@ bool fips_crypto_allowed(void)
* TODO(b/138578318): remove ignoring of FIPS_FATAL_SELF_INTEGRITY.
*/
return ((_fips_status & FIPS_POWER_UP_TEST_DONE) &&
- !(_fips_status &
- (FIPS_ERROR_MASK & (~FIPS_FATAL_SELF_INTEGRITY))));
+ fips_is_no_crypto_error());
}
void fips_throw_err(enum fips_status err)
@@ -147,6 +76,49 @@ void fips_throw_err(enum fips_status err)
}
/**
+ * Set status of FIPS power-up tests on wake from sleep. We don't want to
+ * run lengthy KAT & power-up tests on every wake-up, so need to 'cache'
+ * result in long life register which content persists during sleep mode.
+ *
+ * @param asserted: false power-up tests should run on resume, otherwise
+ * can be skipped.
+ */
+static void fips_set_power_up(bool asserted)
+{
+ /* Enable writing to the long life register */
+ if (asserted)
+ GREG32(PMU, PWRDN_SCRATCH22) = BOARD_FIPS_POWERUP_DONE;
+ else
+ GREG32(PMU, PWRDN_SCRATCH22) = 0;
+}
+
+/**
+ * Return true if FIPS KAT tests completed successfully after waking up
+ * from sleep mode which clears RAM.
+ */
+static bool fips_is_power_up_done(void)
+{
+ return !!(GREG32(PMU, PWRDN_SCRATCH22) == BOARD_FIPS_POWERUP_DONE);
+}
+
+void fips_set_status(enum fips_status status)
+{
+ /**
+ * if FIPS error took place, drop indication of FIPS approved mode.
+ * Next cycle of sleep will power-cycle HW crypto components, so any
+ * soft-errors will be recovered. In case of hard errors it
+ * will be detected again.
+ */
+ /* Accumulate status (errors). */
+ _fips_status |= status;
+
+ status = _fips_status;
+ /* if we have error, require power up tests on resume. */
+ if (status & FIPS_ERROR_MASK)
+ fips_set_power_up(false);
+}
+
+/**
* Test vectors for Known-Answer Tests (KATs) and driving functions.
*/
@@ -420,6 +392,7 @@ static bool fips_ecdsa_verify_kat(void)
return !(fips_break_cmd == FIPS_BREAK_ECDSA) && (passed == 0);
}
+#ifdef CONFIG_FIPS_AES_CBC_256
#define AES_BLOCK_LEN 16
/* Known-answer test for AES-256 encrypt/decrypt. */
@@ -457,12 +430,13 @@ static bool fips_aes256_kat(void)
return !(fips_break_cmd == FIPS_BREAK_AES256) &&
(memcmp(kat_aes128_msg, dec, AES_BLOCK_LEN) == 0);
}
+#endif
#ifdef CONFIG_FIPS_RSA2048
/* Known-answer test for RSA 2048. */
static bool fips_rsa2048_verify_kat(void)
{
- uint8_t digest[SHA256_DIGEST_SIZE];
+ struct sha256_digest digest;
static const uint32_t pub[64] = {
0xf8729219, 0x2b42fc45, 0xfe6f4397, 0xa6ba59df, 0x4ce45ab8,
0x4be044ea, 0xdade58ec, 0xf871ada6, 0x3a6355a1, 0x43739940,
@@ -546,16 +520,16 @@ static bool fips_rsa2048_verify_kat(void)
int passed;
- DCRYPTO_SHA256_hash(msg, sizeof(msg), digest);
- passed = DCRYPTO_rsa_verify(&rsa, digest, sizeof(digest), sig,
+ SHA256_hw_hash(msg, sizeof(msg), &digest);
+ passed = DCRYPTO_rsa_verify(&rsa, digest.b8, sizeof(digest), sig,
sizeof(sig), PADDING_MODE_PKCS1,
HASH_SHA256);
if (!passed)
return false;
- DCRYPTO_SHA256_hash(bad_msg, sizeof(bad_msg), digest);
+ SHA256_hw_hash(bad_msg, sizeof(bad_msg), &digest);
/* now signature should fail */
- return !DCRYPTO_rsa_verify(&rsa, digest, sizeof(digest), sig,
+ return !DCRYPTO_rsa_verify(&rsa, digest.b8, sizeof(digest), sig,
sizeof(sig), PADDING_MODE_PKCS1,
HASH_SHA256);
}
@@ -604,16 +578,11 @@ static bool fips_self_integrity(void)
return DCRYPTO_equals(fips_integrity.b8, digest.b8, sizeof(digest));
}
-/**
- * FIPS Power-up known-answer tests.
- * Single point of initialization for all FIPS-compliant
- * cryptography. Responsible for KATs, TRNG testing, and signalling a
- * fatal error.
- * @return FIPS_POWERON_TEST_ERROR if memory allocation error took place
- */
-#define FIPS_POWERON_TEST_ERROR -2ULL
+/* Duration of FIPS tests. */
+uint64_t fips_last_kat_test_duration;
+
#define FIPS_KAT_STACK_SIZE 2048
-static uint64_t fips_power_up_tests(void)
+void fips_power_up_tests(void)
{
char *stack_buf;
void *stack;
@@ -645,11 +614,14 @@ static uint64_t fips_power_up_tests(void)
if (!call_on_stack(stack, &fips_ecdsa_verify_kat))
_fips_status |= FIPS_FATAL_ECDSA;
- if (!call_on_stack(stack, &fips_aes256_kat))
- _fips_status |= FIPS_FATAL_AES256;
if (!call_on_stack(stack, &fips_hmac_drbg_kat))
_fips_status |= FIPS_FATAL_HMAC_DRBG;
+#ifdef CONFIG_FIPS_AES_CBC_256
+ if (!call_on_stack(stack, &fips_aes256_kat))
+ _fips_status |= FIPS_FATAL_AES256;
+#endif
+
#ifdef CONFIG_FIPS_RSA2048
/* RSA KAT adds 30ms and not used for U2F */
if (!call_on_stack(stack, &fips_rsa2048_verify_kat))
@@ -667,7 +639,7 @@ static uint64_t fips_power_up_tests(void)
if (!call_on_stack(stack, &fips_hmac_sha256_kat))
_fips_status |= FIPS_FATAL_HMAC_SHA256;
#ifdef CONFIG_FIPS_SW_HMAC_DRBG
- /* SW HMAC DRBG adds 40ms and not used for U2F */
+ /* SW HMAC DRBG adds 30ms and not used for U2F */
if (!call_on_stack(stack, &fips_hmac_drbg_kat))
_fips_status |= FIPS_FATAL_HMAC_DRBG;
#endif
@@ -676,9 +648,10 @@ static uint64_t fips_power_up_tests(void)
/* Second call to TRNG warm-up. */
fips_trng_startup(1);
- /* if no errors, set not to run tests on wake from sleep. */
- if (!(_fips_status & FIPS_ERROR_MASK))
- board_set_fips_policy_test(true);
+
+ /* If no errors, set not to run tests on wake from sleep. */
+ if (fips_is_no_crypto_error())
+ fips_set_power_up(true);
else /* write combined error to flash log */
flash_log_add_event(FE_LOG_FIPS_FAILURE,
sizeof(_fips_status),
@@ -686,39 +659,15 @@ static uint64_t fips_power_up_tests(void)
/* Set the bit that power-up tests completed, even if failed. */
_fips_status |= FIPS_POWER_UP_TEST_DONE;
} else
- return FIPS_POWERON_TEST_ERROR;
+ _fips_status |= FIPS_FATAL_OTHER;
- return get_time().val - starttime;
-}
-
-/* Print on console current FIPS mode. */
-static void fips_print_mode(void)
-{
- if (_fips_status == FIPS_UNINITIALIZED)
- CPRINTS("FIPS mode not initialized");
- else if (_fips_status & FIPS_ERROR_MASK)
- CPRINTS("FIPS error code 0x%08x, not-approved", _fips_status);
- else
- CPRINTS("Running in FIPS 140-2 %s mode",
- ((_fips_status & FIPS_MODE_ACTIVE) &&
- (_fips_status & FIPS_POWER_UP_TEST_DONE)) ?
- "approved" :
- "not-approved");
-}
-
-/* Print time it took tests to run or print error message. */
-static void fips_print_test_time(uint64_t time)
-{
- if (time == FIPS_POWERON_TEST_ERROR)
- CPRINTS("FIPS test failed to run");
- else if (time != -1ULL)
- CPRINTS("FIPS power-up tests completed in %llu", time);
+ fips_last_kat_test_duration = get_time().val - starttime;
}
/* Initialize FIPS mode. Executed during power-up and resume from sleep. */
static void fips_power_on(void)
{
- uint64_t testtime = -1ULL;
+ fips_last_kat_test_duration = -1ULL;
/* make sure on power-on / resume it's cleared */
_fips_status = FIPS_UNINITIALIZED;
@@ -727,164 +676,16 @@ static void fips_power_on(void)
* for some reason, run them now. Board FIPS KAT status will
* be updated by fips_power_up_tests() if all tests pass.
*/
- if (!board_fips_power_up_done())
- testtime = fips_power_up_tests();
+ if (!fips_is_power_up_done())
+ fips_power_up_tests();
else /* tests were already completed before sleep */
_fips_status |= FIPS_POWER_UP_TEST_DONE;
/* Check if we can set FIPS-approved mode. */
- if (fips_u2f_compliant())
+ if (fips_crypto_allowed())
fips_set_status(FIPS_MODE_ACTIVE);
- /* Once FIPS power-up tests completed we can enable console output. */
- console_enable_output();
-
- fips_print_test_time(testtime);
- fips_print_mode();
}
/* FIPS initialization is last init hook, HOOK_PRIO_FIPS > HOOK_PRIO_LAST */
-DECLARE_HOOK(HOOK_INIT, fips_power_on, HOOK_PRIO_FIPS);
-
-/* Switch FIPS status. */
-void fips_set_policy(bool active)
-{
-#ifndef CR50_DEV
- /* in Production mode never disable FIPS once enabled. */
- if (!active)
- return;
-#endif
- /* Do nothing if there is no change. */
- if (!(!active ^ !(_fips_status & FIPS_MODE_ACTIVE)))
- return;
-/* Temporarily prevent switch to FIPS mode until U2F key gen is ready. */
-#if FIPS_MODE_ENABLED
- /* Update local board FIPS flag. */
- board_set_local_fips_policy(active);
- CPRINTS("FIPS policy set to %d", active);
- cflush();
- u2f_zeroize();
-
-#ifdef CR50_DEV
- if (!active) {
- uint8_t random[32];
- /* Create fake u2f keys old style */
- fips_trng_bytes(random, sizeof(random));
- setvar(&k_salt, sizeof(k_salt), random, sizeof(random));
-
- fips_trng_bytes(random, sizeof(random));
- write_tpm_nvmem_hidden(TPM_HIDDEN_U2F_KEK, sizeof(random),
- random, 1);
- fips_trng_bytes(random, sizeof(random));
- write_tpm_nvmem_hidden(TPM_HIDDEN_U2F_KH_SALT, sizeof(random),
- random, 1);
- }
-#endif
-#endif
- system_reset(EC_RESET_FLAG_SECURITY);
-}
-
-/* Console command 'fips' to report and change status, run tests */
-static int cmd_fips_status(int argc, char **argv)
-{
- fips_print_mode();
- ccprints("FIPS crypto allowed: %u, u2f compliant: %u, "
- "board power up done: %u, board enforced: %u, fwmp : %u",
- fips_crypto_allowed(), fips_u2f_compliant(),
- board_fips_power_up_done(), board_fips_enforced(),
- board_fwmp_fips_mode_enabled());
-
- cflush();
-
- if (argc == 2) {
- if (!strncmp(argv[1], "on", 2))
- fips_set_policy(true);
- else if (!strncmp(argv[1], "test", 4)) {
- fips_print_test_time(fips_power_up_tests());
- fips_print_mode();
- }
-#ifdef CR50_DEV
- else if (!strncmp(argv[1], "off", 3))
- fips_set_policy(false);
- else if (!strncmp(argv[1], "trng", 4))
- fips_break_cmd = FIPS_BREAK_TRNG;
- else if (!strncmp(argv[1], "sha", 3))
- fips_break_cmd = FIPS_BREAK_SHA256;
-#endif
- }
- return 0;
-}
-
-DECLARE_SAFE_CONSOLE_COMMAND(fips, cmd_fips_status,
-#ifdef CR50_DEV
- "[on | off | test | trng | sha]",
-#else
- "[on | test]",
-#endif
- "Report or change FIPS status, run tests, simulate errors");
-
-/**
- * Vendor command implementation to report & change status, run tests.
- * Command structure:
- *
- * field | size | note
- * =========================================================================
- * op | 1 | 0 - get status, 1 - set FIPS ON (remove old U2F)
- * | | 2 - run tests, 3 .. 8 - simulate errors
- */
-static enum vendor_cmd_rc fips_cmd(enum vendor_cmd_cc code, void *buf,
- size_t input_size, size_t *response_size)
-{
- uint8_t *cmd = buf;
- uint32_t fips_reverse;
-
- *response_size = 0;
- if (input_size != 1)
- return VENDOR_RC_BOGUS_ARGS;
-
- switch ((enum fips_cmd)*cmd) {
- case FIPS_CMD_GET_STATUS:
- fips_reverse = htobe32(_fips_status);
- memcpy(buf, &fips_reverse, sizeof(fips_reverse));
- *response_size = sizeof(fips_reverse);
- break;
- case FIPS_CMD_ON:
- fips_set_policy(true); /* we can reboot here... */
- break;
- case FIPS_CMD_TEST:
- fips_power_up_tests();
- fips_reverse = htobe32(_fips_status);
- memcpy(buf, &fips_reverse, sizeof(fips_reverse));
- *response_size = sizeof(fips_reverse);
- break;
-#ifdef CR50_DEV
- case FIPS_CMD_BREAK_TRNG:
- fips_break_cmd = FIPS_BREAK_TRNG;
- break;
- case FIPS_CMD_BREAK_SHA256:
- fips_break_cmd = FIPS_BREAK_SHA256;
- break;
- case FIPS_CMD_BREAK_HMAC_SHA256:
- fips_break_cmd = FIPS_BREAK_HMAC_SHA256;
- break;
- case FIPS_CMD_BREAK_HMAC_DRBG:
- fips_break_cmd = FIPS_BREAK_HMAC_DRBG;
- break;
- case FIPS_CMD_BREAK_ECDSA:
- fips_break_cmd = FIPS_BREAK_ECDSA;
- break;
- case FIPS_CMD_BREAK_AES256:
- fips_break_cmd = FIPS_BREAK_AES256;
- break;
- case FIPS_CMD_NO_BREAK:
- fips_break_cmd = FIPS_NO_BREAK;
- break;
-#endif
- default:
- return VENDOR_RC_BOGUS_ARGS;
- }
-
- return VENDOR_RC_SUCCESS;
-}
-
-DECLARE_VENDOR_COMMAND(VENDOR_CC_FIPS_CMD, fips_cmd);
+DECLARE_HOOK(HOOK_INIT, fips_power_on, HOOK_PRIO_INIT_FIPS);
diff --git a/board/cr50/fips.h b/board/cr50/fips.h
index 4a7eef2f0e..a9017e46a9 100644
--- a/board/cr50/fips.h
+++ b/board/cr50/fips.h
@@ -27,8 +27,12 @@ enum fips_status {
FIPS_FATAL_HMAC_SHA256 = 1 << 5,
FIPS_FATAL_HMAC_DRBG = 1 << 6,
FIPS_FATAL_ECDSA = 1 << 7,
+#ifdef CONFIG_FIPS_RSA2048
FIPS_FATAL_RSA2048 = 1 << 8,
+#endif
+#ifdef CONFIG_FIPS_AES_CBC_256
FIPS_FATAL_AES256 = 1 << 9,
+#endif
FIPS_FATAL_SELF_INTEGRITY = 1 << 10,
FIPS_FATAL_OTHER = 1 << 15,
FIPS_ERROR_MASK = 0xffff,
@@ -43,9 +47,20 @@ enum fips_break {
FIPS_BREAK_HMAC_SHA256 = 3,
FIPS_BREAK_HMAC_DRBG = 4,
FIPS_BREAK_ECDSA = 5,
- FIPS_BREAK_AES256 = 6
+#ifdef CONFIG_FIPS_AES_CBC_256
+ FIPS_BREAK_AES256 = 6,
+#endif
+#ifdef CONFIG_FIPS_RSA2048
+ FIPS_BREAK_RSA2048 = 7,
+#endif
};
+
+#ifdef CRYPTO_TEST_SETUP
extern uint8_t fips_break_cmd;
+#endif
+
+/* Duration of last FIPS KAT / Power-up tests. */
+extern uint64_t fips_last_kat_test_duration;
/* Command codes for VENDOR_CC_FIPS_CMD. */
enum fips_cmd {
@@ -57,8 +72,13 @@ enum fips_cmd {
FIPS_CMD_BREAK_HMAC_SHA256 = 5,
FIPS_CMD_BREAK_HMAC_DRBG = 6,
FIPS_CMD_BREAK_ECDSA = 7,
+#ifdef CONFIG_FIPS_AES_CBC_256
FIPS_CMD_BREAK_AES256 = 8,
- FIPS_CMD_NO_BREAK = 9
+#endif
+#ifdef CONFIG_FIPS_RSA2048
+ FIPS_CMD_BREAK_RSA2048 = 9,
+#endif
+ FIPS_CMD_NO_BREAK = 10
};
/* These symbols defined in core/cortex-m/ec.lds.S. */
@@ -68,9 +88,6 @@ extern uint8_t __fips_module_end;
/* Return current FIPS status of operations. */
enum fips_status fips_status(void);
-/* return true if in FIPS-approved mode. */
-bool fips_mode(void);
-
/**
* Crypto is enabled when either FIPS mode is not enforced,
* or if it is enforced and in good health
@@ -89,10 +106,14 @@ void fips_set_status(enum fips_status status);
void fips_throw_err(enum fips_status err);
/**
- * Switch FIPS status, zeroize keys if needed. For Production it's a one way
- * to 'FIPS on'. For development board it allows creation of non-FIPS keys.
+ * FIPS Power-up and known-answer tests.
+ * Single point of initialization for all FIPS-compliant
+ * cryptography. Responsible for KATs, TRNG testing, and signalling a
+ * fatal error.
+ *
+ * Set FIPS status globally as a result.
*/
-void fips_set_policy(bool active);
+void fips_power_up_tests(void);
#ifdef __cplusplus
}
diff --git a/board/cr50/fips_cmd.c b/board/cr50/fips_cmd.c
new file mode 100644
index 0000000000..304e23a0da
--- /dev/null
+++ b/board/cr50/fips_cmd.c
@@ -0,0 +1,215 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "builtin/endian.h"
+#include "console.h"
+#include "dcrypto.h"
+#include "ec_commands.h"
+#include "extension.h"
+#include "fips.h"
+#include "fips_rand.h"
+#include "flash_log.h"
+#include "hooks.h"
+#include "new_nvmem.h"
+#include "nvmem.h"
+#include "nvmem_vars.h"
+#include "registers.h"
+#include "scratch_reg1.h"
+#include "shared_mem.h"
+#include "system.h"
+#include "tpm_nvmem_ops.h"
+#include "u2f_impl.h"
+
+#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ##args)
+
+/* Print on console current FIPS mode. */
+static void fips_print_mode(void)
+{
+ enum fips_status status = fips_status();
+
+ if (status == FIPS_UNINITIALIZED)
+ CPRINTS("FIPS mode not initialized");
+ else if (status & FIPS_ERROR_MASK)
+ CPRINTS("FIPS error code 0x%08x, not-approved", status);
+ else
+ CPRINTS("Running in FIPS 140-2 %s mode",
+ ((status & FIPS_MODE_ACTIVE) &&
+ (status & FIPS_POWER_UP_TEST_DONE)) ?
+ "approved" :
+ "not-approved");
+}
+
+/* Print time it took tests to run or print error message. */
+static void fips_print_test_time(void)
+{
+ if (fips_last_kat_test_duration != -1ULL)
+ CPRINTS("FIPS power-up tests completed in %llu",
+ fips_last_kat_test_duration);
+}
+
+static void fips_print_status(void)
+{
+ /* Once FIPS power-up tests completed we can enable console output. */
+ console_enable_output();
+
+ fips_print_test_time();
+ fips_print_mode();
+}
+DECLARE_HOOK(HOOK_INIT, fips_print_status, HOOK_PRIO_INIT_PRINT_FIPS_STATUS);
+
+#ifdef CRYPTO_TEST_SETUP
+static const uint8_t k_salt = NVMEM_VAR_G2F_SALT;
+
+/* Can't include TPM2 headers, so just define constant locally. */
+#define HR_NV_INDEX (1U << 24)
+
+/* Wipe old U2F keys. */
+static void u2f_zeroize_non_fips(void)
+{
+ const uint32_t u2fobjs[] = { TPM_HIDDEN_U2F_KEK | HR_NV_INDEX,
+ TPM_HIDDEN_U2F_KH_SALT | HR_NV_INDEX, 0 };
+ /* Delete NVMEM_VAR_G2F_SALT. */
+ setvar(&k_salt, sizeof(k_salt), NULL, 0);
+ /* Remove U2F keys and wipe all deleted objects. */
+ nvmem_erase_tpm_data_selective(u2fobjs);
+}
+
+/* Set U2F keys to old or new version. */
+static void fips_set_u2f_keys(bool active)
+{
+ if (!active) {
+ /* Old version. */
+ uint8_t random[32];
+ /* Create fake u2f keys old style */
+ fips_trng_bytes(random, sizeof(random));
+ setvar(&k_salt, sizeof(k_salt), random, sizeof(random));
+
+ fips_trng_bytes(random, sizeof(random));
+ write_tpm_nvmem_hidden(TPM_HIDDEN_U2F_KEK, sizeof(random),
+ random, 1);
+ fips_trng_bytes(random, sizeof(random));
+ write_tpm_nvmem_hidden(TPM_HIDDEN_U2F_KH_SALT, sizeof(random),
+ random, 1);
+ } else {
+ /**
+ * TODO(sukhomlinov): Implement new key generation after merging
+ * https://crrev.com/c/3034852 and adding FIPS key gen.
+ */
+ u2f_zeroize_non_fips();
+ }
+ system_reset(EC_RESET_FLAG_SECURITY);
+}
+#endif
+
+/* Console command 'fips' to report and change status, run tests */
+static int cmd_fips_status(int argc, char **argv)
+{
+ fips_print_mode();
+ fips_print_test_time();
+ CPRINTS("FIPS crypto allowed: %u", fips_crypto_allowed());
+
+ cflush();
+
+ if (argc == 2) {
+ if (!strncmp(argv[1], "test", 4)) {
+ fips_power_up_tests();
+ fips_print_test_time();
+ fips_print_mode();
+ }
+#ifdef CRYPTO_TEST_SETUP
+ else if (!strncmp(argv[1], "new", 3))
+ fips_set_u2f_keys(true); /* we can reboot here... */
+ else if (!strncmp(argv[1], "old", 3))
+ fips_set_u2f_keys(false); /* we can reboot here... */
+ else if (!strncmp(argv[1], "trng", 4))
+ fips_break_cmd = FIPS_BREAK_TRNG;
+ else if (!strncmp(argv[1], "sha", 3))
+ fips_break_cmd = FIPS_BREAK_SHA256;
+#endif
+ }
+ return 0;
+}
+
+DECLARE_SAFE_CONSOLE_COMMAND(
+ fips, cmd_fips_status,
+#ifdef CRYPTO_TEST_SETUP
+ "[test | new | old | trng | sha]",
+ "Report FIPS status, switch U2F key, run tests, simulate errors");
+#else
+ "[test]", "Report FIPS status, run tests");
+#endif
+
+/**
+ * Vendor command implementation to report & change status, run tests.
+ * Command structure:
+ *
+ * field | size | note
+ * =========================================================================
+ * op | 1 | 0 - get status, 1 - set FIPS ON (remove old U2F)
+ * | | 2 - run tests, 3 .. 8 - simulate errors
+ */
+static enum vendor_cmd_rc fips_cmd(enum vendor_cmd_cc code, void *buf,
+ size_t input_size, size_t *response_size)
+{
+ uint8_t *cmd = buf;
+ uint32_t fips_reverse;
+
+ *response_size = 0;
+ if (input_size != 1)
+ return VENDOR_RC_BOGUS_ARGS;
+
+ switch ((enum fips_cmd) *cmd) {
+ case FIPS_CMD_GET_STATUS:
+ fips_reverse = htobe32(fips_status());
+ memcpy(buf, &fips_reverse, sizeof(fips_reverse));
+ *response_size = sizeof(fips_reverse);
+ break;
+ case FIPS_CMD_TEST:
+ fips_power_up_tests();
+ fips_reverse = htobe32(fips_status());
+ memcpy(buf, &fips_reverse, sizeof(fips_reverse));
+ *response_size = sizeof(fips_reverse);
+ break;
+#ifdef CRYPTO_TEST_SETUP
+ case FIPS_CMD_ON:
+ fips_set_u2f_keys(true); /* we can reboot here... */
+ break;
+ case FIPS_CMD_BREAK_TRNG:
+ fips_break_cmd = FIPS_BREAK_TRNG;
+ break;
+ case FIPS_CMD_BREAK_SHA256:
+ fips_break_cmd = FIPS_BREAK_SHA256;
+ break;
+ case FIPS_CMD_BREAK_HMAC_SHA256:
+ fips_break_cmd = FIPS_BREAK_HMAC_SHA256;
+ break;
+ case FIPS_CMD_BREAK_HMAC_DRBG:
+ fips_break_cmd = FIPS_BREAK_HMAC_DRBG;
+ break;
+ case FIPS_CMD_BREAK_ECDSA:
+ fips_break_cmd = FIPS_BREAK_ECDSA;
+ break;
+#ifdef CONFIG_FIPS_AES_CBC_256
+ case FIPS_CMD_BREAK_AES256:
+ fips_break_cmd = FIPS_BREAK_AES256;
+ break;
+#endif /* CONFIG_FIPS_AES_CBC_256 */
+#ifdef CONFIG_FIPS_RSA2048
+ case FIPS_CMD_BREAK_RSA2048:
+ fips_break_cmd = FIPS_BREAK_RSA2048;
+ break;
+#endif /* CONFIG_FIPS_RSA2048 */
+ case FIPS_CMD_NO_BREAK:
+ fips_break_cmd = FIPS_NO_BREAK;
+ break;
+#endif /* CRYPTO_TEST_SETUP */
+ default:
+ return VENDOR_RC_BOGUS_ARGS;
+ }
+
+ return VENDOR_RC_SUCCESS;
+}
+
+DECLARE_VENDOR_COMMAND(VENDOR_CC_FIPS_CMD, fips_cmd);
diff --git a/board/cr50/fips_rand.c b/board/cr50/fips_rand.c
index 2b2f796767..a214f9196e 100644
--- a/board/cr50/fips_rand.c
+++ b/board/cr50/fips_rand.c
@@ -181,9 +181,11 @@ static struct rand_result read_rand(void)
uint32_t empty_count = 0;
uint32_t reset_count = 0;
+#ifdef CRYPTO_TEST_SETUP
/* Do we need to simulate error? */
if (fips_break_cmd == FIPS_BREAK_TRNG)
return (struct rand_result){ .random_value = 0, .valid = true };
+#endif
/**
* make sure we never hang in the loop - try at max 1
diff --git a/board/cr50/wp.c b/board/cr50/wp.c
index 7b8f02b24d..e24332c3d4 100644
--- a/board/cr50/wp.c
+++ b/board/cr50/wp.c
@@ -386,7 +386,6 @@ int board_wipe_tpm(int reset_required)
*/
#define FWMP_HASH_SIZE 32
#define FWMP_DEV_DISABLE_CCD_UNLOCK BIT(6)
-#define FWMP_DEV_FIPS_MODE BIT(7)
#define FIRMWARE_FLAG_DEV_MODE 0x02
struct RollbackSpaceFirmware {
@@ -472,19 +471,6 @@ int board_fwmp_allows_unlock(void)
#endif
}
-int board_fwmp_fips_mode_enabled(void)
-{
- struct RollbackSpaceFirmware fw;
-
- if (TPM_READ_SUCCESS ==
- read_tpm_nvmem(FIRMWARE_NV_INDEX, sizeof(fw), &fw)) {
- return !!(fw.flags & FWMP_DEV_FIPS_MODE);
- }
-
- /* If not found or other error, assume fips mode is disabled */
- return 0;
-}
-
int board_vboot_dev_mode_enabled(void)
{
struct RollbackSpaceFirmware fw;
diff --git a/include/config.h b/include/config.h
index 7f334bd5dc..bc183476ac 100644
--- a/include/config.h
+++ b/include/config.h
@@ -4885,9 +4885,11 @@
#define CONFIG_CRC8
#endif
-/* Run RSA 2048 known-answer test (+30 ms) */
+/* Don't run RSA 2048 known-answer test (+30 ms). */
#undef CONFIG_FIPS_RSA2048
-/* Run software HMAC_DRBG-SHA256 known-answer test (+40 ms) */
+/* Don't run software HMAC_DRBG-SHA256 known-answer test (+30 ms). */
#undef CONFIG_FIPS_SW_HMAC_DRBG
+/* Don't run AES CBC 256 test (not used for U2F anymore). */
+#undef CONFIG_FIPS_AES_CBC_256
#endif /* __CROS_EC_CONFIG_H */
diff --git a/include/hooks.h b/include/hooks.h
index 0142ab62a0..1002f23d83 100644
--- a/include/hooks.h
+++ b/include/hooks.h
@@ -15,7 +15,6 @@ enum hook_priority {
HOOK_PRIO_FIRST = 1, /* Highest priority */
HOOK_PRIO_DEFAULT = 5000, /* Default priority */
HOOK_PRIO_LAST = 9999, /* Lowest priority */
- HOOK_PRIO_FIPS = 10000, /* FIPS init executes last */
/* Specific hook vales for HOOK_INIT */
/* DMA inits before ADC, I2C, SPI */
@@ -68,6 +67,11 @@ enum hook_priority {
HOOK_PRIO_TEMP_SENSOR = 6000,
/* After all sensors have been polled */
HOOK_PRIO_TEMP_SENSOR_DONE = HOOK_PRIO_TEMP_SENSOR + 1,
+
+ /* Once devices are initialized, run FIPS tests and print status. */
+ HOOK_PRIO_INIT_FIPS = 9997, /* FIPS init executes last */
+ HOOK_PRIO_INIT_PRINT_FIPS_STATUS = 9998, /* Status of FIPS tests. */
+
};
enum hook_type {