summaryrefslogtreecommitdiff
path: root/common/fpsensor
diff options
context:
space:
mode:
Diffstat (limited to 'common/fpsensor')
-rw-r--r--common/fpsensor/OWNERS10
-rw-r--r--common/fpsensor/fpsensor.c887
-rw-r--r--common/fpsensor/fpsensor_crypto.c286
-rw-r--r--common/fpsensor/fpsensor_private.h19
-rw-r--r--common/fpsensor/fpsensor_state.c313
5 files changed, 0 insertions, 1515 deletions
diff --git a/common/fpsensor/OWNERS b/common/fpsensor/OWNERS
deleted file mode 100644
index 395f722670..0000000000
--- a/common/fpsensor/OWNERS
+++ /dev/null
@@ -1,10 +0,0 @@
-# Fingerprint Sensor
-
-# Don't inherit owners from elsewhere in the manifest
-set noparent
-
-hesling@chromium.org
-jora@google.com
-josienordrum@google.com
-tomhughes@chromium.org
-yichengli@chromium.org
diff --git a/common/fpsensor/fpsensor.c b/common/fpsensor/fpsensor.c
deleted file mode 100644
index 25010c7db8..0000000000
--- a/common/fpsensor/fpsensor.c
+++ /dev/null
@@ -1,887 +0,0 @@
-/* Copyright 2017 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 "atomic.h"
-#include "clock.h"
-#include "common.h"
-#include "console.h"
-#include "cryptoc/util.h"
-#include "ec_commands.h"
-#include "fpsensor.h"
-#include "fpsensor_crypto.h"
-#include "fpsensor_detect.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 "overflow.h"
-#include "spi.h"
-#include "system.h"
-#include "task.h"
-#include "trng.h"
-#include "util.h"
-#include "watchdog.h"
-
-#if !defined(CONFIG_RNG)
-#error "fpsensor requires RNG"
-#endif
-
-#if defined(SECTION_IS_RO)
-#error "fpsensor code should not be in RO image."
-#endif
-
-/* Ready to encrypt a template. */
-static timestamp_t encryption_deadline;
-
-/* raw image offset inside the acquired frame */
-#ifndef FP_SENSOR_IMAGE_OFFSET
-#define FP_SENSOR_IMAGE_OFFSET 0
-#endif
-
-#define FP_MODE_ANY_CAPTURE (FP_MODE_CAPTURE | FP_MODE_ENROLL_IMAGE | \
- FP_MODE_MATCH)
-#define FP_MODE_ANY_DETECT_FINGER (FP_MODE_FINGER_DOWN | FP_MODE_FINGER_UP | \
- FP_MODE_ANY_CAPTURE)
-#define FP_MODE_ANY_WAIT_IRQ (FP_MODE_FINGER_DOWN | FP_MODE_ANY_CAPTURE)
-
-/* Delay between 2 s of the sensor to detect finger removal */
-#define FINGER_POLLING_DELAY (100*MSEC)
-
-/* Timing statistics. */
-static uint32_t capture_time_us;
-static uint32_t matching_time_us;
-static uint32_t overall_time_us;
-static timestamp_t overall_t0;
-static uint8_t timestamps_invalid;
-
-BUILD_ASSERT(sizeof(struct ec_fp_template_encryption_metadata) % 4 == 0);
-
-/* Interrupt line from the fingerprint sensor */
-void fps_event(enum gpio_signal signal)
-{
- task_set_event(TASK_ID_FPSENSOR, TASK_EVENT_SENSOR_IRQ);
-}
-
-static void send_mkbp_event(uint32_t event)
-{
- atomic_or(&fp_events, event);
- mkbp_send_event(EC_MKBP_EVENT_FINGERPRINT);
-}
-
-static inline int is_raw_capture(uint32_t mode)
-{
- int capture_type = FP_CAPTURE_TYPE(mode);
-
- return (capture_type == FP_CAPTURE_VENDOR_FORMAT
- || capture_type == FP_CAPTURE_QUALITY_TEST);
-}
-
-#ifdef HAVE_FP_PRIVATE_DRIVER
-static inline int is_test_capture(uint32_t mode)
-{
- int capture_type = FP_CAPTURE_TYPE(mode);
-
- return (mode & FP_MODE_CAPTURE)
- && (capture_type == FP_CAPTURE_PATTERN0
- || capture_type == FP_CAPTURE_PATTERN1
- || capture_type == FP_CAPTURE_RESET_TEST);
-}
-
-/*
- * contains the bit FP_MODE_ENROLL_SESSION if a finger enrollment is on-going.
- * It is used to detect the ENROLL_SESSION transition when sensor_mode is
- * updated by the host.
- */
-static uint32_t enroll_session;
-
-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);
- CPRINTS("[%d]Enroll =>%d (%d%%)", templ_valid, res, percent);
- if (res < 0)
- return EC_MKBP_FP_ENROLL
- | EC_MKBP_FP_ERRCODE(EC_MKBP_FP_ERR_ENROLL_INTERNAL);
- templ_dirty |= BIT(templ_valid);
- if (percent == 100) {
- res = fp_enrollment_finish(fp_template[templ_valid]);
- if (res) {
- res = EC_MKBP_FP_ERR_ENROLL_INTERNAL;
- } else {
- template_newly_enrolled = templ_valid;
- fp_enable_positive_match_secret(templ_valid,
- &positive_match_secret_state);
- templ_valid++;
- }
- sensor_mode &= ~FP_MODE_ENROLL_SESSION;
- enroll_session &= ~FP_MODE_ENROLL_SESSION;
- }
- return EC_MKBP_FP_ENROLL | EC_MKBP_FP_ERRCODE(res)
- | (percent << EC_MKBP_FP_ENROLL_PROGRESS_OFFSET);
-}
-
-static bool fp_match_success(int match_result)
-{
- if (match_result == EC_MKBP_FP_ERR_MATCH_YES ||
- match_result == EC_MKBP_FP_ERR_MATCH_YES_UPDATED ||
- match_result == EC_MKBP_FP_ERR_MATCH_YES_UPDATE_FAILED) {
- return true;
- }
-
- return false;
-}
-
-static uint32_t fp_process_match(void)
-{
- timestamp_t t0 = get_time();
- int res = -1;
- uint32_t updated = 0;
- int32_t fgr = FP_NO_SUCH_TEMPLATE;
-
- /* match finger against current templates */
- fp_disable_positive_match_secret(&positive_match_secret_state);
- CPRINTS("Matching/%d ...", templ_valid);
- if (templ_valid) {
- res = fp_finger_match(fp_template[0], templ_valid, fp_buffer,
- &fgr, &updated);
- CPRINTS("Match =>%d (finger %d)", res, fgr);
-
- if (fp_match_success(res)) {
- /*
- * Match succeded! Let's check if template number
- * is valid. If it is not valid, overwrite result
- * with EC_MKBP_FP_ERR_MATCH_NO_INTERNAL.
- */
- if (fgr >= 0 && fgr < FP_MAX_FINGER_COUNT) {
- fp_enable_positive_match_secret(fgr,
- &positive_match_secret_state);
- } else {
- res = EC_MKBP_FP_ERR_MATCH_NO_INTERNAL;
- }
- } else if (res < 0) {
- /*
- * Negative result means that there is a problem with
- * code responsible for matching. Overwrite it with
- * MATCH_NO_INTERNAL to let upper layers know what
- * happened.
- */
- res = EC_MKBP_FP_ERR_MATCH_NO_INTERNAL;
- }
-
- if (res == EC_MKBP_FP_ERR_MATCH_YES_UPDATED)
- templ_dirty |= updated;
- } else {
- CPRINTS("No enrolled templates");
- res = EC_MKBP_FP_ERR_MATCH_NO_TEMPLATES;
- }
-
- if (!fp_match_success(res))
- timestamps_invalid |= FPSTATS_MATCHING_INV;
-
- matching_time_us = time_since32(t0);
- return EC_MKBP_FP_MATCH | EC_MKBP_FP_ERRCODE(res)
- | ((fgr << EC_MKBP_FP_MATCH_IDX_OFFSET) & EC_MKBP_FP_MATCH_IDX_MASK);
-}
-
-static void fp_process_finger(void)
-{
- timestamp_t t0 = get_time();
- int res = fp_sensor_acquire_image_with_mode(fp_buffer,
- FP_CAPTURE_TYPE(sensor_mode));
- capture_time_us = time_since32(t0);
- if (!res) {
- uint32_t evt = EC_MKBP_FP_IMAGE_READY;
-
- /* Clean up SPI before clocking up to avoid hang on the dsb
- * in dma_go. Ignore the return value to let the WDT reboot
- * the MCU (and avoid getting trapped in the loop).
- * b/112781659 */
- res = spi_transaction_flush(&spi_devices[0]);
- if (res)
- CPRINTS("Failed to flush SPI: 0x%x", res);
- /* we need CPU power to do the computations */
- clock_enable_module(MODULE_FAST_CPU, 1);
-
- if (sensor_mode & FP_MODE_ENROLL_IMAGE)
- evt = fp_process_enroll();
- else if (sensor_mode & FP_MODE_MATCH)
- evt = fp_process_match();
-
- sensor_mode &= ~FP_MODE_ANY_CAPTURE;
- overall_time_us = time_since32(overall_t0);
- send_mkbp_event(evt);
-
- /* go back to lower power mode */
- clock_enable_module(MODULE_FAST_CPU, 0);
- } else {
- timestamps_invalid |= FPSTATS_CAPTURE_INV;
- }
-}
-#endif /* HAVE_FP_PRIVATE_DRIVER */
-
-void fp_task(void)
-{
- int timeout_us = -1;
-
- CPRINTS("FP_SENSOR_SEL: %s",
- fp_sensor_type_to_str(get_fp_sensor_type()));
-
-#ifdef HAVE_FP_PRIVATE_DRIVER
- /* Reset and initialize the sensor IC */
- fp_sensor_init();
-
- while (1) {
- uint32_t evt;
- enum finger_state st = FINGER_NONE;
-
- /* Wait for a sensor IRQ or a new mode configuration */
- evt = task_wait_event(timeout_us);
-
- if (evt & TASK_EVENT_UPDATE_CONFIG) {
- uint32_t mode = sensor_mode;
-
- gpio_disable_interrupt(GPIO_FPS_INT);
- if ((mode ^ enroll_session) & FP_MODE_ENROLL_SESSION) {
- if (mode & FP_MODE_ENROLL_SESSION) {
- if (fp_enrollment_begin())
- sensor_mode &=
- ~FP_MODE_ENROLL_SESSION;
- } else {
- fp_enrollment_finish(NULL);
- }
- enroll_session =
- sensor_mode & FP_MODE_ENROLL_SESSION;
- }
- if (is_test_capture(mode)) {
- fp_sensor_acquire_image_with_mode(fp_buffer,
- FP_CAPTURE_TYPE(mode));
- sensor_mode &= ~FP_MODE_CAPTURE;
- send_mkbp_event(EC_MKBP_FP_IMAGE_READY);
- continue;
- } else if (sensor_mode & FP_MODE_ANY_DETECT_FINGER) {
- /* wait for a finger on the sensor */
- fp_sensor_configure_detect();
- }
- if (sensor_mode & FP_MODE_DEEPSLEEP)
- /* Shutdown the sensor */
- fp_sensor_low_power();
- if (sensor_mode & FP_MODE_FINGER_UP)
- /* Poll the sensor to detect finger removal */
- timeout_us = FINGER_POLLING_DELAY;
- else
- timeout_us = -1;
- if (mode & FP_MODE_ANY_WAIT_IRQ) {
- gpio_enable_interrupt(GPIO_FPS_INT);
- } else if (mode & FP_MODE_RESET_SENSOR) {
- fp_reset_and_clear_context();
- sensor_mode &= ~FP_MODE_RESET_SENSOR;
- } else if (mode & FP_MODE_SENSOR_MAINTENANCE) {
- fp_maintenance();
- sensor_mode &= ~FP_MODE_SENSOR_MAINTENANCE;
- } else {
- fp_sensor_low_power();
- }
- } else if (evt & (TASK_EVENT_SENSOR_IRQ | TASK_EVENT_TIMER)) {
- overall_t0 = get_time();
- timestamps_invalid = 0;
- gpio_disable_interrupt(GPIO_FPS_INT);
- if (sensor_mode & FP_MODE_ANY_DETECT_FINGER) {
- st = fp_sensor_finger_status();
- if (st == FINGER_PRESENT &&
- sensor_mode & FP_MODE_FINGER_DOWN) {
- CPRINTS("Finger!");
- sensor_mode &= ~FP_MODE_FINGER_DOWN;
- send_mkbp_event(EC_MKBP_FP_FINGER_DOWN);
- }
- if (st == FINGER_NONE &&
- sensor_mode & FP_MODE_FINGER_UP) {
- sensor_mode &= ~FP_MODE_FINGER_UP;
- timeout_us = -1;
- send_mkbp_event(EC_MKBP_FP_FINGER_UP);
- }
- }
-
- if (st == FINGER_PRESENT &&
- sensor_mode & FP_MODE_ANY_CAPTURE)
- fp_process_finger();
-
- if (sensor_mode & FP_MODE_ANY_WAIT_IRQ) {
- fp_sensor_configure_detect();
- gpio_enable_interrupt(GPIO_FPS_INT);
- } else {
- fp_sensor_low_power();
- }
- }
- }
-#else /* !HAVE_FP_PRIVATE_DRIVER */
- while (1) {
- uint32_t evt = task_wait_event(timeout_us);
-
- send_mkbp_event(evt);
- }
-#endif /* !HAVE_FP_PRIVATE_DRIVER */
-}
-
-static enum ec_status fp_command_passthru(struct host_cmd_handler_args *args)
-{
- const struct ec_params_fp_passthru *params = args->params;
- void *out = args->response;
- int rc;
- int ret = EC_RES_SUCCESS;
-
- if (system_is_locked())
- return EC_RES_ACCESS_DENIED;
-
- if (params->len > args->params_size +
- offsetof(struct ec_params_fp_passthru, data) ||
- params->len > args->response_max)
- return EC_RES_INVALID_PARAM;
-
- rc = spi_transaction_async(&spi_devices[0], params->data,
- params->len, out, SPI_READBACK_ALL);
- if (params->flags & EC_FP_FLAG_NOT_COMPLETE)
- rc |= spi_transaction_wait(&spi_devices[0]);
- else
- rc |= spi_transaction_flush(&spi_devices[0]);
-
- if (rc == EC_ERROR_TIMEOUT)
- ret = EC_RES_TIMEOUT;
- else if (rc)
- ret = EC_RES_ERROR;
-
- args->response_size = params->len;
- return ret;
-}
-DECLARE_HOST_COMMAND(EC_CMD_FP_PASSTHRU, fp_command_passthru, EC_VER_MASK(0));
-
-static enum ec_status fp_command_info(struct host_cmd_handler_args *args)
-{
- struct ec_response_fp_info *r = args->response;
-
-#ifdef HAVE_FP_PRIVATE_DRIVER
- if (fp_sensor_get_info(r) < 0)
-#endif
- return EC_RES_UNAVAILABLE;
-
- r->template_size = FP_ALGORITHM_ENCRYPTED_TEMPLATE_SIZE;
- r->template_max = FP_MAX_FINGER_COUNT;
- r->template_valid = templ_valid;
- r->template_dirty = templ_dirty;
- r->template_version = FP_TEMPLATE_FORMAT_VERSION;
-
- /* V1 is identical to V0 with more information appended */
- args->response_size = args->version ? sizeof(*r) :
- sizeof(struct ec_response_fp_info_v0);
- return EC_RES_SUCCESS;
-}
-DECLARE_HOST_COMMAND(EC_CMD_FP_INFO, fp_command_info,
- EC_VER_MASK(0) | EC_VER_MASK(1));
-
-BUILD_ASSERT(FP_CONTEXT_NONCE_BYTES == 12);
-
-int validate_fp_buffer_offset(const uint32_t buffer_size, const uint32_t offset,
- const uint32_t size)
-{
- uint32_t bytes_requested;
-
- if (check_add_overflow(size, offset, &bytes_requested))
- return EC_ERROR_OVERFLOW;
-
- if (bytes_requested > buffer_size)
- return EC_ERROR_INVAL;
-
- return EC_SUCCESS;
-}
-
-static enum ec_status fp_command_frame(struct host_cmd_handler_args *args)
-{
- const struct ec_params_fp_frame *params = args->params;
- void *out = args->response;
- uint32_t idx = FP_FRAME_GET_BUFFER_INDEX(params->offset);
- uint32_t offset = params->offset & FP_FRAME_OFFSET_MASK;
- uint32_t size = params->size;
- uint32_t fgr;
- uint8_t key[SBP_ENC_KEY_LEN];
- struct ec_fp_template_encryption_metadata *enc_info;
- int ret;
-
- if (size > args->response_max)
- return EC_RES_INVALID_PARAM;
-
- if (idx == FP_FRAME_INDEX_RAW_IMAGE) {
- /* The host requested a frame. */
- if (system_is_locked())
- return EC_RES_ACCESS_DENIED;
- if (!is_raw_capture(sensor_mode))
- offset += FP_SENSOR_IMAGE_OFFSET;
-
- ret = validate_fp_buffer_offset(sizeof(fp_buffer), offset,
- size);
- if (ret != EC_SUCCESS)
- return EC_RES_INVALID_PARAM;
-
- memcpy(out, fp_buffer + offset, size);
- args->response_size = size;
- return EC_RES_SUCCESS;
- }
-
- /* The host requested a template. */
-
- /* Templates are numbered from 1 in this host request. */
- fgr = idx - FP_FRAME_INDEX_TEMPLATE;
-
- if (fgr >= FP_MAX_FINGER_COUNT)
- return EC_RES_INVALID_PARAM;
- if (fgr >= templ_valid)
- return EC_RES_UNAVAILABLE;
- ret = validate_fp_buffer_offset(sizeof(fp_enc_buffer), offset, size);
- if (ret != EC_SUCCESS)
- return EC_RES_INVALID_PARAM;
-
- 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))
- return EC_RES_BUSY;
- encryption_deadline.val = now.val + (1 * SECOND);
-
- memset(fp_enc_buffer, 0, sizeof(fp_enc_buffer));
- /*
- * 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->encryption_salt,
- FP_CONTEXT_ENCRYPTION_SALT_BYTES);
- exit_trng();
-
- 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;
- }
-
- /*
- * 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));
- if (ret != EC_SUCCESS) {
- CPRINTS("fgr%d: Failed to encrypt template", fgr);
- return EC_RES_UNAVAILABLE;
- }
- templ_dirty &= ~BIT(fgr);
- }
- memcpy(out, fp_enc_buffer + offset, size);
- args->response_size = size;
-
- return EC_RES_SUCCESS;
-}
-DECLARE_HOST_COMMAND(EC_CMD_FP_FRAME, fp_command_frame, EC_VER_MASK(0));
-
-static enum ec_status fp_command_stats(struct host_cmd_handler_args *args)
-{
- struct ec_response_fp_stats *r = args->response;
-
- r->capture_time_us = capture_time_us;
- r->matching_time_us = matching_time_us;
- r->overall_time_us = overall_time_us;
- r->overall_t0.lo = overall_t0.le.lo;
- r->overall_t0.hi = overall_t0.le.hi;
- r->timestamps_invalid = timestamps_invalid;
- /*
- * Note that this is set to FP_NO_SUCH_TEMPLATE when positive match
- * secret is read/disabled, and we are not using this field in biod.
- */
- r->template_matched = positive_match_secret_state.template_matched;
-
- args->response_size = sizeof(*r);
- return EC_RES_SUCCESS;
-}
-DECLARE_HOST_COMMAND(EC_CMD_FP_STATS, fp_command_stats, EC_VER_MASK(0));
-
-static bool template_needs_validation_value(
- struct ec_fp_template_encryption_metadata *enc_info)
-{
- return enc_info->struct_version == 3
- && FP_TEMPLATE_FORMAT_VERSION == 4;
-}
-
-static int validate_template_format(
- struct ec_fp_template_encryption_metadata *enc_info)
-{
- if (template_needs_validation_value(enc_info))
- /* 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;
- }
- return EC_RES_SUCCESS;
-}
-
-static enum ec_status fp_command_template(struct host_cmd_handler_args *args)
-{
- const struct ec_params_fp_template *params = args->params;
- uint32_t size = params->size & ~FP_TEMPLATE_COMMIT;
- int xfer_complete = params->size & FP_TEMPLATE_COMMIT;
- uint32_t offset = params->offset;
- uint32_t idx = templ_valid;
- uint8_t key[SBP_ENC_KEY_LEN];
- struct ec_fp_template_encryption_metadata *enc_info;
- int ret;
-
- /* Can we store one more template ? */
- if (idx >= FP_MAX_FINGER_COUNT)
- return EC_RES_OVERFLOW;
-
- if (args->params_size !=
- size + offsetof(struct ec_params_fp_template, data))
- return EC_RES_INVALID_PARAM;
- ret = validate_fp_buffer_offset(sizeof(fp_enc_buffer), offset, size);
- if (ret != EC_SUCCESS)
- return EC_RES_INVALID_PARAM;
-
- 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;
-
- /*
- * The complete encrypted template has been received, start
- * decryption.
- */
- fp_clear_finger_context(idx);
- /*
- * 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;
- }
-
- if (enc_info->struct_version <= 3) {
- encrypted_blob_size = sizeof(fp_template[0]);
- } else {
- encrypted_blob_size =
- sizeof(fp_template[0]) +
- sizeof(fp_positive_match_salt[0]);
- }
-
- 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;
- }
-
- /* 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));
- if (ret != EC_SUCCESS) {
- CPRINTS("fgr%d: Failed to decipher template", idx);
- /* Don't leave bad data in the template buffer */
- fp_clear_finger_context(idx);
- return EC_RES_UNAVAILABLE;
- }
- memcpy(fp_template[idx], encrypted_template,
- sizeof(fp_template[0]));
- if (template_needs_validation_value(enc_info)) {
- CPRINTS("fgr%d: Generating positive match salt.", idx);
- init_trng();
- rand_bytes(positive_match_salt,
- FP_POSITIVE_MATCH_SALT_BYTES);
- exit_trng();
- }
- if (bytes_are_trivial(positive_match_salt,
- sizeof(fp_positive_match_salt[0]))) {
- CPRINTS("fgr%d: Trivial positive match salt.", idx);
- always_memset(fp_template[idx], 0,
- sizeof(fp_template[0]));
- return EC_RES_INVALID_PARAM;
- }
- memcpy(fp_positive_match_salt[idx], positive_match_salt,
- sizeof(fp_positive_match_salt[0]));
-
- templ_valid++;
- }
-
- return EC_RES_SUCCESS;
-}
-DECLARE_HOST_COMMAND(EC_CMD_FP_TEMPLATE, fp_command_template, EC_VER_MASK(0));
-
-#ifdef CONFIG_CMD_FPSENSOR_DEBUG
-/* --- Debug console commands --- */
-
-/*
- * Send the current Fingerprint buffer to the host
- * it is formatted as an 8-bpp PGM ASCII file.
- *
- * In addition, it prepends a short Z-Modem download signature,
- * which triggers automatically your preferred viewer if you configure it
- * properly in "File transfer protocols" in the Minicom options menu.
- * (as triggered by Ctrl-A O)
- * +--------------------------------------------------------------------------+
- * | Name Program Name U/D FullScr IO-Red. Multi |
- * | A zmodem /usr/bin/sz -vv -b Y U N Y Y |
- * [...]
- * | L pgm /usr/bin/display_pgm N D N Y N |
- * | M Zmodem download string activates... L |
- *
- * My /usr/bin/display_pgm looks like this:
- * #!/bin/sh
- * TMPF=$(mktemp)
- * ascii-xfr -rdv ${TMPF}
- * display ${TMPF}
- *
- * Alternative (if you're using screen as your terminal):
- *
- * From *outside* the chroot:
- *
- * Install ascii-xfr: sudo apt-get install minicom
- * Install imagemagick: sudo apt-get install imagemagick
- *
- * Add the following to your ${HOME}/.screenrc:
- *
- * zmodem catch
- * zmodem recvcmd '!!! bash -c "ascii-xfr -rdv /tmp/finger.pgm && display /tmp/finger.pgm"'
- *
- * From *outside the chroot*, use screen to connect to UART console:
- *
- * sudo screen -c ${HOME}/.screenrc /dev/pts/NN 115200
- *
- */
-static void upload_pgm_image(uint8_t *frame)
-{
- int x, y;
- uint8_t *ptr = frame;
-
- /* fake Z-modem ZRQINIT signature */
- CPRINTF("#IGNORE for ZModem\r**\030B00");
- msleep(2000); /* let the download program start */
- /* Print 8-bpp PGM ASCII header */
- CPRINTF("P2\n%d %d\n255\n", FP_SENSOR_RES_X, FP_SENSOR_RES_Y);
-
- for (y = 0; y < FP_SENSOR_RES_Y; y++) {
- watchdog_reload();
- for (x = 0; x < FP_SENSOR_RES_X; x++, ptr++)
- CPRINTF("%d ", *ptr);
- CPRINTF("\n");
- cflush();
- }
-
- CPRINTF("\x04"); /* End Of Transmission */
-}
-
-static enum ec_error_list fp_console_action(uint32_t mode)
-{
- int tries = 200;
- uint32_t mode_output = 0;
- int rc = 0;
-
- if (!(sensor_mode & FP_MODE_RESET_SENSOR))
- CPRINTS("Waiting for finger ...");
-
- rc = fp_set_sensor_mode(mode, &mode_output);
-
- if (rc != EC_RES_SUCCESS) {
- /*
- * EC host command errors do not directly map to console command
- * errors.
- */
- return EC_ERROR_UNKNOWN;
- }
-
- while (tries--) {
- if (!(sensor_mode & FP_MODE_ANY_CAPTURE)) {
- CPRINTS("done (events:%x)", fp_events);
- return 0;
- }
- usleep(100 * MSEC);
- }
- return EC_ERROR_TIMEOUT;
-}
-
-int command_fpcapture(int argc, char **argv)
-{
- int capture_type = FP_CAPTURE_SIMPLE_IMAGE;
- uint32_t mode;
- enum ec_error_list rc;
-
- /*
- * TODO(b/142944002): Remove this redundant check for system_is_locked
- * once we have unit-tests/integration-tests in place.
- */
- if (system_is_locked())
- return EC_ERROR_ACCESS_DENIED;
-
- if (argc >= 2) {
- char *e;
-
- capture_type = strtoi(argv[1], &e, 0);
- if (*e || capture_type < 0)
- return EC_ERROR_PARAM1;
- }
- mode = FP_MODE_CAPTURE | ((capture_type << FP_MODE_CAPTURE_TYPE_SHIFT)
- & FP_MODE_CAPTURE_TYPE_MASK);
-
- rc = fp_console_action(mode);
- if (rc == EC_SUCCESS)
- upload_pgm_image(fp_buffer + FP_SENSOR_IMAGE_OFFSET);
-
- return rc;
-}
-DECLARE_CONSOLE_COMMAND_FLAGS(fpcapture, command_fpcapture, NULL,
- "Capture fingerprint in PGM format",
- CMD_FLAG_RESTRICTED);
-
-int command_fpenroll(int argc, char **argv)
-{
- enum ec_error_list rc;
- int percent = 0;
- uint32_t event;
- static const char * const enroll_str[] = {"OK", "Low Quality",
- "Immobile", "Low Coverage"};
-
- /*
- * TODO(b/142944002): Remove this redundant check for system_is_locked
- * once we have unit-tests/integration-tests in place.
- */
- if (system_is_locked())
- return EC_ERROR_ACCESS_DENIED;
-
- do {
- int tries = 1000;
-
- rc = fp_console_action(FP_MODE_ENROLL_SESSION |
- FP_MODE_ENROLL_IMAGE);
- if (rc != EC_SUCCESS)
- break;
- event = atomic_clear(&fp_events);
- percent = EC_MKBP_FP_ENROLL_PROGRESS(event);
- CPRINTS("Enroll capture: %s (%d%%)",
- enroll_str[EC_MKBP_FP_ERRCODE(event) & 3], percent);
- /* wait for finger release between captures */
- sensor_mode = FP_MODE_ENROLL_SESSION | FP_MODE_FINGER_UP;
- task_set_event(TASK_ID_FPSENSOR, TASK_EVENT_UPDATE_CONFIG);
- while (tries-- && sensor_mode & FP_MODE_FINGER_UP)
- usleep(20 * MSEC);
- } while (percent < 100);
- sensor_mode = 0; /* reset FP_MODE_ENROLL_SESSION */
- task_set_event(TASK_ID_FPSENSOR, TASK_EVENT_UPDATE_CONFIG);
-
- return rc;
-}
-DECLARE_CONSOLE_COMMAND_FLAGS(fpenroll, command_fpenroll, NULL,
- "Enroll a new fingerprint",
- CMD_FLAG_RESTRICTED);
-
-
-int command_fpmatch(int argc, char **argv)
-{
- enum ec_error_list rc = fp_console_action(FP_MODE_MATCH);
- uint32_t event = atomic_clear(&fp_events);
-
- if (rc == EC_SUCCESS && event & EC_MKBP_FP_MATCH) {
- uint32_t errcode = EC_MKBP_FP_ERRCODE(event);
-
- CPRINTS("Match: %s (%d)",
- errcode & EC_MKBP_FP_ERR_MATCH_YES ? "YES" : "NO",
- errcode);
- }
-
- return rc;
-}
-DECLARE_CONSOLE_COMMAND(fpmatch, command_fpmatch, NULL,
- "Run match algorithm against finger");
-
-int command_fpclear(int argc, char **argv)
-{
- /*
- * We intentionally run this on the fp_task so that we use the
- * same code path as host commands.
- */
- enum ec_error_list rc = fp_console_action(FP_MODE_RESET_SENSOR);
-
- if (rc < 0)
- CPRINTS("Failed to clear fingerprint context: %d", rc);
-
- atomic_clear(&fp_events);
-
- return rc;
-}
-DECLARE_CONSOLE_COMMAND(fpclear, command_fpclear, NULL,
- "Clear fingerprint sensor context");
-
-int command_fpmaintenance(int argc, char **argv)
-{
-#ifdef HAVE_FP_PRIVATE_DRIVER
- return fp_maintenance();
-#else
- return EC_SUCCESS;
-#endif /* #ifdef HAVE_FP_PRIVATE_DRIVER */
-}
-DECLARE_CONSOLE_COMMAND(fpmaintenance, command_fpmaintenance, NULL,
- "Run fingerprint sensor maintenance");
-
-#endif /* CONFIG_CMD_FPSENSOR_DEBUG */
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;
-}
diff --git a/common/fpsensor/fpsensor_private.h b/common/fpsensor/fpsensor_private.h
deleted file mode 100644
index a42049dece..0000000000
--- a/common/fpsensor/fpsensor_private.h
+++ /dev/null
@@ -1,19 +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.
- */
-
-/* Internal header file for common/fpsensor directory */
-
-#ifndef __CROS_EC_FPSENSOR_PRIVATE_H
-#define __CROS_EC_FPSENSOR_PRIVATE_H
-
-#include <stdint.h>
-
-#define CPRINTF(format, args...) cprintf(CC_FP, format, ## args)
-#define CPRINTS(format, args...) cprints(CC_FP, format, ## args)
-
-int validate_fp_buffer_offset(uint32_t buffer_size, uint32_t offset,
- uint32_t size);
-
-#endif /* __CROS_EC_FPSENSOR_PRIVATE_H */
diff --git a/common/fpsensor/fpsensor_state.c b/common/fpsensor/fpsensor_state.c
deleted file mode 100644
index db64110b56..0000000000
--- a/common/fpsensor/fpsensor_state.c
+++ /dev/null
@@ -1,313 +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 "common.h"
-#include "cryptoc/util.h"
-#include "ec_commands.h"
-#include "fpsensor.h"
-#include "fpsensor_crypto.h"
-#include "fpsensor_private.h"
-#include "fpsensor_state.h"
-#include "host_command.h"
-#include "system.h"
-#include "task.h"
-#include "util.h"
-
-/* 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 */
-uint8_t fp_template[FP_MAX_FINGER_COUNT][FP_ALGORITHM_TEMPLATE_SIZE]
- FP_TEMPLATE_SECTION;
-/* Encryption/decryption buffer */
-/* TODO: On-the-fly encryption/decryption without a dedicated buffer */
-/*
- * Store the encryption metadata at the beginning of the buffer containing the
- * ciphered data.
- */
-uint8_t fp_enc_buffer[FP_ALGORITHM_ENCRYPTED_TEMPLATE_SIZE]
- FP_TEMPLATE_SECTION;
-/* Salt used in derivation of positive match secret. */
-uint8_t fp_positive_match_salt
- [FP_MAX_FINGER_COUNT][FP_POSITIVE_MATCH_SALT_BYTES];
-
-struct positive_match_secret_state positive_match_secret_state = {
- .template_matched = FP_NO_SUCH_TEMPLATE,
- .readable = false,
- .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 */
-uint32_t templ_dirty;
-/* Current user ID */
-uint32_t user_id[FP_CONTEXT_USERID_WORDS];
-/* Part of the IKM used to derive encryption keys received from the TPM. */
-uint8_t tpm_seed[FP_CONTEXT_TPM_BYTES];
-/* Status of the FP encryption engine. */
-static uint32_t fp_encryption_status;
-
-uint32_t fp_events;
-
-uint32_t sensor_mode;
-
-void fp_task_simulate(void)
-{
- int timeout_us = -1;
-
- while (1)
- task_wait_event(timeout_us);
-}
-
-void fp_clear_finger_context(int idx)
-{
- always_memset(fp_template[idx], 0, sizeof(fp_template[0]));
- always_memset(fp_positive_match_salt[idx], 0,
- sizeof(fp_positive_match_salt[0]));
-}
-
-/**
- * @warning |fp_buffer| contains data used by the matching algorithm that must
- * be released by calling fp_sensor_deinit() first. Call
- * fp_reset_and_clear_context instead of calling this directly.
- */
-static void _fp_clear_context(void)
-{
- int idx;
-
- templ_valid = 0;
- templ_dirty = 0;
- always_memset(fp_buffer, 0, sizeof(fp_buffer));
- always_memset(fp_enc_buffer, 0, sizeof(fp_enc_buffer));
- always_memset(user_id, 0, sizeof(user_id));
- fp_disable_positive_match_secret(&positive_match_secret_state);
- for (idx = 0; idx < FP_MAX_FINGER_COUNT; idx++)
- fp_clear_finger_context(idx);
-}
-
-void fp_reset_and_clear_context(void)
-{
- if (fp_sensor_deinit() != EC_SUCCESS)
- CPRINTS("Failed to deinit sensor");
- _fp_clear_context();
- if (fp_sensor_init() != EC_SUCCESS)
- CPRINTS("Failed to init sensor");
-}
-
-int fp_get_next_event(uint8_t *out)
-{
- uint32_t event_out = atomic_clear(&fp_events);
-
- memcpy(out, &event_out, sizeof(event_out));
-
- return sizeof(event_out);
-}
-DECLARE_EVENT_SOURCE(EC_MKBP_EVENT_FINGERPRINT, fp_get_next_event);
-
-static enum ec_status 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_encryption_status & FP_ENC_STATUS_SEED_SET) {
- CPRINTS("Seed has already been set.");
- return EC_RES_ACCESS_DENIED;
- }
- memcpy(tpm_seed, params->seed, sizeof(tpm_seed));
- fp_encryption_status |= FP_ENC_STATUS_SEED_SET;
-
- return EC_RES_SUCCESS;
-}
-DECLARE_HOST_COMMAND(EC_CMD_FP_SEED, fp_command_tpm_seed, EC_VER_MASK(0));
-
-int fp_tpm_seed_is_set(void)
-{
- return fp_encryption_status & FP_ENC_STATUS_SEED_SET;
-}
-
-static enum ec_status
-fp_command_encryption_status(struct host_cmd_handler_args *args)
-{
- struct ec_response_fp_encryption_status *r = args->response;
-
- r->valid_flags = FP_ENC_STATUS_SEED_SET;
- r->status = fp_encryption_status;
- args->response_size = sizeof(*r);
-
- return EC_RES_SUCCESS;
-}
-DECLARE_HOST_COMMAND(EC_CMD_FP_ENC_STATUS, fp_command_encryption_status,
- EC_VER_MASK(0));
-
-static int validate_fp_mode(const uint32_t mode)
-{
- uint32_t capture_type = FP_CAPTURE_TYPE(mode);
- uint32_t algo_mode = mode & ~FP_MODE_CAPTURE_TYPE_MASK;
- uint32_t cur_mode = sensor_mode;
-
- if (capture_type >= FP_CAPTURE_TYPE_MAX)
- return EC_ERROR_INVAL;
-
- if (algo_mode & ~FP_VALID_MODES)
- return EC_ERROR_INVAL;
-
- if ((mode & FP_MODE_ENROLL_SESSION) &&
- templ_valid >= FP_MAX_FINGER_COUNT) {
- CPRINTS("Maximum number of fingers already enrolled: %d",
- FP_MAX_FINGER_COUNT);
- return EC_ERROR_INVAL;
- }
-
- /* Don't allow sensor reset if any other mode is
- * set (including FP_MODE_RESET_SENSOR itself).
- */
- if (mode & FP_MODE_RESET_SENSOR) {
- if (cur_mode & FP_VALID_MODES)
- return EC_ERROR_INVAL;
- }
-
- return EC_SUCCESS;
-}
-
-int fp_set_sensor_mode(uint32_t mode, uint32_t *mode_output)
-{
- int ret;
-
- if (mode_output == NULL)
- return EC_RES_INVALID_PARAM;
-
- ret = validate_fp_mode(mode);
- if (ret != EC_SUCCESS) {
- CPRINTS("Invalid FP mode 0x%x", mode);
- return EC_RES_INVALID_PARAM;
- }
-
- if (!(mode & FP_MODE_DONT_CHANGE)) {
- sensor_mode = mode;
- task_set_event(TASK_ID_FPSENSOR, TASK_EVENT_UPDATE_CONFIG);
- }
-
- *mode_output = sensor_mode;
- return EC_RES_SUCCESS;
-}
-
-static enum ec_status fp_command_mode(struct host_cmd_handler_args *args)
-{
- const struct ec_params_fp_mode *p = args->params;
- struct ec_response_fp_mode *r = args->response;
-
- int ret = fp_set_sensor_mode(p->mode, &r->mode);
-
- if (ret == EC_RES_SUCCESS)
- args->response_size = sizeof(*r);
-
- return ret;
-}
-DECLARE_HOST_COMMAND(EC_CMD_FP_MODE, fp_command_mode, EC_VER_MASK(0));
-
-static enum ec_status fp_command_context(struct host_cmd_handler_args *args)
-{
- const struct ec_params_fp_context_v1 *p = args->params;
- uint32_t mode_output;
-
- switch (p->action) {
- case FP_CONTEXT_ASYNC:
- if (sensor_mode & FP_MODE_RESET_SENSOR)
- return EC_RES_BUSY;
-
- /**
- * Trigger a call to fp_reset_and_clear_context() by
- * requesting a reset. Since that function triggers a call to
- * fp_sensor_open(), this must be asynchronous because
- * fp_sensor_open() can take ~175 ms. See http://b/137288498.
- */
- return fp_set_sensor_mode(FP_MODE_RESET_SENSOR, &mode_output);
-
- case FP_CONTEXT_GET_RESULT:
- if (sensor_mode & FP_MODE_RESET_SENSOR)
- return EC_RES_BUSY;
-
- memcpy(user_id, p->userid, sizeof(user_id));
- return EC_RES_SUCCESS;
- }
-
- return EC_RES_INVALID_PARAM;
-}
-DECLARE_HOST_COMMAND(EC_CMD_FP_CONTEXT, fp_command_context, EC_VER_MASK(1));
-
-int fp_enable_positive_match_secret(uint32_t fgr,
- struct positive_match_secret_state *state)
-{
- timestamp_t now;
-
- if (state->readable) {
- CPRINTS("Error: positive match secret already readable.");
- fp_disable_positive_match_secret(state);
- return EC_ERROR_UNKNOWN;
- }
-
- now = get_time();
- state->template_matched = fgr;
- state->readable = true;
- state->deadline.val = now.val + (5 * SECOND);
- return EC_SUCCESS;
-}
-
-void fp_disable_positive_match_secret(
- struct positive_match_secret_state *state)
-{
- state->template_matched = FP_NO_SUCH_TEMPLATE;
- state->readable = false;
- state->deadline.val = 0;
-}
-
-static enum ec_status fp_command_read_match_secret(
- struct host_cmd_handler_args *args)
-{
- const struct ec_params_fp_read_match_secret *params = args->params;
- struct ec_response_fp_read_match_secret *response = args->response;
- int8_t fgr = params->fgr;
- timestamp_t now = get_time();
- struct positive_match_secret_state state_copy
- = positive_match_secret_state;
-
- fp_disable_positive_match_secret(&positive_match_secret_state);
-
- if (fgr < 0 || fgr >= FP_MAX_FINGER_COUNT) {
- CPRINTS("Invalid finger number %d", fgr);
- return EC_RES_INVALID_PARAM;
- }
- if (timestamp_expired(state_copy.deadline, &now)) {
- CPRINTS("Reading positive match secret disallowed: "
- "deadline has passed.");
- return EC_RES_TIMEOUT;
- }
- if (fgr != state_copy.template_matched || !state_copy.readable) {
- CPRINTS("Positive match secret for finger %d is not meant to "
- "be read now.", fgr);
- return EC_RES_ACCESS_DENIED;
- }
-
- if (derive_positive_match_secret(response->positive_match_secret,
- fp_positive_match_salt[fgr])
- != EC_SUCCESS) {
- CPRINTS("Failed to derive positive match secret for finger %d",
- fgr);
- /* Keep the template and encryption salt. */
- return EC_RES_ERROR;
- }
- CPRINTS("Derived positive match secret for finger %d", fgr);
- args->response_size = sizeof(*response);
-
- return EC_RES_SUCCESS;
-}
-DECLARE_HOST_COMMAND(EC_CMD_FP_READ_MATCH_SECRET, fp_command_read_match_secret,
- EC_VER_MASK(0));