summaryrefslogtreecommitdiff
path: root/common/fpsensor/fpsensor.c
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/fpsensor.c
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-firmware-brya-14505.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/fpsensor.c')
-rw-r--r--common/fpsensor/fpsensor.c887
1 files changed, 0 insertions, 887 deletions
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 */