summaryrefslogtreecommitdiff
path: root/common/fpsensor/fpsensor_crypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/fpsensor/fpsensor_crypto.c')
-rw-r--r--common/fpsensor/fpsensor_crypto.c286
1 files changed, 0 insertions, 286 deletions
diff --git a/common/fpsensor/fpsensor_crypto.c b/common/fpsensor/fpsensor_crypto.c
deleted file mode 100644
index 73d7aca681..0000000000
--- a/common/fpsensor/fpsensor_crypto.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/* Copyright 2019 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 <stdbool.h>
-
-#include "aes.h"
-#include "aes-gcm.h"
-#include "cryptoc/util.h"
-#include "fpsensor_crypto.h"
-#include "fpsensor_private.h"
-#include "fpsensor_state.h"
-#include "rollback.h"
-
-#if !defined(CONFIG_AES) || !defined(CONFIG_AES_GCM) || \
- !defined(CONFIG_ROLLBACK_SECRET_SIZE)
-#error "fpsensor requires AES, AES_GCM and ROLLBACK_SECRET_SIZE"
-#endif
-
-static int get_ikm(uint8_t *ikm)
-{
- int ret;
-
- if (!fp_tpm_seed_is_set()) {
- CPRINTS("Seed hasn't been set.");
- return EC_ERROR_ACCESS_DENIED;
- }
-
- /*
- * The first CONFIG_ROLLBACK_SECRET_SIZE bytes of IKM are read from the
- * anti-rollback blocks.
- */
- ret = rollback_get_secret(ikm);
- if (ret != EC_SUCCESS) {
- CPRINTS("Failed to read rollback secret: %d", ret);
- return EC_ERROR_HW_INTERNAL;
- }
- /*
- * IKM is the concatenation of the rollback secret and the seed from
- * the TPM.
- */
- memcpy(ikm + CONFIG_ROLLBACK_SECRET_SIZE, tpm_seed, sizeof(tpm_seed));
-
- return EC_SUCCESS;
-}
-
-static void hkdf_extract(uint8_t *prk, const uint8_t *salt, size_t salt_size,
- const uint8_t *ikm, size_t ikm_size)
-{
- /*
- * Derive a key with the "extract" step of HKDF
- * https://tools.ietf.org/html/rfc5869#section-2.2
- */
- hmac_SHA256(prk, salt, salt_size, ikm, ikm_size);
-}
-
-static int hkdf_expand_one_step(uint8_t *out_key, size_t out_key_size,
- uint8_t *prk, size_t prk_size,
- uint8_t *info, size_t info_size)
-{
- uint8_t key_buf[SHA256_DIGEST_SIZE];
- uint8_t message_buf[SHA256_DIGEST_SIZE + 1];
-
- if (out_key_size > SHA256_DIGEST_SIZE) {
- CPRINTS("Deriving key material longer than SHA256_DIGEST_SIZE "
- "requires more steps of HKDF expand.");
- return EC_ERROR_INVAL;
- }
-
- if (info_size > SHA256_DIGEST_SIZE) {
- CPRINTS("Info size too big for HKDF.");
- return EC_ERROR_INVAL;
- }
-
- memcpy(message_buf, info, info_size);
- /* 1 step, set the counter byte to 1. */
- message_buf[info_size] = 0x01;
- hmac_SHA256(key_buf, prk, prk_size, message_buf, info_size + 1);
-
- memcpy(out_key, key_buf, out_key_size);
- always_memset(key_buf, 0, sizeof(key_buf));
-
- return EC_SUCCESS;
-}
-
-int hkdf_expand(uint8_t *out_key, size_t L, const uint8_t *prk,
- size_t prk_size, const uint8_t *info, size_t info_size)
-{
- /*
- * "Expand" step of HKDF.
- * https://tools.ietf.org/html/rfc5869#section-2.3
- */
-#define HASH_LEN SHA256_DIGEST_SIZE
- uint8_t count = 1;
- const uint8_t *T = out_key;
- size_t T_len = 0;
- uint8_t T_buffer[HASH_LEN];
- /* Number of blocks. */
- const uint32_t N = DIV_ROUND_UP(L, HASH_LEN);
- uint8_t info_buffer[HASH_LEN + HKDF_MAX_INFO_SIZE + sizeof(count)];
- bool arguments_valid = false;
-
- if (out_key == NULL || L == 0)
- CPRINTS("HKDF expand: output buffer not valid.");
- else if (prk == NULL)
- CPRINTS("HKDF expand: prk is NULL.");
- else if (info == NULL && info_size > 0)
- CPRINTS("HKDF expand: info is NULL but info size is not zero.");
- else if (info_size > HKDF_MAX_INFO_SIZE)
- CPRINTF("HKDF expand: info size larger than %d bytes.\n",
- HKDF_MAX_INFO_SIZE);
- else if (N > HKDF_SHA256_MAX_BLOCK_COUNT)
- CPRINTS("HKDF expand: output key size too large.");
- else
- arguments_valid = true;
-
- if (!arguments_valid)
- return EC_ERROR_INVAL;
-
- while (L > 0) {
- const size_t block_size = L < HASH_LEN ? L : HASH_LEN;
-
- memcpy(info_buffer, T, T_len);
- memcpy(info_buffer + T_len, info, info_size);
- info_buffer[T_len + info_size] = count;
- hmac_SHA256(T_buffer, prk, prk_size, info_buffer,
- T_len + info_size + sizeof(count));
- memcpy(out_key, T_buffer, block_size);
-
- T += T_len;
- T_len = HASH_LEN;
- count++;
- out_key += block_size;
- L -= block_size;
- }
- always_memset(T_buffer, 0, sizeof(T_buffer));
- always_memset(info_buffer, 0, sizeof(info_buffer));
- return EC_SUCCESS;
-#undef HASH_LEN
-}
-
-int derive_positive_match_secret(uint8_t *output,
- const uint8_t *input_positive_match_salt)
-{
- int ret;
- uint8_t ikm[CONFIG_ROLLBACK_SECRET_SIZE + sizeof(tpm_seed)];
- uint8_t prk[SHA256_DIGEST_SIZE];
- static const char info_prefix[] = "positive_match_secret for user ";
- uint8_t info[sizeof(info_prefix) - 1 + sizeof(user_id)];
-
- if (bytes_are_trivial(input_positive_match_salt,
- FP_POSITIVE_MATCH_SALT_BYTES)) {
- CPRINTS("Failed to derive positive match secret: "
- "salt bytes are trivial.");
- return EC_ERROR_INVAL;
- }
-
- ret = get_ikm(ikm);
- if (ret != EC_SUCCESS) {
- CPRINTS("Failed to get IKM: %d", ret);
- return ret;
- }
-
- /* "Extract" step of HKDF. */
- hkdf_extract(prk, input_positive_match_salt,
- FP_POSITIVE_MATCH_SALT_BYTES, ikm, sizeof(ikm));
- always_memset(ikm, 0, sizeof(ikm));
-
- memcpy(info, info_prefix, strlen(info_prefix));
- memcpy(info + strlen(info_prefix), user_id, sizeof(user_id));
-
- /* "Expand" step of HKDF. */
- ret = hkdf_expand(output, FP_POSITIVE_MATCH_SECRET_BYTES, prk,
- sizeof(prk), info, sizeof(info));
- always_memset(prk, 0, sizeof(prk));
-
- /* Check that secret is not full of 0x00 or 0xff. */
- if (bytes_are_trivial(output, FP_POSITIVE_MATCH_SECRET_BYTES)) {
- CPRINTS("Failed to derive positive match secret: "
- "derived secret bytes are trivial.");
- ret = EC_ERROR_HW_INTERNAL;
- }
- return ret;
-}
-
-int derive_encryption_key(uint8_t *out_key, const uint8_t *salt)
-{
- int ret;
- uint8_t ikm[CONFIG_ROLLBACK_SECRET_SIZE + sizeof(tpm_seed)];
- uint8_t prk[SHA256_DIGEST_SIZE];
-
- BUILD_ASSERT(SBP_ENC_KEY_LEN <= SHA256_DIGEST_SIZE);
- BUILD_ASSERT(SBP_ENC_KEY_LEN <= CONFIG_ROLLBACK_SECRET_SIZE);
- BUILD_ASSERT(sizeof(user_id) == SHA256_DIGEST_SIZE);
-
- ret = get_ikm(ikm);
- if (ret != EC_SUCCESS) {
- CPRINTS("Failed to get IKM: %d", ret);
- return ret;
- }
-
- /* "Extract step of HKDF. */
- hkdf_extract(prk, salt, FP_CONTEXT_ENCRYPTION_SALT_BYTES, ikm,
- sizeof(ikm));
- always_memset(ikm, 0, sizeof(ikm));
-
- /*
- * Only 1 "expand" step of HKDF since the size of the "info" context
- * (user_id in our case) is exactly SHA256_DIGEST_SIZE.
- * https://tools.ietf.org/html/rfc5869#section-2.3
- */
- ret = hkdf_expand_one_step(out_key, SBP_ENC_KEY_LEN, prk, sizeof(prk),
- (uint8_t *)user_id, sizeof(user_id));
- always_memset(prk, 0, sizeof(prk));
-
- return ret;
-}
-
-int aes_gcm_encrypt(const uint8_t *key, int key_size,
- const uint8_t *plaintext,
- uint8_t *ciphertext, int text_size,
- const uint8_t *nonce, int nonce_size,
- uint8_t *tag, int tag_size)
-{
- int res;
- AES_KEY aes_key;
- GCM128_CONTEXT ctx;
-
- if (nonce_size != FP_CONTEXT_NONCE_BYTES) {
- CPRINTS("Invalid nonce size %d bytes", nonce_size);
- return EC_ERROR_INVAL;
- }
-
- res = AES_set_encrypt_key(key, 8 * key_size, &aes_key);
- if (res) {
- CPRINTS("Failed to set encryption key: %d", res);
- return EC_ERROR_UNKNOWN;
- }
- CRYPTO_gcm128_init(&ctx, &aes_key, (block128_f)AES_encrypt, 0);
- CRYPTO_gcm128_setiv(&ctx, &aes_key, nonce, nonce_size);
- /* CRYPTO functions return 1 on success, 0 on error. */
- res = CRYPTO_gcm128_encrypt(&ctx, &aes_key, plaintext, ciphertext,
- text_size);
- if (!res) {
- CPRINTS("Failed to encrypt: %d", res);
- return EC_ERROR_UNKNOWN;
- }
- CRYPTO_gcm128_tag(&ctx, tag, tag_size);
- return EC_SUCCESS;
-}
-
-int aes_gcm_decrypt(const uint8_t *key, int key_size, uint8_t *plaintext,
- const uint8_t *ciphertext, int text_size,
- const uint8_t *nonce, int nonce_size,
- const uint8_t *tag, int tag_size)
-{
- int res;
- AES_KEY aes_key;
- GCM128_CONTEXT ctx;
-
- if (nonce_size != FP_CONTEXT_NONCE_BYTES) {
- CPRINTS("Invalid nonce size %d bytes", nonce_size);
- return EC_ERROR_INVAL;
- }
-
- res = AES_set_encrypt_key(key, 8 * key_size, &aes_key);
- if (res) {
- CPRINTS("Failed to set decryption key: %d", res);
- return EC_ERROR_UNKNOWN;
- }
- CRYPTO_gcm128_init(&ctx, &aes_key, (block128_f)AES_encrypt, 0);
- CRYPTO_gcm128_setiv(&ctx, &aes_key, nonce, nonce_size);
- /* CRYPTO functions return 1 on success, 0 on error. */
- res = CRYPTO_gcm128_decrypt(&ctx, &aes_key, ciphertext, plaintext,
- text_size);
- if (!res) {
- CPRINTS("Failed to decrypt: %d", res);
- return EC_ERROR_UNKNOWN;
- }
- res = CRYPTO_gcm128_finish(&ctx, tag, tag_size);
- if (!res) {
- CPRINTS("Found incorrect tag: %d", res);
- return EC_ERROR_UNKNOWN;
- }
- return EC_SUCCESS;
-}