summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYicheng Li <yichengli@chromium.org>2019-09-24 16:18:38 -0700
committerCommit Bot <commit-bot@chromium.org>2019-10-09 21:30:42 +0000
commitcb860c94d5b562c6f6833dd60bcf2920713bb9b9 (patch)
treeed5d2f024083a672773d64bfbba4a902281abbdd
parent18bc5eba805ae2bb140373ba763acd75e20f8805 (diff)
downloadchrome-ec-cb860c94d5b562c6f6833dd60bcf2920713bb9b9.tar.gz
fpsensor: Enable positive match secret and positive match salt on enrollment.
On enrollment success, generate new positive_match_salt and send it as part of the encrypted blob. Also enable positive match secret to be read. The positive_match_salt is used to derive positive_match_secret and is different from the encryption salt for encrypting the templates. The positive_match_salt needs to be sent to biod and stored with templates because it needs to be re-uploaded to FPMCU the next time the user logs in. The positive match secret needs to be sent to biod so that it knows what to compare against at a match. BRANCH=nocturne BUG=chromium:927095 TEST=make -j buildall TEST=tested enrollment, matching and multifinger on DUT nocturne Change-Id: I3e44a972ee17c5a93bddd52340f8f2249836463a Signed-off-by: Yicheng Li <yichengli@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1828058 Reviewed-by: Nicolas Norvez <norvez@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
-rw-r--r--common/fpsensor/fpsensor.c87
-rw-r--r--common/fpsensor/fpsensor_crypto.c3
-rw-r--r--common/fpsensor/fpsensor_state.c2
-rw-r--r--include/ec_commands.h9
-rw-r--r--include/fpsensor_state.h4
-rw-r--r--test/fpsensor.c6
6 files changed, 88 insertions, 23 deletions
diff --git a/common/fpsensor/fpsensor.c b/common/fpsensor/fpsensor.c
index 5377b526b6..486d2f4d12 100644
--- a/common/fpsensor/fpsensor.c
+++ b/common/fpsensor/fpsensor.c
@@ -97,6 +97,10 @@ static uint32_t fp_process_enroll(void)
int percent = 0;
int res;
+ if (template_newly_enrolled != FP_NO_SUCH_TEMPLATE)
+ CPRINTS("Warning: previously enrolled template has not been "
+ "read yet.");
+
/* begin/continue enrollment */
CPRINTS("[%d]Enrolling ...", templ_valid);
res = fp_finger_enroll(fp_buffer, &percent);
@@ -110,10 +114,9 @@ static uint32_t fp_process_enroll(void)
if (res) {
res = EC_MKBP_FP_ERR_ENROLL_INTERNAL;
} else {
- init_trng();
- rand_bytes(fp_positive_match_salt[templ_valid],
- FP_POSITIVE_MATCH_SALT_BYTES);
- exit_trng();
+ template_newly_enrolled = templ_valid;
+ fp_enable_positive_match_secret(templ_valid,
+ &positive_match_secret_state);
templ_valid++;
}
sensor_mode &= ~FP_MODE_ENROLL_SESSION;
@@ -407,6 +410,13 @@ static enum ec_status fp_command_frame(struct host_cmd_handler_args *args)
if (!offset) {
/* Host has requested the first chunk, do the encryption. */
timestamp_t now = get_time();
+ /* Encrypted template is after the metadata. */
+ uint8_t *encrypted_template = fp_enc_buffer + sizeof(*enc_info);
+ /* Positive match salt is after the template. */
+ uint8_t *positive_match_salt =
+ encrypted_template + sizeof(fp_template[0]);
+ size_t encrypted_blob_size = sizeof(fp_template[0]) +
+ sizeof(fp_positive_match_salt[0]);
/* b/114160734: Not more than 1 encrypted message per second. */
if (!timestamp_expired(encryption_deadline, &now))
@@ -414,23 +424,50 @@ static enum ec_status fp_command_frame(struct host_cmd_handler_args *args)
encryption_deadline.val = now.val + (1 * SECOND);
memset(fp_enc_buffer, 0, sizeof(fp_enc_buffer));
- /* The beginning of the buffer contains nonce/salt/tag. */
+ /*
+ * The beginning of the buffer contains nonce, encryption_salt
+ * and tag.
+ */
enc_info = (void *)fp_enc_buffer;
enc_info->struct_version = FP_TEMPLATE_FORMAT_VERSION;
init_trng();
rand_bytes(enc_info->nonce, FP_CONTEXT_NONCE_BYTES);
- rand_bytes(enc_info->salt, FP_CONTEXT_SALT_BYTES);
+ rand_bytes(enc_info->encryption_salt,
+ FP_CONTEXT_ENCRYPTION_SALT_BYTES);
exit_trng();
- ret = derive_encryption_key(key, enc_info->salt);
+ if (fgr == template_newly_enrolled) {
+ /*
+ * Newly enrolled templates need new positive match
+ * salt, new positive match secret and new validation
+ * value.
+ */
+ template_newly_enrolled = FP_NO_SUCH_TEMPLATE;
+ init_trng();
+ rand_bytes(fp_positive_match_salt[fgr],
+ FP_POSITIVE_MATCH_SALT_BYTES);
+ exit_trng();
+ }
+
+ ret = derive_encryption_key(key, enc_info->encryption_salt);
if (ret != EC_SUCCESS) {
CPRINTS("fgr%d: Failed to derive key", fgr);
return EC_RES_UNAVAILABLE;
}
- ret = aes_gcm_encrypt(key, SBP_ENC_KEY_LEN, fp_template[fgr],
- fp_enc_buffer + sizeof(*enc_info),
- sizeof(fp_template[0]),
+ /*
+ * Copy the payload to |fp_enc_buffer| where it will be
+ * encrypted in-place.
+ */
+ memcpy(encrypted_template, fp_template[fgr],
+ sizeof(fp_template[0]));
+ memcpy(positive_match_salt, fp_positive_match_salt[fgr],
+ sizeof(fp_positive_match_salt[0]));
+
+ /* Encrypt the secret blob in-place. */
+ ret = aes_gcm_encrypt(key, SBP_ENC_KEY_LEN, encrypted_template,
+ encrypted_template,
+ encrypted_blob_size,
enc_info->nonce, FP_CONTEXT_NONCE_BYTES,
enc_info->tag, FP_CONTEXT_TAG_BYTES);
always_memset(key, 0, sizeof(key));
@@ -471,6 +508,10 @@ DECLARE_HOST_COMMAND(EC_CMD_FP_STATS, fp_command_stats, EC_VER_MASK(0));
static int validate_template_format(
struct ec_fp_template_encryption_metadata *enc_info)
{
+ if (enc_info->struct_version == 3 && FP_TEMPLATE_FORMAT_VERSION == 4)
+ /* The host requested migration to v4. */
+ return EC_RES_SUCCESS;
+
if (enc_info->struct_version != FP_TEMPLATE_FORMAT_VERSION) {
CPRINTS("Invalid template format %d", enc_info->struct_version);
return EC_RES_INVALID_PARAM;
@@ -503,27 +544,39 @@ static enum ec_status fp_command_template(struct host_cmd_handler_args *args)
memcpy(&fp_enc_buffer[offset], params->data, size);
if (xfer_complete) {
+ /* Encrypted template is after the metadata. */
+ uint8_t *encrypted_template = fp_enc_buffer + sizeof(*enc_info);
+ /* Positive match salt is after the template. */
+ uint8_t *positive_match_salt =
+ encrypted_template + sizeof(fp_template[0]);
+ size_t encrypted_blob_size = sizeof(fp_template[0]) +
+ sizeof(fp_positive_match_salt[0]);
+
/*
* The complete encrypted template has been received, start
* decryption.
*/
fp_clear_finger_context(idx);
- /* The beginning of the buffer contains nonce/salt/tag. */
+ /*
+ * The beginning of the buffer contains nonce, encryption_salt
+ * and tag.
+ */
enc_info = (void *)fp_enc_buffer;
ret = validate_template_format(enc_info);
if (ret != EC_RES_SUCCESS) {
CPRINTS("fgr%d: Template format not supported", idx);
return EC_RES_INVALID_PARAM;
}
- ret = derive_encryption_key(key, enc_info->salt);
+ ret = derive_encryption_key(key, enc_info->encryption_salt);
if (ret != EC_SUCCESS) {
CPRINTS("fgr%d: Failed to derive key", idx);
return EC_RES_UNAVAILABLE;
}
- ret = aes_gcm_decrypt(key, SBP_ENC_KEY_LEN, fp_template[idx],
- fp_enc_buffer + sizeof(*enc_info),
- sizeof(fp_template[0]),
+ /* Decrypt the secret blob in-place. */
+ ret = aes_gcm_decrypt(key, SBP_ENC_KEY_LEN, encrypted_template,
+ encrypted_template,
+ encrypted_blob_size,
enc_info->nonce, FP_CONTEXT_NONCE_BYTES,
enc_info->tag, FP_CONTEXT_TAG_BYTES);
always_memset(key, 0, sizeof(key));
@@ -534,6 +587,10 @@ static enum ec_status fp_command_template(struct host_cmd_handler_args *args)
return EC_RES_UNAVAILABLE;
}
templ_valid++;
+ memcpy(fp_template[idx], encrypted_template,
+ sizeof(fp_template[0]));
+ memcpy(fp_positive_match_salt[idx], positive_match_salt,
+ sizeof(fp_positive_match_salt[0]));
}
return EC_RES_SUCCESS;
diff --git a/common/fpsensor/fpsensor_crypto.c b/common/fpsensor/fpsensor_crypto.c
index 4a2b31c411..73d7aca681 100644
--- a/common/fpsensor/fpsensor_crypto.c
+++ b/common/fpsensor/fpsensor_crypto.c
@@ -200,7 +200,8 @@ int derive_encryption_key(uint8_t *out_key, const uint8_t *salt)
}
/* "Extract step of HKDF. */
- hkdf_extract(prk, salt, FP_CONTEXT_SALT_BYTES, ikm, sizeof(ikm));
+ hkdf_extract(prk, salt, FP_CONTEXT_ENCRYPTION_SALT_BYTES, ikm,
+ sizeof(ikm));
always_memset(ikm, 0, sizeof(ikm));
/*
diff --git a/common/fpsensor/fpsensor_state.c b/common/fpsensor/fpsensor_state.c
index 82a548b8af..ec4ddb4fd9 100644
--- a/common/fpsensor/fpsensor_state.c
+++ b/common/fpsensor/fpsensor_state.c
@@ -38,6 +38,8 @@ struct positive_match_secret_state positive_match_secret_state = {
.deadline.val = 0,
};
+/* Index of the last enrolled but not retrieved template. */
+int8_t template_newly_enrolled = FP_NO_SUCH_TEMPLATE;
/* Number of used templates */
uint32_t templ_valid;
/* Bitmap of the templates with local modifications */
diff --git a/include/ec_commands.h b/include/ec_commands.h
index f28b9ea3e2..6e5e3b6990 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -5916,15 +5916,18 @@ struct ec_response_fp_info {
#define FP_FRAME_OFFSET_MASK 0x0FFFFFFF
/* Version of the format of the encrypted templates. */
-#define FP_TEMPLATE_FORMAT_VERSION 3
+#define FP_TEMPLATE_FORMAT_VERSION 4
/* Constants for encryption parameters */
#define FP_CONTEXT_NONCE_BYTES 12
#define FP_CONTEXT_USERID_WORDS (32 / sizeof(uint32_t))
#define FP_CONTEXT_TAG_BYTES 16
-#define FP_CONTEXT_SALT_BYTES 16
+#define FP_CONTEXT_ENCRYPTION_SALT_BYTES 16
#define FP_CONTEXT_TPM_BYTES 32
+/* Constants for positive match parameters. */
+#define FP_POSITIVE_MATCH_SALT_BYTES 16
+
struct ec_fp_template_encryption_metadata {
/*
* Version of the structure format (N=3).
@@ -5937,7 +5940,7 @@ struct ec_fp_template_encryption_metadata {
* a different one is used for every message.
*/
uint8_t nonce[FP_CONTEXT_NONCE_BYTES];
- uint8_t salt[FP_CONTEXT_SALT_BYTES];
+ uint8_t encryption_salt[FP_CONTEXT_ENCRYPTION_SALT_BYTES];
uint8_t tag[FP_CONTEXT_TAG_BYTES];
};
diff --git a/include/fpsensor_state.h b/include/fpsensor_state.h
index 624318837d..4047fca74d 100644
--- a/include/fpsensor_state.h
+++ b/include/fpsensor_state.h
@@ -38,8 +38,8 @@
#define SBP_ENC_KEY_LEN 16
#define FP_ALGORITHM_ENCRYPTED_TEMPLATE_SIZE \
(FP_ALGORITHM_TEMPLATE_SIZE + \
+ FP_POSITIVE_MATCH_SALT_BYTES + \
sizeof(struct ec_fp_template_encryption_metadata))
-#define FP_POSITIVE_MATCH_SALT_BYTES 16
/* Events for the FPSENSOR task */
#define TASK_EVENT_SENSOR_IRQ TASK_EVENT_CUSTOM_BIT(0)
@@ -63,6 +63,8 @@ extern uint8_t fp_enc_buffer[FP_ALGORITHM_ENCRYPTED_TEMPLATE_SIZE];
/* Salt used in derivation of positive match secret. */
extern uint8_t fp_positive_match_salt
[FP_MAX_FINGER_COUNT][FP_POSITIVE_MATCH_SALT_BYTES];
+/* Index of the last enrolled but not retrieved template. */
+extern int8_t template_newly_enrolled;
/* Number of used templates */
extern uint32_t templ_valid;
/* Bitmap of the templates with local modifications */
diff --git a/test/fpsensor.c b/test/fpsensor.c
index 962295afbf..81441295ae 100644
--- a/test/fpsensor.c
+++ b/test/fpsensor.c
@@ -276,7 +276,7 @@ test_static int test_hkdf_expand(void)
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 };
+ static const uint8_t unused_salt[FP_CONTEXT_ENCRYPTION_SALT_BYTES];
/* GIVEN that the TPM seed is not set. */
if (fp_tpm_seed_is_set()) {
@@ -373,7 +373,7 @@ test_static int test_derive_encryption_key(void)
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 };
+ static const uint8_t unused_salt[FP_CONTEXT_ENCRYPTION_SALT_BYTES];
/* GIVEN that reading the rollback secret will fail. */
rollback_should_fail = 1;
@@ -473,7 +473,7 @@ test_static int test_derive_positive_match_secret_fail_salt_trivial(void)
{
static uint8_t output[FP_POSITIVE_MATCH_SECRET_BYTES];
/* GIVEN that the salt is trivial. */
- static const uint8_t salt[FP_CONTEXT_SALT_BYTES] = { 0 };
+ static const uint8_t salt[FP_CONTEXT_ENCRYPTION_SALT_BYTES] = { 0 };
/* THEN deriving positive match secret will fail. */
TEST_ASSERT(derive_positive_match_secret(output, salt)