summaryrefslogtreecommitdiff
path: root/test/fpsensor.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/fpsensor.c')
-rw-r--r--test/fpsensor.c176
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, &params,
+ 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, &params,
+ 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, &params,
+ 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, &params,
+ 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, &params,
+ 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, &params,
+ 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, &params,
+ 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();
}