summaryrefslogtreecommitdiff
path: root/common/fpsensor
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2021-11-04 12:11:58 -0600
committerCommit Bot <commit-bot@chromium.org>2021-11-05 04:22:34 +0000
commit252457d4b21f46889eebad61d4c0a65331919cec (patch)
tree01856c4d31d710b20e85a74c8d7b5836e35c3b98 /common/fpsensor
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-stabilize-14469.41.B-ish.tar.gz
In the interest of making long-term branch maintenance incur as little technical debt on us as possible, we should not maintain any files on the branch we are not actually using. This has the added effect of making it extremely clear when merging CLs from the main branch when changes have the possibility to affect us. The follow-on CL adds a convenience script to actually pull updates from the main branch and generate a CL for the update. BUG=b:204206272 BRANCH=ish TEST=make BOARD=arcada_ish && make BOARD=drallion_ish Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
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));