diff options
Diffstat (limited to 'board/cr50/fips.c')
-rw-r--r-- | board/cr50/fips.c | 357 |
1 files changed, 79 insertions, 278 deletions
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); |