diff options
author | Yicheng Li <yichengli@chromium.org> | 2019-06-10 11:44:47 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-06-14 06:33:00 +0000 |
commit | b5c6cf246deb0ade98bf3e84999984998b67267e (patch) | |
tree | d63d161ac18640d0cd07923ca714f2eca91da0d9 | |
parent | 2d62dee3a8f32499bab8f4b95b84a9eaeea919dc (diff) | |
download | chrome-ec-b5c6cf246deb0ade98bf3e84999984998b67267e.tar.gz |
fpsensor: Add unit test for derive_encryption_key().
Mock rollback_get_secret() and use it to test derive_encryption_key().
BRANCH=nocturne
BUG=chromium:927095
TEST=make -j buildall
TEST=tested enrollment, matching and multifinger on nocturne DUT
TEST=verified test key vectors by running boringSSL's HKDF
(https://boringssl.googlesource.com/boringssl/+/c0b4c72b6d4c6f4828a373ec454bd646390017d4/crypto/hkdf/)
locally
Change-Id: Ie2f51e4f64788d938e43d0c5c18685d1cfdd001c
Signed-off-by: Yicheng Li <yichengli@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1652495
Reviewed-by: Nicolas Norvez <norvez@chromium.org>
-rw-r--r-- | common/fpsensor/build.mk | 2 | ||||
-rw-r--r-- | common/fpsensor/fpsensor_crypto.c | 2 | ||||
-rw-r--r-- | common/rollback.c | 2 | ||||
-rw-r--r-- | include/fpsensor_crypto.h | 2 | ||||
-rw-r--r-- | test/fpsensor.c | 151 | ||||
-rw-r--r-- | test/test_config.h | 7 |
6 files changed, 159 insertions, 7 deletions
diff --git a/common/fpsensor/build.mk b/common/fpsensor/build.mk index c684dd01b9..14361588f6 100644 --- a/common/fpsensor/build.mk +++ b/common/fpsensor/build.mk @@ -8,7 +8,7 @@ _fpsensor_dir:=$(dir $(lastword $(MAKEFILE_LIST))) all-obj-$(HAS_TASK_FPSENSOR)+=$(_fpsensor_dir)/fpsensor_state.o +all-obj-$(HAS_TASK_FPSENSOR)+=$(_fpsensor_dir)/fpsensor_crypto.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_crypto.c b/common/fpsensor/fpsensor_crypto.c index 5c5715a462..7e31e3f923 100644 --- a/common/fpsensor/fpsensor_crypto.c +++ b/common/fpsensor/fpsensor_crypto.c @@ -16,7 +16,7 @@ #error "fpsensor requires AES, AES_GCM and ROLLBACK_SECRET_SIZE" #endif -int derive_encryption_key(uint8_t *out_key, uint8_t *salt) +int derive_encryption_key(uint8_t *out_key, const uint8_t *salt) { int ret; uint8_t key_buf[SHA256_DIGEST_SIZE]; diff --git a/common/rollback.c b/common/rollback.c index 2f4ba88c1c..ef78146094 100644 --- a/common/rollback.c +++ b/common/rollback.c @@ -137,7 +137,7 @@ int32_t rollback_get_minimum_version(void) } #ifdef CONFIG_ROLLBACK_SECRET_SIZE -int rollback_get_secret(uint8_t *secret) +test_mockable int rollback_get_secret(uint8_t *secret) { struct rollback_data data; uint8_t first; diff --git a/include/fpsensor_crypto.h b/include/fpsensor_crypto.h index 515955fe03..26fe96a328 100644 --- a/include/fpsensor_crypto.h +++ b/include/fpsensor_crypto.h @@ -15,7 +15,7 @@ * @param salt the salt to use in HKDF. * @return EC_RES_SUCCESS on success and EC_RES_ERROR otherwise. */ -int derive_encryption_key(uint8_t *out_key, uint8_t *salt); +int derive_encryption_key(uint8_t *out_key, const uint8_t *salt); /** * Encrypt |plaintext| using AES-GCM128. diff --git a/test/fpsensor.c b/test/fpsensor.c index 82e68ffe94..66ca679b3d 100644 --- a/test/fpsensor.c +++ b/test/fpsensor.c @@ -5,11 +5,37 @@ #include "common.h" #include "ec_commands.h" +#include "fpsensor_crypto.h" #include "fpsensor_state.h" #include "host_command.h" #include "test_util.h" #include "util.h" +static const uint8_t fake_rollback_secret[] = { + 0xcf, 0xe3, 0x23, 0x76, 0x35, 0x04, 0xc2, 0x0f, + 0x0d, 0xb6, 0x02, 0xa9, 0x68, 0xba, 0x2a, 0x61, + 0x86, 0x2a, 0x85, 0xd1, 0xca, 0x09, 0x54, 0x8a, + 0x6b, 0xe2, 0xe3, 0x38, 0xde, 0x5d, 0x59, 0x14, +}; + +static const uint8_t fake_tpm_seed[] = { + 0xd9, 0x71, 0xaf, 0xc4, 0xcd, 0x36, 0xe3, 0x60, + 0xf8, 0x5a, 0xa0, 0xa6, 0x2c, 0xb3, 0xf5, 0xe2, + 0xeb, 0xb9, 0xd8, 0x2f, 0xb5, 0x78, 0x5c, 0x79, + 0x82, 0xce, 0x06, 0x3f, 0xcc, 0x23, 0xb9, 0xe7, +}; + +static int rollback_should_fail; + +/* Mock the rollback for unit test. */ +int rollback_get_secret(uint8_t *secret) +{ + if (rollback_should_fail) + return EC_ERROR_UNKNOWN; + memcpy(secret, fake_rollback_secret, sizeof(fake_rollback_secret)); + return EC_SUCCESS; +} + static int check_fp_enc_status_valid_flags(const uint32_t expected) { int rv; @@ -33,6 +59,122 @@ static int check_fp_enc_status_valid_flags(const uint32_t expected) return EC_RES_SUCCESS; } +test_static int test_derive_encryption_key_failure_seed_not_set(void) +{ + static uint8_t unused_key[SBP_ENC_KEY_LEN]; + static const uint8_t unused_salt[FP_CONTEXT_SALT_BYTES] = { 0 }; + + /* GIVEN that the TPM seed is not set. */ + if (fp_tpm_seed_is_set()) { + ccprintf("%s:%s(): this test should be executed before setting" + " TPM seed.\n", __FILE__, __func__); + return -1; + } + + /* THEN derivation will fail. */ + TEST_ASSERT(derive_encryption_key(unused_key, unused_salt) == + EC_RES_ERROR); + + return EC_SUCCESS; +} + +static int test_derive_encryption_key_raw(const uint32_t *user_id_, + const uint8_t *salt, + const uint8_t *expected_key) +{ + uint8_t key[SBP_ENC_KEY_LEN]; + int rv; + + /* + * |user_id| is a global variable used as "info" in HKDF expand + * in derive_encryption_key(). + */ + memcpy(user_id, user_id_, sizeof(user_id)); + rv = derive_encryption_key(key, salt); + + TEST_ASSERT(rv == EC_RES_SUCCESS); + TEST_ASSERT_ARRAY_EQ(key, expected_key, sizeof(key)); + + return EC_SUCCESS; +} + +test_static int test_derive_encryption_key(void) +{ + /* + * These vectors are obtained by choosing the salt and the user_id + * (used as "info" in HKDF), and running boringSSL's HKDF + * (https://boringssl.googlesource.com/boringssl/+/c0b4c72b6d4c6f4828a373ec454bd646390017d4/crypto/hkdf/) + * locally to get the output key. The IKM used in the run is the + * concatenation of |fake_rollback_secret| and |fake_tpm_seed|. + */ + static const uint32_t user_id1[] = { + 0x608b1b0b, 0xe10d3d24, 0x0bbbe4e6, 0x807b36d9, + 0x2a1f8abc, 0xea38104a, 0x562d9431, 0x64d721c5, + }; + + static const uint8_t salt1[] = { + 0xd0, 0x88, 0x34, 0x15, 0xc0, 0xfa, 0x8e, 0x22, + 0x9f, 0xb4, 0xd5, 0xa9, 0xee, 0xd3, 0x15, 0x19, + }; + + static const uint8_t key1[] = { + 0xdb, 0x49, 0x6e, 0x1b, 0x67, 0x8a, 0x35, 0xc6, + 0xa0, 0x9d, 0xb6, 0xa0, 0x13, 0xf4, 0x21, 0xb3, + }; + + static const uint32_t user_id2[] = { + 0x2546a2ca, 0xf1891f7a, 0x44aad8b8, 0x0d6aac74, + 0x6a4ab846, 0x9c279796, 0x5a72eae1, 0x8276d2a3, + }; + + static const uint8_t salt2[] = { + 0x72, 0x6b, 0xc1, 0xe4, 0x64, 0xd4, 0xff, 0xa2, + 0x5a, 0xac, 0x5b, 0x0b, 0x06, 0x67, 0xe1, 0x53, + }; + + static const uint8_t key2[] = { + 0x8d, 0x53, 0xaf, 0x4c, 0x96, 0xa2, 0xee, 0x46, + 0x9c, 0xe2, 0xe2, 0x6f, 0xe6, 0x66, 0x3d, 0x3a, + }; + + /* + * GIVEN that the TPM seed is set, and reading the rollback secret will + * succeed. + */ + TEST_ASSERT(fp_tpm_seed_is_set() && !rollback_should_fail); + + /* THEN the derivation will succeed. */ + TEST_ASSERT(test_derive_encryption_key_raw(user_id1, salt1, key1) == + EC_SUCCESS); + + TEST_ASSERT(test_derive_encryption_key_raw(user_id2, salt2, key2) == + EC_SUCCESS); + + return EC_SUCCESS; +} + +test_static int test_derive_encryption_key_failure_rollback_fail(void) +{ + static uint8_t unused_key[SBP_ENC_KEY_LEN]; + static const uint8_t unused_salt[FP_CONTEXT_SALT_BYTES] = { 0 }; + + /* GIVEN that reading the rollback secret will fail. */ + rollback_should_fail = 1; + /* THEN the derivation will fail. */ + TEST_ASSERT(derive_encryption_key(unused_key, unused_salt) == + EC_RES_ERROR); + + /* GIVEN that reading the rollback secret will succeed. */ + rollback_should_fail = 0; + /* GIVEN that the TPM seed has been set. */ + TEST_ASSERT(fp_tpm_seed_is_set()); + /* THEN the derivation will succeed. */ + TEST_ASSERT(derive_encryption_key(unused_key, unused_salt) == + EC_RES_SUCCESS); + + return EC_SUCCESS; +} + static int check_fp_tpm_seed_not_set(void) { int rv; @@ -63,7 +205,7 @@ static int set_fp_tpm_seed(void) struct ec_response_fp_encryption_status resp = { 0 }; params.struct_version = FP_TEMPLATE_FORMAT_VERSION; - params.seed[0] = 0; + memcpy(params.seed, fake_tpm_seed, sizeof(fake_tpm_seed)); rv = test_send_host_command(EC_CMD_FP_SEED, 0, ¶ms, sizeof(params), @@ -87,7 +229,7 @@ static int set_fp_tpm_seed(void) return EC_RES_SUCCESS; } -test_static int test_fpsensor(void) +test_static int test_fpsensor_seed(void) { TEST_ASSERT(check_fp_enc_status_valid_flags(FP_ENC_STATUS_SEED_SET) == EC_RES_SUCCESS); @@ -99,7 +241,10 @@ test_static int test_fpsensor(void) void run_test(void) { - RUN_TEST(test_fpsensor); + RUN_TEST(test_derive_encryption_key_failure_seed_not_set); + RUN_TEST(test_fpsensor_seed); + RUN_TEST(test_derive_encryption_key); + RUN_TEST(test_derive_encryption_key_failure_rollback_fail); test_print_result(); } diff --git a/test/test_config.h b/test/test_config.h index d3c7db1895..366b8216d0 100644 --- a/test/test_config.h +++ b/test/test_config.h @@ -75,6 +75,13 @@ #define CONFIG_MAG_CALIBRATE #endif +#ifdef TEST_FPSENSOR +#define CONFIG_AES +#define CONFIG_AES_GCM +#define CONFIG_ROLLBACK_SECRET_SIZE 32 +#define CONFIG_SHA256 +#endif + #if defined(TEST_MOTION_LID) || defined(TEST_MOTION_ANGLE) || \ defined(TEST_MOTION_ANGLE_TABLET) enum sensor_id { |