diff options
author | Nicolas Norvez <norvez@chromium.org> | 2018-10-30 17:52:23 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-11-02 00:26:29 -0700 |
commit | f603c09ba1ed5acc1011bd3227bfc05d45ce75db (patch) | |
tree | ca81e12881846b4c32c9f79a2fab0509b5428b94 | |
parent | cad8fea56739f0050272426b7481db79cae07d73 (diff) | |
download | chrome-ec-f603c09ba1ed5acc1011bd3227bfc05d45ce75db.tar.gz |
fpsensor: add TPM seed to Input Key Material
Make the encryption key also depend on data held by the TPM. Append that
seed to the anti-rollback IKM and feed that to HKDF-Extract when
deriving the encryption key.
The seed must be set once, and can't be overwritten.
Bump the template format version to 3, since it's not compatible with
previously enrolled templates.
Also add the corresponding command to ectool (fpseed).
BRANCH=nocturne
BUG=b:117909326
TEST=upload templates without having set a seed -> fails as expected
TEST=enroll finger without having set a seed -> fails as expected
TEST=set a seed twice -> 2nd time fails as expected
TEST=set seed, enroll finger -> success.
TEST=upload templates after having set the seed -> success.
TEST=set a different seed, upload templates -> fails as expected
TEST=reboot EC, reset original seed, upload templates -> success
TEST=load templates enrolled with format version=2 -> fails as expected
Change-Id: I64fd99f9d317d1fcab4a58a679be64cf8a425b00
Signed-off-by: Nicolas Norvez <norvez@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1309050
Reviewed-by: Adam Langley <agl@chromium.org>
Reviewed-by: Nicolas Boichat <drinkcat@chromium.org>
-rw-r--r-- | common/fpsensor.c | 49 | ||||
-rw-r--r-- | include/ec_commands.h | 15 | ||||
-rw-r--r-- | util/ectool.c | 26 |
3 files changed, 83 insertions, 7 deletions
diff --git a/common/fpsensor.c b/common/fpsensor.c index dec669ec9a..d2f4a6297f 100644 --- a/common/fpsensor.c +++ b/common/fpsensor.c @@ -42,7 +42,7 @@ #define FP_MAX_FINGER_COUNT 0 #endif #define SBP_ENC_KEY_LEN 16 -#define FP_TEMPLATE_FORMAT_VERSION 2 +#define FP_TEMPLATE_FORMAT_VERSION 3 #define FP_ALGORITHM_ENCRYPTED_TEMPLATE_SIZE \ (FP_ALGORITHM_TEMPLATE_SIZE + \ sizeof(struct ec_fp_template_encryption_metadata)) @@ -76,6 +76,10 @@ static uint32_t templ_dirty; static uint32_t user_id[FP_CONTEXT_USERID_WORDS]; /* Ready to encrypt a template. */ static timestamp_t encryption_deadline; +/* Part of the IKM used to derive encryption keys received from the TPM. */ +static uint8_t tpm_seed[FP_CONTEXT_TPM_BYTES]; +/* Flag indicating whether the seed has been initialised or not. */ +static int fp_tpm_seed_is_set; #define CPRINTF(format, args...) cprintf(CC_FP, format, ## args) #define CPRINTS(format, args...) cprints(CC_FP, format, ## args) @@ -348,26 +352,39 @@ 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 rb_secret[CONFIG_ROLLBACK_SECRET_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); - ret = rollback_get_secret(rb_secret); + 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, rb_secret, - sizeof(rb_secret)); - memset(rb_secret, 0, sizeof(rb_secret)); + 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 @@ -782,6 +799,26 @@ static int fp_command_context(struct host_cmd_handler_args *args) } DECLARE_HOST_COMMAND(EC_CMD_FP_CONTEXT, fp_command_context, EC_VER_MASK(0)); +static int fp_command_tpm_seed(struct host_cmd_handler_args *args) +{ + const struct ec_params_fp_seed *params = args->params; + + if (params->struct_version != FP_TEMPLATE_FORMAT_VERSION) { + CPRINTS("Invalid seed format %d", params->struct_version); + return EC_RES_INVALID_PARAM; + } + + if (fp_tpm_seed_is_set) { + CPRINTS("Seed has already been set."); + return EC_RES_ACCESS_DENIED; + } + memcpy(tpm_seed, params->seed, sizeof(tpm_seed)); + fp_tpm_seed_is_set = 1; + + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_FP_SEED, fp_command_tpm_seed, EC_VER_MASK(0)); + #ifdef CONFIG_CMD_FPSENSOR_DEBUG /* --- Debug console commands --- */ diff --git a/include/ec_commands.h b/include/ec_commands.h index d15528c6a5..d26f159bde 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -5071,10 +5071,11 @@ struct __ec_align4 ec_response_fp_info { #define FP_CONTEXT_USERID_WORDS (32 / sizeof(uint32_t)) #define FP_CONTEXT_TAG_BYTES 16 #define FP_CONTEXT_SALT_BYTES 16 +#define FP_CONTEXT_TPM_BYTES 32 struct ec_fp_template_encryption_metadata { /* - * Version of the structure format (N=1). + * Version of the structure format (N=3). */ uint16_t struct_version; /* Reserved bytes, set to 0. */ @@ -5134,6 +5135,18 @@ struct __ec_align2 ec_response_fp_stats { int8_t template_matched; }; +#define EC_CMD_FP_SEED 0x0408 +struct __ec_align4 ec_params_fp_seed { + /* + * Version of the structure format (N=3). + */ + uint16_t struct_version; + /* Reserved bytes, set to 0. */ + uint16_t reserved; + /* Seed from the TPM. */ + uint8_t seed[FP_CONTEXT_TPM_BYTES]; +}; + /*****************************************************************************/ /* Touchpad MCU commands: range 0x0500-0x05FF */ diff --git a/util/ectool.c b/util/ectool.c index 4cb4b71623..3d3cf21693 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -134,6 +134,8 @@ const char help_str[] = " Prints information about the Fingerprint sensor\n" " fpmode [capture|deepsleep|fingerdown|fingerup]\n" " Configure/Read the fingerprint sensor current mode\n" + " fpseed\n" + " Sets the value of the TPM seed.\n" " fpstats\n" " Prints timing statisitcs relating to capture and matching\n" " fptemplate [<infile>|<index 0..2>]\n" @@ -1467,6 +1469,29 @@ int cmd_fp_mode(int argc, char *argv[]) return 0; } +int cmd_fp_seed(int argc, char *argv[]) +{ + struct ec_params_fp_seed p; + const char *seed = argv[1]; + int rv; + + if (argc == 1) { + printf("Missing seed argument.\n"); + return 1; + } + if (strlen(seed) != FP_CONTEXT_TPM_BYTES) { + printf("Invalid seed '%s' is %zd bytes long instead of %d.\n", + seed, strlen(seed), FP_CONTEXT_TPM_BYTES); + return 1; + } + printf("Setting seed '%s'\n", seed); + p.struct_version = 3; + memcpy(p.seed, seed, FP_CONTEXT_TPM_BYTES); + + rv = ec_command(EC_CMD_FP_SEED, 0, &p, sizeof(p), NULL, 0); + return rv; +} + int cmd_fp_stats(int argc, char *argv[]) { struct ec_response_fp_stats r; @@ -8351,6 +8376,7 @@ const struct command commands[] = { {"fpframe", cmd_fp_frame}, {"fpinfo", cmd_fp_info}, {"fpmode", cmd_fp_mode}, + {"fpseed", cmd_fp_seed}, {"fpstats", cmd_fp_stats}, {"fptemplate", cmd_fp_template}, {"gpioget", cmd_gpio_get}, |