| /* Copyright 2024 The ChromiumOS Authors |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "mock_fingerprint_algorithm.h" |
| |
| #include <zephyr/device.h> |
| #include <zephyr/devicetree.h> |
| #include <zephyr/drivers/emul.h> |
| #include <zephyr/drivers/gpio.h> |
| #include <zephyr/drivers/gpio/gpio_emul.h> |
| #include <zephyr/fff.h> |
| #include <zephyr/sys/util.h> |
| #include <zephyr/ztest.h> |
| #include <zephyr/ztest_assert.h> |
| |
| #include <drivers/fingerprint.h> |
| #include <drivers/fingerprint_sim.h> |
| #include <ec_commands.h> |
| #include <ec_tasks.h> |
| #include <fingerprint/fingerprint_alg.h> |
| #include <fpsensor/fpsensor_state.h> |
| #include <host_command.h> |
| #include <rollback.h> |
| |
| DEFINE_FFF_GLOBALS; |
| |
| FAKE_VALUE_FUNC(int, mkbp_send_event, uint8_t); |
| |
| #define fp_sim DEVICE_DT_GET(DT_CHOSEN(cros_fp_fingerprint_sensor)) |
| #define IMAGE_SIZE \ |
| MAX_FROM_LIST(LISTIFY(NUM_IMAGE_CAPTURE_TYPES, \ |
| FINGERPRINT_SENSOR_FRAME_SIZE, (, ), \ |
| DT_CHOSEN(cros_fp_fingerprint_sensor))) |
| static uint8_t image_buffer[IMAGE_SIZE]; |
| |
| static const uint8_t fake_rollback_entropy[] = "some_rollback_entropy"; |
| |
| static const size_t test_info_buffer_size = |
| sizeof(struct ec_response_fp_info_v3) + |
| sizeof(struct fp_image_frame_params_v2) * FP_MAX_CAPTURE_TYPES; |
| static uint8_t buffer[test_info_buffer_size]; |
| static struct ec_response_fp_info_v3 *test_info_buffer = |
| (struct ec_response_fp_info_v3 *)buffer; |
| |
| /* The fake TPM seed is "very_secret_32_bytes_of_tpm_seed" */ |
| #define FAKE_TPM_SEED \ |
| { 0x76, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, \ |
| 0x5f, 0x33, 0x32, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, \ |
| 0x66, 0x5f, 0x74, 0x70, 0x6d, 0x5f, 0x73, 0x65, 0x65, 0x64 } |
| |
| /* The fake UserID is "i_m_a_fake_user_id_used_for_test" */ |
| #define FAKE_USER_ID \ |
| { 0x5f6d5f69, 0x61665f61, 0x755f656b, 0x5f726573, \ |
| 0x755f6469, 0x5f646573, 0x5f726f66, 0x74736574 } |
| |
| static const uint8_t example_template[CONFIG_FP_ALGORITHM_TEMPLATE_SIZE] = { |
| 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, |
| 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, |
| 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20 |
| }; |
| |
| static const uint8_t |
| example_positive_match_secret[FP_POSITIVE_MATCH_SECRET_BYTES] = { |
| 0xc8, 0x3a, 0x56, 0x56, 0xe7, 0x96, 0x06, 0xc3, |
| 0xb3, 0xed, 0x47, 0x20, 0x7e, 0x60, 0xbd, 0x5e, |
| 0xef, 0x6c, 0xa8, 0x84, 0xf2, 0x71, 0x86, 0x1a, |
| 0xf2, 0xa3, 0x6b, 0xa8, 0x1a, 0x82, 0x59, 0x45 |
| }; |
| |
| /* |
| * Encrypted template with metadata and positive match salt, for more |
| * information please check comment in fpsensor_template.c |
| */ |
| static const uint8_t |
| example_template_encrypted[sizeof(struct ec_params_fp_template) + |
| FP_ALGORITHM_ENCRYPTED_TEMPLATE_SIZE] = { |
| /* |
| * FP_TEMPLATE params. |
| * |
| * offset - 4 bytes |
| * size - 4 bytes |
| */ |
| 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x80, |
| /* |
| * Encryption metadata. |
| * |
| * struct_version - 2 bytes |
| * reserved - 2 bytes |
| * nonce - 12 bytes |
| * encryption_salt - 16 bytes |
| * tag - 16 bytes |
| */ |
| 0x04, 0x00, 0x00, 0x00, 0x94, 0x1e, 0xe3, 0x47, 0x31, 0x0b, |
| 0x89, 0x73, 0x1a, 0xeb, 0xa4, 0x45, 0x2b, 0x2e, 0x90, 0x58, |
| 0xfa, 0x25, 0x3e, 0x3b, 0x21, 0x35, 0x9a, 0x25, 0x79, 0x20, |
| 0xba, 0x60, 0x6b, 0x73, 0xb8, 0xac, 0x86, 0x6f, 0xe1, 0xbc, |
| 0x86, 0xca, 0xf6, 0x42, 0x25, 0x1f, 0xd1, 0x22, |
| /* Encrypted template. */ |
| 0xed, 0x2f, 0xb5, 0xf3, 0x9a, 0x7a, 0xfe, 0x09, 0x82, 0x69, |
| 0x9a, 0xd0, 0xa0, 0x60, 0x35, 0x15, 0x87, 0xdf, 0xea, 0xf7, |
| 0x8f, 0x4f, 0xdf, 0x5d, 0x7a, 0x93, 0xcf, 0x61, 0xad, 0xe6, |
| 0xc2, 0x3a, |
| /* Encrypted positive match salt. */ |
| 0x0f, 0x8d, 0xe0, 0x47, 0x69, 0x0f, 0xda, 0xea, 0xbc, 0xdc, |
| 0x96, 0x7d, 0x69, 0x19, 0xac, 0xe7 |
| }; |
| |
| static int match_result; |
| static int32_t finger_index; |
| static uint32_t finger_updated_bitmap; |
| |
| ZTEST_USER(fpsensor_match, test_match_no_templates_mkbp_event) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_MATCH, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| uint32_t fp_events; |
| |
| /* Switch mode to match. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_MATCH); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Put finger on the sensor. */ |
| fingerprint_get_state(fp_sim, &state); |
| state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Ping fpsensor task. */ |
| fingerprint_run_callback(fp_sim); |
| |
| /* Give opportunity for fpsensor task to process event. */ |
| k_msleep(1); |
| |
| /* Confirm MKBP event was sent. */ |
| zassert_equal(mkbp_send_event_fake.call_count, 1); |
| zassert_equal(mkbp_send_event_fake.arg0_val, EC_MKBP_EVENT_FINGERPRINT); |
| |
| /* |
| * Confirm that: |
| * - MKBP event is FP_MATCH |
| * - Match failed with NO_TEMPLATES |
| * - Finger ID is FP_NO_SUCH_TEMPLATE |
| */ |
| fp_get_next_event((uint8_t *)&fp_events); |
| zassert_true(fp_events & EC_MKBP_FP_MATCH); |
| zassert_equal(EC_MKBP_FP_ERRCODE(fp_events), |
| EC_MKBP_FP_ERR_MATCH_NO_TEMPLATES); |
| zassert_equal(EC_MKBP_FP_MATCH_IDX(fp_events), |
| FP_NO_SUCH_TEMPLATE & 0xF); |
| } |
| |
| ZTEST_USER(fpsensor_match, test_match_no_templates_mode_cleared) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_MATCH, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| |
| /* Switch mode to match. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_MATCH); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Put finger on the sensor. */ |
| fingerprint_get_state(fp_sim, &state); |
| state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Ping fpsensor task. */ |
| fingerprint_run_callback(fp_sim); |
| |
| /* Give opportunity for fpsensor task to process event. */ |
| k_msleep(1); |
| |
| /* Confirm that capture mode is not enabled. */ |
| params.mode = FP_MODE_DONT_CHANGE; |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_false(response.mode & FP_MODE_MATCH); |
| } |
| |
| static int match_compare(const struct fingerprint_algorithm *const alg, |
| void *templ, uint32_t templ_count, |
| const uint8_t *const image, bool template_update, |
| int32_t *match_index, uint32_t *update_bitmap) |
| { |
| zassert_true(template_update); |
| zassert_equal(templ_count, 1); |
| zassert_mem_equal((uint8_t *)templ, example_template, |
| CONFIG_FP_ALGORITHM_TEMPLATE_SIZE); |
| zassert_mem_equal(image, image_buffer, IMAGE_SIZE); |
| |
| return 0; |
| } |
| |
| ZTEST_USER(fpsensor_match, test_match_correct_template_and_image) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_MATCH, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| |
| /* Load example template. */ |
| zassert_ok(ec_cmd_fp_template( |
| NULL, |
| (struct ec_params_fp_template *)example_template_encrypted, |
| sizeof(example_template_encrypted))); |
| |
| /* |
| * Use custom match function to check if template and scan passed to |
| * matching algorithm is correct. |
| */ |
| mock_alg_match_fake.custom_fake = match_compare; |
| |
| /* Switch mode to match. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_MATCH); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Put finger on the sensor. */ |
| fingerprint_get_state(fp_sim, &state); |
| state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Prepare image. */ |
| memset(image_buffer, 1, IMAGE_SIZE); |
| |
| /* Load image to simulator. */ |
| fingerprint_load_image(fp_sim, image_buffer, IMAGE_SIZE); |
| |
| /* Ping fpsensor task. */ |
| fingerprint_run_callback(fp_sim); |
| |
| /* Give opportunity for fpsensor task process event. */ |
| k_msleep(1); |
| |
| /* Make sure that 'match' was called. */ |
| zassert_equal(mock_alg_match_fake.call_count, 1); |
| } |
| |
| ZTEST_USER(fpsensor_match, test_match_no_match_mkbp_event) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_MATCH, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| uint32_t fp_events; |
| |
| /* Load example template. */ |
| zassert_ok(ec_cmd_fp_template( |
| NULL, |
| (struct ec_params_fp_template *)example_template_encrypted, |
| sizeof(example_template_encrypted))); |
| |
| mock_alg_match_fake.return_val = FP_MATCH_RESULT_NO_MATCH; |
| |
| /* Switch mode to match. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_MATCH); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Put finger on the sensor. */ |
| fingerprint_get_state(fp_sim, &state); |
| state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Ping fpsensor task. */ |
| fingerprint_run_callback(fp_sim); |
| |
| /* Give opportunity for fpsensor task process event. */ |
| k_msleep(1); |
| |
| /* Make sure that 'match' was called. */ |
| zassert_equal(mock_alg_match_fake.call_count, 1); |
| |
| /* Confirm MKBP event was sent. */ |
| zassert_equal(mkbp_send_event_fake.call_count, 1); |
| zassert_equal(mkbp_send_event_fake.arg0_val, EC_MKBP_EVENT_FINGERPRINT); |
| |
| /* |
| * Confirm that: |
| * - MKBP event is FP_MATCH |
| * - Match failed with NO_MATCH |
| * - Finger ID is FP_NO_SUCH_TEMPLATE |
| */ |
| fp_get_next_event((uint8_t *)&fp_events); |
| zassert_true(fp_events & EC_MKBP_FP_MATCH); |
| zassert_equal(EC_MKBP_FP_ERRCODE(fp_events), EC_MKBP_FP_ERR_MATCH_NO); |
| zassert_equal(EC_MKBP_FP_MATCH_IDX(fp_events), |
| FP_NO_SUCH_TEMPLATE & 0xF); |
| } |
| |
| static int custom_match(const struct fingerprint_algorithm *const alg, |
| void *templ, uint32_t templ_count, |
| const uint8_t *const image, bool template_update, |
| int32_t *match_index, uint32_t *update_bitmap) |
| { |
| *match_index = finger_index; |
| *update_bitmap = finger_updated_bitmap; |
| |
| return match_result; |
| } |
| |
| static int match_no_update(const struct fingerprint_algorithm *const alg, |
| void *templ, uint32_t templ_count, |
| const uint8_t *const image, bool template_update, |
| int32_t *match_index, uint32_t *update_bitmap) |
| { |
| zassert_false(template_update); |
| zassert_equal(templ_count, 1); |
| |
| return 0; |
| } |
| |
| ZTEST_USER(fpsensor_match, test_match_no_template_update) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_MATCH | FP_MODE_MATCH_NO_TEMPLATE_UPDATE, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| |
| /* Load example template. */ |
| zassert_ok(ec_cmd_fp_template( |
| NULL, |
| (struct ec_params_fp_template *)example_template_encrypted, |
| sizeof(example_template_encrypted))); |
| |
| /* |
| * Use match_no_update function to check if FPSENSOR requested match |
| * without template update. |
| */ |
| mock_alg_match_fake.custom_fake = match_no_update; |
| |
| /* Switch mode to match. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_MATCH); |
| zassert_true(response.mode & FP_MODE_MATCH_NO_TEMPLATE_UPDATE); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Put finger on the sensor. */ |
| fingerprint_get_state(fp_sim, &state); |
| state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Ping fpsensor task. */ |
| fingerprint_run_callback(fp_sim); |
| |
| /* Give opportunity for fpsensor task process event. */ |
| k_msleep(1); |
| |
| /* Make sure that 'match' was called. */ |
| zassert_equal(mock_alg_match_fake.call_count, 1); |
| } |
| |
| ZTEST_USER(fpsensor_match, test_match_success_mkbp_event) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_MATCH, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| uint32_t fp_events; |
| |
| /* Load example template. */ |
| zassert_ok(ec_cmd_fp_template( |
| NULL, |
| (struct ec_params_fp_template *)example_template_encrypted, |
| sizeof(example_template_encrypted))); |
| |
| match_result = FP_MATCH_RESULT_MATCH; |
| finger_index = 0; |
| finger_updated_bitmap = 0; |
| mock_alg_match_fake.custom_fake = custom_match; |
| |
| /* Switch mode to match. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_MATCH); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Put finger on the sensor. */ |
| fingerprint_get_state(fp_sim, &state); |
| state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Ping fpsensor task. */ |
| fingerprint_run_callback(fp_sim); |
| |
| /* Give opportunity for fpsensor task process event. */ |
| k_msleep(1); |
| |
| /* Make sure that 'match' was called. */ |
| zassert_equal(mock_alg_match_fake.call_count, 1); |
| |
| /* Confirm MKBP event was sent. */ |
| zassert_equal(mkbp_send_event_fake.call_count, 1); |
| zassert_equal(mkbp_send_event_fake.arg0_val, EC_MKBP_EVENT_FINGERPRINT); |
| |
| /* |
| * Confirm that: |
| * - MKBP event is FP_MATCH |
| * - Match succeeded with MATCH_YES |
| * - Finger ID is 0 |
| */ |
| fp_get_next_event((uint8_t *)&fp_events); |
| zassert_true(fp_events & EC_MKBP_FP_MATCH); |
| zassert_equal(EC_MKBP_FP_ERRCODE(fp_events), EC_MKBP_FP_ERR_MATCH_YES); |
| zassert_equal(EC_MKBP_FP_MATCH_IDX(fp_events), 0); |
| } |
| |
| ZTEST_USER(fpsensor_match, test_match_success_template_updated_mkbp_event) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_MATCH, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| uint32_t fp_events; |
| |
| /* Load example template. */ |
| zassert_ok(ec_cmd_fp_template( |
| NULL, |
| (struct ec_params_fp_template *)example_template_encrypted, |
| sizeof(example_template_encrypted))); |
| |
| match_result = FP_MATCH_RESULT_MATCH_UPDATED; |
| finger_index = 0; |
| finger_updated_bitmap = 0x1; |
| mock_alg_match_fake.custom_fake = custom_match; |
| |
| /* Switch mode to match. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_MATCH); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Put finger on the sensor. */ |
| fingerprint_get_state(fp_sim, &state); |
| state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Ping fpsensor task. */ |
| fingerprint_run_callback(fp_sim); |
| |
| /* Give opportunity for fpsensor task process event. */ |
| k_msleep(1); |
| |
| /* Make sure that 'match' was called. */ |
| zassert_equal(mock_alg_match_fake.call_count, 1); |
| |
| /* Confirm MKBP event was sent. */ |
| zassert_equal(mkbp_send_event_fake.call_count, 1); |
| zassert_equal(mkbp_send_event_fake.arg0_val, EC_MKBP_EVENT_FINGERPRINT); |
| |
| /* |
| * Confirm that: |
| * - MKBP event is FP_MATCH |
| * - Match succeeded with MATCH_YES_UPDATED |
| * - Finger ID is 0 |
| */ |
| fp_get_next_event((uint8_t *)&fp_events); |
| zassert_true(fp_events & EC_MKBP_FP_MATCH); |
| zassert_equal(EC_MKBP_FP_ERRCODE(fp_events), |
| EC_MKBP_FP_ERR_MATCH_YES_UPDATED); |
| zassert_equal(EC_MKBP_FP_MATCH_IDX(fp_events), 0); |
| } |
| |
| ZTEST_USER(fpsensor_match, test_match_success_template_update_failed_mkbp_event) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_MATCH, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| uint32_t fp_events; |
| |
| /* Load example template. */ |
| zassert_ok(ec_cmd_fp_template( |
| NULL, |
| (struct ec_params_fp_template *)example_template_encrypted, |
| sizeof(example_template_encrypted))); |
| |
| match_result = FP_MATCH_RESULT_MATCH_UPDATE_FAILED; |
| finger_index = 0; |
| finger_updated_bitmap = 0; |
| mock_alg_match_fake.custom_fake = custom_match; |
| |
| /* Switch mode to match. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_MATCH); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Put finger on the sensor. */ |
| fingerprint_get_state(fp_sim, &state); |
| state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Ping fpsensor task. */ |
| fingerprint_run_callback(fp_sim); |
| |
| /* Give opportunity for fpsensor task process event. */ |
| k_msleep(1); |
| |
| /* Make sure that 'match' was called. */ |
| zassert_equal(mock_alg_match_fake.call_count, 1); |
| |
| /* Confirm MKBP event was sent. */ |
| zassert_equal(mkbp_send_event_fake.call_count, 1); |
| zassert_equal(mkbp_send_event_fake.arg0_val, EC_MKBP_EVENT_FINGERPRINT); |
| |
| /* |
| * Confirm that: |
| * - MKBP event is FP_MATCH |
| * - Match succeeded with MATCH_YES_UPDATE_FAILED |
| * - Finger ID is 0 |
| */ |
| fp_get_next_event((uint8_t *)&fp_events); |
| zassert_true(fp_events & EC_MKBP_FP_MATCH); |
| zassert_equal(EC_MKBP_FP_ERRCODE(fp_events), |
| EC_MKBP_FP_ERR_MATCH_YES_UPDATE_FAILED); |
| zassert_equal(EC_MKBP_FP_MATCH_IDX(fp_events), 0); |
| } |
| |
| ZTEST_USER(fpsensor_match, test_match_success_template_updated_dirty_template) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_MATCH, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| |
| /* Load example template. */ |
| zassert_ok(ec_cmd_fp_template( |
| NULL, |
| (struct ec_params_fp_template *)example_template_encrypted, |
| sizeof(example_template_encrypted))); |
| |
| match_result = FP_MATCH_RESULT_MATCH_UPDATED; |
| finger_index = 0; |
| finger_updated_bitmap = 0x1; |
| mock_alg_match_fake.custom_fake = custom_match; |
| |
| /* Switch mode to match. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_MATCH); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Put finger on the sensor. */ |
| fingerprint_get_state(fp_sim, &state); |
| state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Ping fpsensor task. */ |
| fingerprint_run_callback(fp_sim); |
| |
| /* Give opportunity for fpsensor task process event. */ |
| k_msleep(1); |
| |
| /* Make sure that 'match' was called. */ |
| zassert_equal(mock_alg_match_fake.call_count, 1); |
| |
| /* Confirm that dirty templates bitmap is correct. */ |
| zassert_ok(ec_cmd_fp_info_v3(NULL, test_info_buffer, |
| test_info_buffer_size)); |
| zassert_equal(test_info_buffer->template_info.template_dirty, 0x1); |
| } |
| |
| ZTEST_USER(fpsensor_match, |
| test_match_success_template_update_failed_dirty_template) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_MATCH, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| |
| /* Load example template. */ |
| zassert_ok(ec_cmd_fp_template( |
| NULL, |
| (struct ec_params_fp_template *)example_template_encrypted, |
| sizeof(example_template_encrypted))); |
| |
| match_result = FP_MATCH_RESULT_MATCH_UPDATE_FAILED; |
| finger_index = 0; |
| finger_updated_bitmap = 0x1; |
| mock_alg_match_fake.custom_fake = custom_match; |
| |
| /* Switch mode to match. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_MATCH); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Put finger on the sensor. */ |
| fingerprint_get_state(fp_sim, &state); |
| state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Ping fpsensor task. */ |
| fingerprint_run_callback(fp_sim); |
| |
| /* Give opportunity for fpsensor task process event. */ |
| k_msleep(1); |
| |
| /* Make sure that 'match' was called. */ |
| zassert_equal(mock_alg_match_fake.call_count, 1); |
| |
| /* Confirm that dirty templates bitmap is correct. */ |
| zassert_ok(ec_cmd_fp_info_v3(NULL, test_info_buffer, |
| test_info_buffer_size)); |
| zassert_equal(test_info_buffer->template_info.template_dirty, 0x0); |
| } |
| |
| ZTEST_USER(fpsensor_match, test_match_success_no_template_update_dirty_template) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_MATCH, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| |
| /* Load example template. */ |
| zassert_ok(ec_cmd_fp_template( |
| NULL, |
| (struct ec_params_fp_template *)example_template_encrypted, |
| sizeof(example_template_encrypted))); |
| |
| match_result = FP_MATCH_RESULT_MATCH; |
| finger_index = 0; |
| finger_updated_bitmap = 0x1; |
| mock_alg_match_fake.custom_fake = custom_match; |
| |
| /* Switch mode to match. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_MATCH); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Put finger on the sensor. */ |
| fingerprint_get_state(fp_sim, &state); |
| state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Ping fpsensor task. */ |
| fingerprint_run_callback(fp_sim); |
| |
| /* Give opportunity for fpsensor task process event. */ |
| k_msleep(1); |
| |
| /* Make sure that 'match' was called. */ |
| zassert_equal(mock_alg_match_fake.call_count, 1); |
| |
| /* Confirm that dirty templates bitmap is correct. */ |
| zassert_ok(ec_cmd_fp_info_v3(NULL, test_info_buffer, |
| test_info_buffer_size)); |
| zassert_equal(test_info_buffer->template_info.template_dirty, 0x0); |
| } |
| |
| ZTEST_USER(fpsensor_match, test_match_no_template_update_dirty_template) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_MATCH | FP_MODE_MATCH_NO_TEMPLATE_UPDATE, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| |
| /* Load example template. */ |
| zassert_ok(ec_cmd_fp_template( |
| NULL, |
| (struct ec_params_fp_template *)example_template_encrypted, |
| sizeof(example_template_encrypted))); |
| |
| /* Return MATCH_YES but NOT updated because we requested no update. */ |
| match_result = FP_MATCH_RESULT_MATCH; |
| finger_index = 0; |
| finger_updated_bitmap = 0x1; |
| mock_alg_match_fake.custom_fake = custom_match; |
| |
| /* Switch mode to match. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_MATCH); |
| zassert_true(response.mode & FP_MODE_MATCH_NO_TEMPLATE_UPDATE); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Put finger on the sensor. */ |
| fingerprint_get_state(fp_sim, &state); |
| state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Ping fpsensor task. */ |
| fingerprint_run_callback(fp_sim); |
| |
| /* Give opportunity for fpsensor task process event. */ |
| k_msleep(1); |
| |
| /* Confirm that dirty templates bitmap is correct (no templates dirty). |
| */ |
| zassert_ok(ec_cmd_fp_info_v3(NULL, test_info_buffer, |
| test_info_buffer_size)); |
| zassert_equal(test_info_buffer->template_info.template_dirty, 0x0); |
| } |
| |
| ZTEST_USER(fpsensor_match, |
| test_match_success_read_positive_match_secret_allowed) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_MATCH, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| struct ec_params_fp_read_match_secret secret_params; |
| struct ec_response_fp_read_match_secret secret_response; |
| |
| /* Load example template. */ |
| zassert_ok(ec_cmd_fp_template( |
| NULL, |
| (struct ec_params_fp_template *)example_template_encrypted, |
| sizeof(example_template_encrypted))); |
| |
| match_result = FP_MATCH_RESULT_MATCH; |
| finger_index = 0; |
| finger_updated_bitmap = 0x1; |
| mock_alg_match_fake.custom_fake = custom_match; |
| |
| /* Switch mode to match. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_MATCH); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Put finger on the sensor. */ |
| fingerprint_get_state(fp_sim, &state); |
| state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Ping fpsensor task. */ |
| fingerprint_run_callback(fp_sim); |
| |
| /* Give opportunity for fpsensor task process event. */ |
| k_msleep(1); |
| |
| /* Make sure that 'match' was called. */ |
| zassert_equal(mock_alg_match_fake.call_count, 1); |
| |
| /* Read positive match secret for matched template. */ |
| secret_params.fgr = 0; |
| zassert_ok(ec_cmd_fp_read_match_secret(NULL, &secret_params, |
| &secret_response)); |
| zassert_mem_equal(secret_response.positive_match_secret, |
| example_positive_match_secret, |
| FP_POSITIVE_MATCH_SECRET_BYTES); |
| } |
| |
| ZTEST_USER(fpsensor_match, |
| test_match_success_read_positive_match_secret_timeout) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_MATCH, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| struct ec_params_fp_read_match_secret secret_params; |
| struct ec_response_fp_read_match_secret secret_response; |
| |
| /* Load example template. */ |
| zassert_ok(ec_cmd_fp_template( |
| NULL, |
| (struct ec_params_fp_template *)example_template_encrypted, |
| sizeof(example_template_encrypted))); |
| |
| match_result = FP_MATCH_RESULT_MATCH; |
| finger_index = 0; |
| finger_updated_bitmap = 0x1; |
| mock_alg_match_fake.custom_fake = custom_match; |
| |
| /* Switch mode to match. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_MATCH); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Put finger on the sensor. */ |
| fingerprint_get_state(fp_sim, &state); |
| state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Ping fpsensor task. */ |
| fingerprint_run_callback(fp_sim); |
| |
| /* Give opportunity for fpsensor task process event. */ |
| k_msleep(1); |
| |
| /* Make sure that 'match' was called. */ |
| zassert_equal(mock_alg_match_fake.call_count, 1); |
| |
| /* Wait at least 15 seconds for positive match secret to timeout. */ |
| k_msleep(15000); |
| |
| /* Confirm that we can't read positive match secret. */ |
| secret_params.fgr = 0; |
| zassert_equal(EC_RES_TIMEOUT, |
| ec_cmd_fp_read_match_secret(NULL, &secret_params, |
| &secret_response)); |
| } |
| |
| ZTEST_USER(fpsensor_match, test_match_success_read_positive_match_secret_twice) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_MATCH, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| struct ec_params_fp_read_match_secret secret_params; |
| struct ec_response_fp_read_match_secret secret_response; |
| |
| /* Load example template. */ |
| zassert_ok(ec_cmd_fp_template( |
| NULL, |
| (struct ec_params_fp_template *)example_template_encrypted, |
| sizeof(example_template_encrypted))); |
| |
| match_result = FP_MATCH_RESULT_MATCH; |
| finger_index = 0; |
| finger_updated_bitmap = 0x1; |
| mock_alg_match_fake.custom_fake = custom_match; |
| |
| /* Switch mode to match. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_MATCH); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Put finger on the sensor. */ |
| fingerprint_get_state(fp_sim, &state); |
| state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Ping fpsensor task. */ |
| fingerprint_run_callback(fp_sim); |
| |
| /* Give opportunity for fpsensor task process event. */ |
| k_msleep(1); |
| |
| /* Make sure that 'match' was called. */ |
| zassert_equal(mock_alg_match_fake.call_count, 1); |
| |
| secret_params.fgr = 0; |
| |
| /* Expect that we can read positive match secret for the first time. */ |
| zassert_ok(ec_cmd_fp_read_match_secret(NULL, &secret_params, |
| &secret_response)); |
| |
| /* |
| * Confirm that we can't read positive match secret for the second time. |
| */ |
| zassert_equal(EC_RES_TIMEOUT, |
| ec_cmd_fp_read_match_secret(NULL, &secret_params, |
| &secret_response)); |
| } |
| |
| ZTEST_USER(fpsensor_match, |
| test_match_read_positive_match_secret_without_match_fails) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_MATCH, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| struct ec_params_fp_read_match_secret secret_params; |
| struct ec_response_fp_read_match_secret secret_response; |
| |
| /* Load example template. */ |
| zassert_ok(ec_cmd_fp_template( |
| NULL, |
| (struct ec_params_fp_template *)example_template_encrypted, |
| sizeof(example_template_encrypted))); |
| |
| mock_alg_match_fake.return_val = FP_MATCH_RESULT_NO_MATCH; |
| |
| /* Switch mode to match. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_MATCH); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Put finger on the sensor. */ |
| fingerprint_get_state(fp_sim, &state); |
| state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Ping fpsensor task. */ |
| fingerprint_run_callback(fp_sim); |
| |
| /* Give opportunity for fpsensor task process event. */ |
| k_msleep(1); |
| |
| /* Make sure that 'match' was called. */ |
| zassert_equal(mock_alg_match_fake.call_count, 1); |
| |
| /* Confirm that we can't read positive match secret. */ |
| secret_params.fgr = 0; |
| zassert_equal(EC_RES_TIMEOUT, |
| ec_cmd_fp_read_match_secret(NULL, &secret_params, |
| &secret_response)); |
| } |
| |
| ZTEST_USER(fpsensor_match, test_match_error_no_positive_match_secret) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_MATCH, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| struct ec_params_fp_read_match_secret secret_params; |
| struct ec_response_fp_read_match_secret secret_response; |
| |
| /* Load example template. */ |
| zassert_ok(ec_cmd_fp_template( |
| NULL, |
| (struct ec_params_fp_template *)example_template_encrypted, |
| sizeof(example_template_encrypted))); |
| |
| /* Negative value means error. */ |
| mock_alg_match_fake.return_val = -1; |
| |
| /* Switch mode to match. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_MATCH); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Put finger on the sensor. */ |
| fingerprint_get_state(fp_sim, &state); |
| state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Ping fpsensor task. */ |
| fingerprint_run_callback(fp_sim); |
| |
| /* Give opportunity for fpsensor task process event. */ |
| k_msleep(1); |
| |
| /* Make sure that 'match' was called. */ |
| zassert_equal(mock_alg_match_fake.call_count, 1); |
| |
| /* Confirm that we can't read positive match secret. */ |
| secret_params.fgr = 0; |
| zassert_equal(EC_RES_TIMEOUT, |
| ec_cmd_fp_read_match_secret(NULL, &secret_params, |
| &secret_response)); |
| } |
| |
| ZTEST_USER(fpsensor_match, test_match_error_mkbp_event) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_MATCH, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| uint32_t fp_events; |
| |
| /* Load example template. */ |
| zassert_ok(ec_cmd_fp_template( |
| NULL, |
| (struct ec_params_fp_template *)example_template_encrypted, |
| sizeof(example_template_encrypted))); |
| |
| /* Negative value means error. */ |
| mock_alg_match_fake.return_val = -1; |
| |
| /* Switch mode to match. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_MATCH); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Put finger on the sensor. */ |
| fingerprint_get_state(fp_sim, &state); |
| state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Ping fpsensor task. */ |
| fingerprint_run_callback(fp_sim); |
| |
| /* Give opportunity for fpsensor task process event. */ |
| k_msleep(1); |
| |
| /* Make sure that 'match' was called. */ |
| zassert_equal(mock_alg_match_fake.call_count, 1); |
| |
| /* Confirm MKBP event was sent. */ |
| zassert_equal(mkbp_send_event_fake.call_count, 1); |
| zassert_equal(mkbp_send_event_fake.arg0_val, EC_MKBP_EVENT_FINGERPRINT); |
| |
| /* |
| * Confirm that: |
| * - MKBP event is FP_MATCH |
| * - Match failed with NO_INTERNAL |
| * - Finger ID is FP_NO_SUCH_TEMPLATE |
| */ |
| fp_get_next_event((uint8_t *)&fp_events); |
| zassert_true(fp_events & EC_MKBP_FP_MATCH); |
| zassert_equal(EC_MKBP_FP_ERRCODE(fp_events), |
| EC_MKBP_FP_ERR_MATCH_NO_INTERNAL); |
| zassert_equal(EC_MKBP_FP_MATCH_IDX(fp_events), |
| FP_NO_SUCH_TEMPLATE & 0xF); |
| } |
| |
| static void *fpsensor_setup(void) |
| { |
| struct ec_params_fp_seed fp_seed_params = { |
| .struct_version = 4, |
| .reserved = 0, |
| .seed = FAKE_TPM_SEED, |
| }; |
| |
| /* Start shimmed tasks. */ |
| start_ec_tasks(); |
| k_msleep(100); |
| |
| /* Add some entropy to rollback region. */ |
| rollback_add_entropy(fake_rollback_entropy, |
| sizeof(fake_rollback_entropy) - 1); |
| |
| /* Set TPM seed. */ |
| ec_cmd_fp_seed(NULL, &fp_seed_params); |
| |
| return NULL; |
| } |
| |
| static void fpsensor_before(void *f) |
| { |
| struct fingerprint_sensor_state state = { |
| .bad_pixels = 0, |
| .maintenance_ran = false, |
| .detect_mode = false, |
| .low_power_mode = false, |
| .finger_state = FINGERPRINT_FINGER_STATE_NONE, |
| .init_result = 0, |
| .deinit_result = 0, |
| .config_result = 0, |
| .get_info_result = 0, |
| .acquire_image_result = FINGERPRINT_SENSOR_SCAN_GOOD, |
| .last_acquire_image_mode = -1, |
| }; |
| struct ec_params_fp_context_v1 fp_context_params = { |
| .action = FP_CONTEXT_ASYNC, |
| .userid = FAKE_USER_ID, |
| }; |
| uint32_t fp_events; |
| |
| fingerprint_set_state(fp_sim, &state); |
| RESET_FAKE(mkbp_send_event); |
| |
| RESET_FAKE(mock_alg_init); |
| RESET_FAKE(mock_alg_exit); |
| RESET_FAKE(mock_alg_enroll_start); |
| RESET_FAKE(mock_alg_enroll_step); |
| RESET_FAKE(mock_alg_enroll_finish); |
| RESET_FAKE(mock_alg_match); |
| |
| match_result = 0; |
| finger_index = 0; |
| finger_updated_bitmap = 0; |
| |
| /* Set context (FP_CONTEXT_ASYNC). */ |
| ec_cmd_fp_context_v1(NULL, &fp_context_params); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Get context setting result. */ |
| fp_context_params.action = FP_CONTEXT_GET_RESULT; |
| ec_cmd_fp_context_v1(NULL, &fp_context_params); |
| |
| /* Clear MKBP events from previous tests. */ |
| fp_get_next_event((uint8_t *)&fp_events); |
| } |
| |
| ZTEST_SUITE(fpsensor_match, NULL, fpsensor_setup, fpsensor_before, NULL, NULL); |