diff options
author | Yicheng Li <yichengli@chromium.org> | 2019-06-06 18:27:42 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-06-13 19:13:57 +0000 |
commit | 35d0e17de6d76699c4fac850d39ed4c4b5488cb2 (patch) | |
tree | c527fec2dd43909f444f6f12a2d9c8336ce9720a /common | |
parent | 2fb0ff65ecac63829d93d1d9ae0994ebf7a5883d (diff) | |
download | chrome-ec-35d0e17de6d76699c4fac850d39ed4c4b5488cb2.tar.gz |
fpsensor: Move crypto-related code to fpsensor_crypto.c
Move crypto-related code to common/fpsensor/fpsensor_state.c. This
facilitates unittesting because we can control whether to link in
crypto-related code, and also facilitates mocking the encryption
engine.
BRANCH=nocturne
BUG=chromium:927095
TEST=ran unittests
TEST=tested enrollment, matching and multifinger on DUT nocturne
Change-Id: I5bffc1460cbe2c9e3d6294ea5fff41f14019f0eb
Signed-off-by: Yicheng Li <yichengli@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1648922
Reviewed-by: Nicolas Norvez <norvez@chromium.org>
Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Diffstat (limited to 'common')
-rw-r--r-- | common/fpsensor/build.mk | 1 | ||||
-rw-r--r-- | common/fpsensor/fpsensor.c | 139 | ||||
-rw-r--r-- | common/fpsensor/fpsensor_crypto.c | 142 | ||||
-rw-r--r-- | common/fpsensor/fpsensor_private.h | 14 | ||||
-rw-r--r-- | common/fpsensor/fpsensor_state.c | 4 |
5 files changed, 162 insertions, 138 deletions
diff --git a/common/fpsensor/build.mk b/common/fpsensor/build.mk index 3b03152b05..c684dd01b9 100644 --- a/common/fpsensor/build.mk +++ b/common/fpsensor/build.mk @@ -10,4 +10,5 @@ _fpsensor_dir:=$(dir $(lastword $(MAKEFILE_LIST))) all-obj-$(HAS_TASK_FPSENSOR)+=$(_fpsensor_dir)/fpsensor_state.o ifneq ($(CONFIG_SPI_FP_PORT),) all-obj-$(HAS_TASK_FPSENSOR)+=$(_fpsensor_dir)/fpsensor.o +all-obj-$(HAS_TASK_FPSENSOR)+=$(_fpsensor_dir)/fpsensor_crypto.o endif diff --git a/common/fpsensor/fpsensor.c b/common/fpsensor/fpsensor.c index e0fe146949..f1b31e43c7 100644 --- a/common/fpsensor/fpsensor.c +++ b/common/fpsensor/fpsensor.c @@ -3,21 +3,19 @@ * found in the LICENSE file. */ -#include "aes.h" -#include "aes-gcm.h" #include "atomic.h" #include "clock.h" #include "common.h" #include "console.h" #include "ec_commands.h" #include "fpsensor.h" +#include "fpsensor_crypto.h" +#include "fpsensor_private.h" #include "fpsensor_state.h" #include "gpio.h" #include "host_command.h" #include "link_defs.h" #include "mkbp_event.h" -#include "rollback.h" -#include "sha256.h" #include "spi.h" #include "system.h" #include "task.h" @@ -26,17 +24,13 @@ #include "util.h" #include "watchdog.h" -#if !defined(CONFIG_AES) || !defined(CONFIG_AES_GCM) || \ - !defined(CONFIG_ROLLBACK_SECRET_SIZE) || !defined(CONFIG_RNG) -#error "fpsensor requires AES, AES_GCM, ROLLBACK_SECRET_SIZE and RNG" +#if !defined(CONFIG_RNG) +#error "fpsensor requires RNG" #endif /* Ready to encrypt a template. */ static timestamp_t encryption_deadline; -#define CPRINTF(format, args...) cprintf(CC_FP, format, ## args) -#define CPRINTS(format, args...) cprints(CC_FP, format, ## args) - /* raw image offset inside the acquired frame */ #ifndef FP_SENSOR_IMAGE_OFFSET #define FP_SENSOR_IMAGE_OFFSET 0 @@ -295,62 +289,6 @@ void fp_task(void) #endif /* !HAVE_FP_PRIVATE_DRIVER */ } -static int derive_encryption_key(uint8_t *out_key, uint8_t *salt) -{ - int ret; - uint8_t key_buf[SHA256_DIGEST_SIZE]; - uint8_t prk[SHA256_DIGEST_SIZE]; - uint8_t message[sizeof(user_id) + 1]; - uint8_t ikm[CONFIG_ROLLBACK_SECRET_SIZE + sizeof(tpm_seed)]; - - 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); - - if (!fp_tpm_seed_is_set()) { - CPRINTS("Seed hasn't been set."); - return EC_RES_ERROR; - } - - /* - * 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_RES_ERROR; - } - /* - * 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)); - - /* - * Derive a key with the "extract" step of HKDF - * https://tools.ietf.org/html/rfc5869#section-2.2 - */ - hmac_SHA256(prk, salt, FP_CONTEXT_SALT_BYTES, ikm, sizeof(ikm)); - 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 - */ - memcpy(message, user_id, sizeof(user_id)); - /* 1 step, set the counter byte to 1. */ - message[sizeof(message) - 1] = 0x01; - hmac_SHA256(key_buf, prk, sizeof(prk), message, sizeof(message)); - memset(prk, 0, sizeof(prk)); - - memcpy(out_key, key_buf, SBP_ENC_KEY_LEN); - memset(key_buf, 0, sizeof(key_buf)); - - return EC_RES_SUCCESS; -} - static int fp_command_passthru(struct host_cmd_handler_args *args) { const struct ec_params_fp_passthru *params = args->params; @@ -408,75 +346,6 @@ DECLARE_HOST_COMMAND(EC_CMD_FP_INFO, fp_command_info, BUILD_ASSERT(FP_CONTEXT_NONCE_BYTES == 12); -static int aes_gcm_encrypt(const uint8_t *key, int key_size, - const uint8_t *plaintext, - uint8_t *ciphertext, int plaintext_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_RES_INVALID_PARAM; - } - - res = AES_set_encrypt_key(key, 8 * key_size, &aes_key); - if (res) { - CPRINTS("Failed to set encryption key: %d", res); - return EC_RES_ERROR; - } - 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, - plaintext_size); - if (!res) { - CPRINTS("Failed to encrypt: %d", res); - return EC_RES_ERROR; - } - CRYPTO_gcm128_tag(&ctx, tag, tag_size); - return EC_RES_SUCCESS; -} - -static int aes_gcm_decrypt(const uint8_t *key, int key_size, uint8_t *plaintext, - const uint8_t *ciphertext, int plaintext_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_RES_INVALID_PARAM; - } - - res = AES_set_encrypt_key(key, 8 * key_size, &aes_key); - if (res) { - CPRINTS("Failed to set decryption key: %d", res); - return EC_RES_ERROR; - } - 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, - plaintext_size); - if (!res) { - CPRINTS("Failed to decrypt: %d", res); - return EC_RES_ERROR; - } - res = CRYPTO_gcm128_finish(&ctx, tag, tag_size); - if (!res) { - CPRINTS("Found incorrect tag: %d", res); - return EC_RES_ERROR; - } - return EC_RES_SUCCESS; -} - static int validate_fp_buffer_offset(const uint32_t buffer_size, const uint32_t offset, const uint32_t size) { diff --git a/common/fpsensor/fpsensor_crypto.c b/common/fpsensor/fpsensor_crypto.c new file mode 100644 index 0000000000..5c5715a462 --- /dev/null +++ b/common/fpsensor/fpsensor_crypto.c @@ -0,0 +1,142 @@ +/* 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 "aes.h" +#include "aes-gcm.h" +#include "fpsensor_crypto.h" +#include "fpsensor_private.h" +#include "fpsensor_state.h" +#include "rollback.h" +#include "sha256.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 + +int derive_encryption_key(uint8_t *out_key, uint8_t *salt) +{ + int ret; + uint8_t key_buf[SHA256_DIGEST_SIZE]; + uint8_t prk[SHA256_DIGEST_SIZE]; + uint8_t message[sizeof(user_id) + 1]; + uint8_t ikm[CONFIG_ROLLBACK_SECRET_SIZE + sizeof(tpm_seed)]; + + 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); + + if (!fp_tpm_seed_is_set()) { + CPRINTS("Seed hasn't been set."); + return EC_RES_ERROR; + } + + /* + * 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_RES_ERROR; + } + /* + * 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)); + + /* + * Derive a key with the "extract" step of HKDF + * https://tools.ietf.org/html/rfc5869#section-2.2 + */ + hmac_SHA256(prk, salt, FP_CONTEXT_SALT_BYTES, ikm, sizeof(ikm)); + 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 + */ + memcpy(message, user_id, sizeof(user_id)); + /* 1 step, set the counter byte to 1. */ + message[sizeof(message) - 1] = 0x01; + hmac_SHA256(key_buf, prk, sizeof(prk), message, sizeof(message)); + memset(prk, 0, sizeof(prk)); + + memcpy(out_key, key_buf, SBP_ENC_KEY_LEN); + memset(key_buf, 0, sizeof(key_buf)); + + return EC_RES_SUCCESS; +} + +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_RES_INVALID_PARAM; + } + + res = AES_set_encrypt_key(key, 8 * key_size, &aes_key); + if (res) { + CPRINTS("Failed to set encryption key: %d", res); + return EC_RES_ERROR; + } + 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_RES_ERROR; + } + CRYPTO_gcm128_tag(&ctx, tag, tag_size); + return EC_RES_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_RES_INVALID_PARAM; + } + + res = AES_set_encrypt_key(key, 8 * key_size, &aes_key); + if (res) { + CPRINTS("Failed to set decryption key: %d", res); + return EC_RES_ERROR; + } + 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_RES_ERROR; + } + res = CRYPTO_gcm128_finish(&ctx, tag, tag_size); + if (!res) { + CPRINTS("Found incorrect tag: %d", res); + return EC_RES_ERROR; + } + return EC_RES_SUCCESS; +} diff --git a/common/fpsensor/fpsensor_private.h b/common/fpsensor/fpsensor_private.h new file mode 100644 index 0000000000..fb97fb3bfd --- /dev/null +++ b/common/fpsensor/fpsensor_private.h @@ -0,0 +1,14 @@ +/* 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. + */ + +/* Internal header file for common/fpsensor directory */ + +#ifndef __CROS_EC_FPSENSOR_PRIVATE_H +#define __CROS_EC_FPSENSOR_PRIVATE_H + +#define CPRINTF(format, args...) cprintf(CC_FP, format, ## args) +#define CPRINTS(format, args...) cprints(CC_FP, format, ## args) + +#endif /* __CROS_EC_FPSENSOR_PRIVATE_H */ diff --git a/common/fpsensor/fpsensor_state.c b/common/fpsensor/fpsensor_state.c index f8016b49e9..4e634e2785 100644 --- a/common/fpsensor/fpsensor_state.c +++ b/common/fpsensor/fpsensor_state.c @@ -6,15 +6,13 @@ #include "common.h" #include "ec_commands.h" #include "fpsensor.h" +#include "fpsensor_private.h" #include "fpsensor_state.h" #include "host_command.h" #include "system.h" #include "task.h" #include "util.h" -#define CPRINTF(format, args...) cprintf(CC_FP, format, ## args) -#define CPRINTS(format, args...) cprints(CC_FP, format, ## args) - /* Last acquired frame (aligned as it is used by arbitrary binary libraries) */ uint8_t fp_buffer[FP_SENSOR_IMAGE_SIZE] FP_FRAME_SECTION __aligned(4); /* Fingers templates for the current user */ |