diff options
Diffstat (limited to 'test/fpsensor.c')
-rw-r--r-- | test/fpsensor.c | 176 |
1 files changed, 175 insertions, 1 deletions
diff --git a/test/fpsensor.c b/test/fpsensor.c index b31aa3b259..962295afbf 100644 --- a/test/fpsensor.c +++ b/test/fpsensor.c @@ -8,6 +8,7 @@ #include "fpsensor_crypto.h" #include "fpsensor_state.h" #include "host_command.h" +#include "mock/timer_mock.h" #include "test_util.h" #include "util.h" @@ -38,7 +39,8 @@ static const uint8_t fake_user_id[] = { }; /* - * |expected_positive_match_secret| is obtained by running BoringSSL locally. + * |expected_positive_match_secret_for_empty_user_id| is obtained by running + * BoringSSL locally. * From https://boringssl.googlesource.com/boringssl * commit 365b7a0fcbf273b1fa704d151059e419abd6cfb8 * @@ -601,6 +603,172 @@ test_static int test_fp_set_sensor_mode(void) return EC_SUCCESS; } +test_static int test_enable_positive_match_secret(void) +{ + struct positive_match_secret_state dumb_state = { + .template_matched = FP_NO_SUCH_TEMPLATE, + .readable = false, + .deadline.val = 0, + }; + timestamp_t now = get_time(); + + TEST_ASSERT(fp_enable_positive_match_secret(0, &dumb_state) == + EC_SUCCESS); + TEST_ASSERT(dumb_state.template_matched == 0); + TEST_ASSERT(dumb_state.readable == true); + TEST_ASSERT(dumb_state.deadline.val == now.val + (5 * SECOND)); + + /* Trying to enable again before reading secret should fail. */ + TEST_ASSERT(fp_enable_positive_match_secret(0, &dumb_state) == + EC_ERROR_UNKNOWN); + TEST_ASSERT(dumb_state.template_matched == FP_NO_SUCH_TEMPLATE); + TEST_ASSERT(dumb_state.readable == false); + TEST_ASSERT(dumb_state.deadline.val == 0); + + return EC_SUCCESS; +} + +test_static int test_disable_positive_match_secret(void) +{ + struct positive_match_secret_state dumb_state; + + TEST_ASSERT(fp_enable_positive_match_secret(0, &dumb_state) == + EC_SUCCESS); + fp_disable_positive_match_secret(&dumb_state); + TEST_ASSERT(dumb_state.template_matched == FP_NO_SUCH_TEMPLATE); + TEST_ASSERT(dumb_state.readable == false); + TEST_ASSERT(dumb_state.deadline.val == 0); + + return EC_SUCCESS; +} + +test_static int test_command_read_match_secret(void) +{ + int rv; + struct ec_params_fp_read_match_secret params; + struct ec_response_fp_read_match_secret resp; + timestamp_t now = get_time(); + + /* Invalid finger index should be rejected. */ + params.fgr = FP_NO_SUCH_TEMPLATE; + rv = test_send_host_command(EC_CMD_FP_READ_MATCH_SECRET, 0, ¶ms, + sizeof(params), NULL, 0); + TEST_ASSERT(rv == EC_RES_INVALID_PARAM); + params.fgr = FP_MAX_FINGER_COUNT; + rv = test_send_host_command(EC_CMD_FP_READ_MATCH_SECRET, 0, ¶ms, + sizeof(params), NULL, 0); + TEST_ASSERT(rv == EC_RES_INVALID_PARAM); + + memset(&resp, 0, sizeof(resp)); + /* GIVEN that finger index is valid. */ + params.fgr = 0; + + /* GIVEN that positive match secret is enabled. */ + fp_enable_positive_match_secret(params.fgr, + &positive_match_secret_state); + + /* GIVEN that salt is non-trivial. */ + memcpy(fp_positive_match_salt[0], fake_positive_match_salt, + sizeof(fp_positive_match_salt[0])); + /* THEN reading positive match secret should succeed. */ + rv = test_send_host_command(EC_CMD_FP_READ_MATCH_SECRET, 0, ¶ms, + sizeof(params), &resp, sizeof(resp)); + if (rv != EC_RES_SUCCESS) { + ccprintf("%s:%s(): rv = %d\n", __FILE__, __func__, rv); + return -1; + } + /* AND the readable bit should be cleared after the read. */ + TEST_ASSERT(positive_match_secret_state.readable == false); + + TEST_ASSERT_ARRAY_EQ( + resp.positive_match_secret, + expected_positive_match_secret_for_empty_user_id, + sizeof(expected_positive_match_secret_for_empty_user_id)); + + /* + * Now try reading secret again. + * EVEN IF the deadline has not passed. + */ + positive_match_secret_state.deadline.val = now.val + 1 * SECOND; + rv = test_send_host_command(EC_CMD_FP_READ_MATCH_SECRET, 0, ¶ms, + sizeof(params), NULL, 0); + /* + * This time the command should fail because the + * fp_pos_match_secret_readable bit is cleared when the secret was read + * the first time. + */ + TEST_ASSERT(rv == EC_RES_ACCESS_DENIED); + + return EC_SUCCESS; +} + +test_static int test_command_read_match_secret_wrong_finger(void) +{ + int rv; + struct ec_params_fp_read_match_secret params; + + /* GIVEN that the finger is not the matched or enrolled finger. */ + params.fgr = 0; + /* + * GIVEN that positive match secret is enabled for a different + * finger. + */ + fp_enable_positive_match_secret(params.fgr + 1, + &positive_match_secret_state); + + /* Reading secret will fail. */ + rv = test_send_host_command(EC_CMD_FP_READ_MATCH_SECRET, 0, ¶ms, + sizeof(params), NULL, 0); + TEST_ASSERT(rv == EC_RES_ACCESS_DENIED); + return EC_SUCCESS; +} + +test_static int test_command_read_match_secret_timeout(void) +{ + int rv; + struct ec_params_fp_read_match_secret params; + + params.fgr = 0; + /* GIVEN that the read is too late. */ + fp_enable_positive_match_secret(params.fgr, + &positive_match_secret_state); + set_time(positive_match_secret_state.deadline); + + /* EVEN IF encryption salt is non-trivial. */ + memcpy(fp_positive_match_salt[0], fake_positive_match_salt, + sizeof(fp_positive_match_salt[0])); + /* Reading secret will fail. */ + rv = test_send_host_command(EC_CMD_FP_READ_MATCH_SECRET, 0, ¶ms, + sizeof(params), NULL, 0); + TEST_ASSERT(rv == EC_RES_TIMEOUT); + return EC_SUCCESS; +} + +test_static int test_command_read_match_secret_unreadable(void) +{ + int rv; + struct ec_params_fp_read_match_secret params; + + params.fgr = 0; + /* GIVEN that the readable bit is not set. */ + fp_enable_positive_match_secret(params.fgr, + &positive_match_secret_state); + positive_match_secret_state.readable = false; + + /* EVEN IF the finger is just matched. */ + TEST_ASSERT(positive_match_secret_state.template_matched + == params.fgr); + + /* EVEN IF encryption salt is non-trivial. */ + memcpy(fp_positive_match_salt[0], fake_positive_match_salt, + sizeof(fp_positive_match_salt[0])); + /* Reading secret will fail. */ + rv = test_send_host_command(EC_CMD_FP_READ_MATCH_SECRET, 0, ¶ms, + sizeof(params), NULL, 0); + TEST_ASSERT(rv == EC_RES_ACCESS_DENIED); + return EC_SUCCESS; +} + void run_test(void) { /* These are independent of global state. */ @@ -622,6 +790,12 @@ void run_test(void) RUN_TEST(test_derive_new_pos_match_secret); RUN_TEST(test_derive_positive_match_secret_fail_rollback_fail); RUN_TEST(test_derive_positive_match_secret_fail_salt_trivial); + RUN_TEST(test_enable_positive_match_secret); + RUN_TEST(test_disable_positive_match_secret); + RUN_TEST(test_command_read_match_secret); + RUN_TEST(test_command_read_match_secret_wrong_finger); + RUN_TEST(test_command_read_match_secret_timeout); + RUN_TEST(test_command_read_match_secret_unreadable); test_print_result(); } |