diff options
author | Vadim Sukhomlinov <sukhomlinov@google.com> | 2021-09-27 17:47:29 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-10-02 04:01:49 +0000 |
commit | 0ad46f2259b79b07a1d4b114fd58472a88c19282 (patch) | |
tree | 8313e9894a779c602cca27fd79b81bcc9a7ca3b6 /common | |
parent | 7b25ee08172491864900e3a2ba59d761355f4069 (diff) | |
download | chrome-ec-0ad46f2259b79b07a1d4b114fd58472a88c19282.tar.gz |
cr50: provide public crypto API for HMAC/HASH with error reporting.
To implement FIPS mode for Cr50 we should be able to block access to
crypto functions if errors are detected. Historically all HASH/HMAC
functions were declared as void with no return type.
1) Split existing functions into public part (data structs, update and
final parts) and internal part - unchecked init functions.
2) Introduced new functions to start SHA / HMAC operation which returns
status code and block access to crypto in case of FIPS errors.
3) Dcrypto hash algorithms codes updated to match TPM_ALG_ID to simplify
adaptation layer and move checks inside Dcrypto module.
4) Updated all uses of API outside FIPS module to check return code and
act accordingly.
5) As a side effect RSA can now support SHA384 & SHA512 for signing,
board/host mock ups simplified.
BUG=b:197893750
TEST=make buildall -j; make BOARD=cr50 CRYPTO_TEST=1;
test/tpm_test/tpm_test.py
TCG tests
------------------------------ Test Result Summary ---------------------
Test executed on: Tue Sep 28 15:23:35 2021
Performed Tests: 248
Passed Tests: 248
Failed Tests: 0
Errors: 0
Warnings: 0
========================================================================
Signed-off-by: Vadim Sukhomlinov <sukhomlinov@google.com>
Change-Id: Ibbc38703496f417cba693c37d39a82a662c3f7ee
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3192137
Reviewed-by: Vadim Sukhomlinov <sukhomlinov@chromium.org>
Reviewed-by: Andrey Pronin <apronin@chromium.org>
Tested-by: Vadim Sukhomlinov <sukhomlinov@chromium.org>
Commit-Queue: Vadim Sukhomlinov <sukhomlinov@chromium.org>
Diffstat (limited to 'common')
-rw-r--r-- | common/ccd_config.c | 24 | ||||
-rw-r--r-- | common/pinweaver.c | 90 | ||||
-rw-r--r-- | common/rma_auth.c | 45 |
3 files changed, 104 insertions, 55 deletions
diff --git a/common/ccd_config.c b/common/ccd_config.c index 12e88689ad..d87842a055 100644 --- a/common/ccd_config.c +++ b/common/ccd_config.c @@ -236,7 +236,8 @@ static int raw_has_password(void) * @param digest Pointer to a CCD_PASSWORD_DIGEST_SIZE buffer * @param password The password to digest */ -static void ccd_password_digest(uint8_t *digest, const char *password) +static enum ec_error_list ccd_password_digest(uint8_t *digest, + const char *password) { struct sha256_ctx sha; uint8_t *unique_id; @@ -244,11 +245,13 @@ static void ccd_password_digest(uint8_t *digest, const char *password) unique_id_len = system_get_chip_unique_id(&unique_id); - SHA256_hw_init(&sha); + if (DCRYPTO_hw_sha256_init(&sha) != DCRYPTO_OK) + return EC_ERROR_HW_INTERNAL; SHA256_update(&sha, config.password_salt, sizeof(config.password_salt)); SHA256_update(&sha, unique_id, unique_id_len); SHA256_update(&sha, password, strlen(password)); memcpy(digest, SHA256_final(&sha)->b8, CCD_PASSWORD_DIGEST_SIZE); + return EC_SUCCESS; } /** @@ -258,7 +261,7 @@ static void ccd_password_digest(uint8_t *digest, const char *password) * @return EC_SUCCESS, EC_ERROR_BUSY if too soon since last attempt, or * EC_ERROR_ACCESS_DENIED if mismatch. */ -static int raw_check_password(const char *password) +static enum ec_error_list raw_check_password(const char *password) { /* * Time of last password attempt; initialized to 0 at boot. Yes, we're @@ -272,6 +275,7 @@ static int raw_check_password(const char *password) uint8_t digest[CCD_PASSWORD_DIGEST_SIZE]; uint32_t t; + enum ec_error_list result; /* If no password is set, match only an empty password */ if (!raw_has_password()) @@ -284,7 +288,9 @@ static int raw_check_password(const char *password) last_password_time = t; /* Calculate the digest of the password */ - ccd_password_digest(digest, password); + result = ccd_password_digest(digest, password); + if (result != EC_SUCCESS) + return result; if (safe_memcmp(digest, config.password_digest, sizeof(config.password_digest))) @@ -312,19 +318,23 @@ static void raw_reset_password(void) * @param password New password; must be non-empty * @return EC_SUCCESS if successful */ -static int raw_set_password(const char *password) +static enum ec_error_list raw_set_password(const char *password) { + enum ec_error_list result; + /* Get a new salt */ if (!fips_rand_bytes(config.password_salt, sizeof(config.password_salt))) return EC_ERROR_HW_INTERNAL; /* Update the password digest */ - ccd_password_digest(config.password_digest, password); + result = ccd_password_digest(config.password_digest, password); + if (result != EC_SUCCESS) + return result; /* Track whether we were opened when we set the password */ raw_set_flag(CCD_FLAG_PASSWORD_SET_WHEN_UNLOCKED, - ccd_state == CCD_STATE_UNLOCKED); + ccd_state == CCD_STATE_UNLOCKED); return EC_SUCCESS; } diff --git a/common/pinweaver.c b/common/pinweaver.c index 0bcd752ab6..9b7ad0b6d6 100644 --- a/common/pinweaver.c +++ b/common/pinweaver.c @@ -164,7 +164,8 @@ static int create_merkle_tree(struct bits_per_level_t bits_per_level, /* Initialize the root hash. */ for (hx = 0; hx < height.v; ++hx) { - SHA256_hw_init(&ctx); + if (DCRYPTO_hw_sha256_init(&ctx) != DCRYPTO_OK) + return PW_ERR_CRYPTO_FAILURE; for (kx = 0; kx < fan_out; ++kx) HASH_update((union hash_ctx *)&ctx, temp_hash, PW_HASH_SIZE); @@ -180,29 +181,31 @@ static int create_merkle_tree(struct bits_per_level_t bits_per_level, } /* Computes the HMAC for an encrypted leaf using the key in the merkle_tree. */ -static void compute_hmac(const struct merkle_tree_t *merkle_tree, +static int compute_hmac(const struct merkle_tree_t *merkle_tree, const struct imported_leaf_data_t *imported_leaf_data, uint8_t result[PW_HASH_SIZE]) { struct hmac_sha256_ctx hmac; - HMAC_SHA256_hw_init(&hmac, merkle_tree->hmac_key, - sizeof(merkle_tree->hmac_key)); - /* use HASH_update() vs. HMAC_update() due limits of dcrypto mock. */ - HASH_update((union hash_ctx *)&hmac.hash, imported_leaf_data->head, - sizeof(*imported_leaf_data->head)); - HASH_update((union hash_ctx *)&hmac.hash, imported_leaf_data->iv, - sizeof(PW_WRAP_BLOCK_SIZE)); - HASH_update((union hash_ctx *)&hmac.hash, imported_leaf_data->pub, - imported_leaf_data->head->pub_len); - HASH_update((union hash_ctx *)&hmac.hash, - imported_leaf_data->cipher_text, - imported_leaf_data->head->sec_len); - memcpy(result, HMAC_SHA256_hw_final(&hmac), PW_HASH_SIZE); + if (DCRYPTO_hw_hmac_sha256_init(&hmac, merkle_tree->hmac_key, + sizeof(merkle_tree->hmac_key)) != + DCRYPTO_OK) + return PW_ERR_CRYPTO_FAILURE; + + HMAC_SHA256_update(&hmac, imported_leaf_data->head, + sizeof(*imported_leaf_data->head)); + HMAC_SHA256_update(&hmac, imported_leaf_data->iv, + sizeof(PW_WRAP_BLOCK_SIZE)); + HMAC_SHA256_update(&hmac, imported_leaf_data->pub, + imported_leaf_data->head->pub_len); + HMAC_SHA256_update(&hmac, imported_leaf_data->cipher_text, + imported_leaf_data->head->sec_len); + memcpy(result, HMAC_SHA256_final(&hmac), PW_HASH_SIZE); + return EC_SUCCESS; } /* Computes the root hash for the specified path and child hash. */ -static void compute_root_hash(const struct merkle_tree_t *merkle_tree, +static int compute_root_hash(const struct merkle_tree_t *merkle_tree, struct label_t path, const uint8_t hashes[][PW_HASH_SIZE], const uint8_t child_hash[PW_HASH_SIZE], @@ -214,18 +217,25 @@ static void compute_root_hash(const struct merkle_tree_t *merkle_tree, uint8_t temp_hash[PW_HASH_SIZE]; uint8_t hx = 0; uint64_t index = path.v; + int ret; + + ret = compute_hash(hashes, num_aux, + (struct index_t){ index & path_suffix_mask }, + child_hash, temp_hash); + if (ret != EC_SUCCESS) + return ret; - compute_hash(hashes, num_aux, - (struct index_t){index & path_suffix_mask}, - child_hash, temp_hash); for (hx = 1; hx < merkle_tree->height.v; ++hx) { hashes += num_aux; index = index >> merkle_tree->bits_per_level.v; - compute_hash(hashes, num_aux, - (struct index_t){index & path_suffix_mask}, - temp_hash, temp_hash); + ret = compute_hash(hashes, num_aux, + (struct index_t){ index & path_suffix_mask }, + temp_hash, temp_hash); + if (ret != EC_SUCCESS) + return ret; } memcpy(new_root, temp_hash, sizeof(temp_hash)); + return EC_SUCCESS; } /* Checks to see the specified path is valid. The length of the path should be @@ -239,8 +249,11 @@ static int authenticate_path(const struct merkle_tree_t *merkle_tree, const uint8_t child_hash[PW_HASH_SIZE]) { uint8_t parent[PW_HASH_SIZE]; + int ret; - compute_root_hash(merkle_tree, path, hashes, child_hash, parent); + ret = compute_root_hash(merkle_tree, path, hashes, child_hash, parent); + if (ret != EC_SUCCESS) + return ret; if (memcmp(parent, merkle_tree->root, sizeof(parent)) != 0) return PW_ERR_PATH_AUTH_FAILED; return EC_SUCCESS; @@ -334,13 +347,13 @@ static int handle_leaf_update( import_leaf((const struct unimported_leaf_data_t *)wrapped_leaf_data, &ptrs); - compute_hmac(merkle_tree, &ptrs, wrapped_leaf_data->hmac); - compute_root_hash(merkle_tree, leaf_data->pub.label, - hashes, wrapped_leaf_data->hmac, - new_root); + ret = compute_hmac(merkle_tree, &ptrs, wrapped_leaf_data->hmac); + if (ret != EC_SUCCESS) + return ret; - return EC_SUCCESS; + return compute_root_hash(merkle_tree, leaf_data->pub.label, hashes, + wrapped_leaf_data->hmac, new_root); } /******************************************************************************/ @@ -532,7 +545,9 @@ static int validate_request_with_wrapped_leaf( if (ret != EC_SUCCESS) return ret; - compute_hmac(merkle_tree, imported_leaf_data, hmac); + ret = compute_hmac(merkle_tree, imported_leaf_data, hmac); + if (ret != EC_SUCCESS) + return ret; /* Safe memcmp is used here to prevent an attacker from being able to * brute force a valid HMAC for a crafted wrapped_leaf_data. * memcmp provides an attacker a timing side-channel they can use to @@ -994,8 +1009,10 @@ static int pw_handle_remove_leaf(struct merkle_tree_t *merkle_tree, if (ret != EC_SUCCESS) return ret; - compute_root_hash(merkle_tree, request->leaf_location, - request->path_hashes, empty_hash, new_root); + ret = compute_root_hash(merkle_tree, request->leaf_location, + request->path_hashes, empty_hash, new_root); + if (ret != EC_SUCCESS) + return ret; ret = log_remove_leaf(request->leaf_location, new_root); if (ret != EC_SUCCESS) @@ -1283,7 +1300,10 @@ static int pw_handle_log_replay(const struct merkle_tree_t *merkle_tree, if (log.entries[x].type.v != PW_TRY_AUTH) return PW_ERR_TYPE_INVALID; - compute_hmac(merkle_tree, &imported_leaf_data, hmac); + ret = compute_hmac(merkle_tree, &imported_leaf_data, hmac); + if (ret != EC_SUCCESS) + return ret; + if (safe_memcmp(hmac, request->unimported_leaf_data.hmac, sizeof(hmac))) return PW_ERR_HMAC_AUTH_FAILED; @@ -1385,14 +1405,15 @@ int get_path_auxiliary_hash_count(const struct merkle_tree_t *merkle_tree) * ARRAY_SIZE(hashes) == num_hashes * 0 <= location <= num_hashes */ -void compute_hash(const uint8_t hashes[][PW_HASH_SIZE], uint16_t num_hashes, +int compute_hash(const uint8_t hashes[][PW_HASH_SIZE], uint16_t num_hashes, struct index_t location, const uint8_t child_hash[PW_HASH_SIZE], uint8_t result[PW_HASH_SIZE]) { struct sha256_ctx ctx; - SHA256_hw_init(&ctx); + if (DCRYPTO_hw_sha256_init(&ctx) != DCRYPTO_OK) + return PW_ERR_CRYPTO_FAILURE; if (location.v > 0) HASH_update((union hash_ctx *)&ctx, hashes[0], PW_HASH_SIZE * location.v); @@ -1401,6 +1422,7 @@ void compute_hash(const uint8_t hashes[][PW_HASH_SIZE], uint16_t num_hashes, HASH_update((union hash_ctx *)&ctx, hashes[location.v], PW_HASH_SIZE * (num_hashes - location.v)); memcpy(result, HASH_final((union hash_ctx *)&ctx), PW_HASH_SIZE); + return EC_SUCCESS; } /* If a request from older protocol comes, this method should make it diff --git a/common/rma_auth.c b/common/rma_auth.c index 9de2d9984b..01c3ff827e 100644 --- a/common/rma_auth.c +++ b/common/rma_auth.c @@ -75,31 +75,38 @@ static char authcode[RMA_AUTHCODE_BUF_SIZE]; static int tries_left; static uint64_t last_challenge_time; -static void get_hmac_sha256(void *hmac_out, const uint8_t *secret, +static enum ec_error_list get_hmac_sha256(void *hmac_out, const uint8_t *secret, size_t secret_size, const void *ch_ptr, size_t ch_size) { #ifdef USE_DCRYPTO struct hmac_sha256_ctx hmac; - HMAC_SHA256_hw_init(&hmac, secret, secret_size); + if (DCRYPTO_hw_hmac_sha256_init(&hmac, secret, secret_size) != + DCRYPTO_OK) + return EC_ERROR_HW_INTERNAL; HMAC_SHA256_update(&hmac, ch_ptr, ch_size); - memcpy(hmac_out, HMAC_SHA256_hw_final(&hmac), 32); + memcpy(hmac_out, HMAC_SHA256_final(&hmac), 32); #else hmac_SHA256(hmac_out, secret, secret_size, ch_ptr, ch_size); #endif + return EC_SUCCESS; } -static void hash_buffer(void *dest, size_t dest_size, - const void *buffer, size_t buf_size) +static enum ec_error_list hash_buffer(void *dest, size_t dest_size, + const void *buffer, size_t buf_size) { /* We know that the destination is no larger than 32 bytes. */ uint8_t temp[32]; + enum ec_error_list ret; - get_hmac_sha256(temp, buffer, buf_size, buffer, buf_size); + ret = get_hmac_sha256(temp, buffer, buf_size, buffer, buf_size); + if (ret) + return ret; /* Or should we do XOR of the temp modulo dest size? */ memcpy(dest, temp, dest_size); + return EC_SUCCESS; } #ifdef CONFIG_RMA_AUTH_USE_P256 @@ -148,7 +155,8 @@ static int p256_get_pub_key_and_secret(uint8_t pub_key[P256_NBYTES], } /* Did not succeed, rehash the private key and try again. */ - SHA256_hw_init(&sha); + if (DCRYPTO_hw_sha256_init(&sha) != DCRYPTO_OK) + return EC_ERROR_HW_INTERNAL; SHA256_update(&sha, buf, sizeof(buf)); memcpy(buf, SHA256_final(&sha), sizeof(buf)); } @@ -177,10 +185,11 @@ static int p256_get_pub_key_and_secret(uint8_t pub_key[P256_NBYTES], } #endif -void get_rma_device_id(uint8_t rma_device_id[RMA_DEVICE_ID_SIZE]) +int get_rma_device_id(uint8_t rma_device_id[RMA_DEVICE_ID_SIZE]) { uint8_t *chip_unique_id; int chip_unique_id_size = system_get_chip_unique_id(&chip_unique_id); + enum ec_error_list ret; if (chip_unique_id_size < 0) chip_unique_id_size = 0; @@ -198,9 +207,12 @@ void get_rma_device_id(uint8_t rma_device_id[RMA_DEVICE_ID_SIZE]) * rma_challenge:device_id, let's use first few bytes of * its hash. */ - hash_buffer(rma_device_id, RMA_DEVICE_ID_SIZE, - chip_unique_id, chip_unique_id_size); + ret = hash_buffer(rma_device_id, RMA_DEVICE_ID_SIZE, + chip_unique_id, chip_unique_id_size); + if (ret != EC_SUCCESS) + return ret; } + return EC_SUCCESS; } /** @@ -217,6 +229,7 @@ int rma_create_challenge(void) struct board_id bid; uint8_t *cptr = (uint8_t *)&c; uint64_t t; + int ret; /* Clear the current challenge and authcode, if any */ memset(challenge, 0, sizeof(challenge)); @@ -236,9 +249,11 @@ int rma_create_challenge(void) return EC_ERROR_UNKNOWN; memcpy(c.board_id, &bid.type, sizeof(c.board_id)); - get_rma_device_id(c.device_id); + ret = get_rma_device_id(c.device_id); + if (ret != EC_SUCCESS) + return ret; - /* Calculate a new ephemeral key pair and the shared secret. */ + /* Calculate a new ephemeral key pair and the shared secret. */ #ifdef CONFIG_RMA_AUTH_USE_P256 if (p256_get_pub_key_and_secret(c.device_pub_key, secret) != EC_SUCCESS) return EC_ERROR_UNKNOWN; @@ -251,13 +266,15 @@ int rma_create_challenge(void) if (base32_encode(challenge, sizeof(challenge), cptr, 8 * sizeof(c), 9)) return EC_ERROR_UNKNOWN; - /* * Auth code is a truncated HMAC of the ephemeral public key, BoardID, * and DeviceID. Those are all in the right order in the challenge * struct, after the version/key id byte. */ - get_hmac_sha256(temp, secret, sizeof(secret), cptr + 1, sizeof(c) - 1); + ret = get_hmac_sha256(temp, secret, sizeof(secret), cptr + 1, + sizeof(c) - 1); + if (ret != EC_SUCCESS) + return ret; if (base32_encode(authcode, sizeof(authcode), temp, RMA_AUTHCODE_CHARS * 5, 0)) return EC_ERROR_UNKNOWN; |