diff options
Diffstat (limited to 'src/faceauth_tests.cc')
-rw-r--r-- | src/faceauth_tests.cc | 1349 |
1 files changed, 1028 insertions, 321 deletions
diff --git a/src/faceauth_tests.cc b/src/faceauth_tests.cc index 32088fa..14a01cb 100644 --- a/src/faceauth_tests.cc +++ b/src/faceauth_tests.cc @@ -16,49 +16,44 @@ using std::unique_ptr; namespace { +vector<uint8_t> EMBEDDING_VECTOR_NULL(128, 0); +const vector<uint8_t> EMBEDDING_VECTOR_1(64, 16); +const vector<uint8_t> EMBEDDING_VECTOR_2(64, (uint8_t)-16); + +const uint32_t PROFILE_1 = 1; +const uint32_t PROFILE_2 = 2; +const uint32_t PROFILE_3 = 3; +const uint32_t PROFILE_4 = 4; +const uint32_t PROFILE_5 = 5; +const uint32_t PROFILE_6 = 6; + class FaceAuthTest: public testing::Test { + public: + static unique_ptr<nos::NuggetClientInterface> client; + static unique_ptr<test_harness::TestHarness> uart_printer; + protected: void SetUp() override; static void SetUpTestCase(); static void TearDownTestCase(); - - static unique_ptr<nos::NuggetClientInterface> client; - static unique_ptr<test_harness::TestHarness> uart_printer; - - static const fa_result_t RunTask(const fa_task_t task, - const fa_embedding_t* embed = NULL, - const fa_token_t* token = NULL); - static void Run(const fa_result_t expected, const fa_task_t task, - const fa_embedding_t* embed = NULL, - const fa_token_t* token = NULL); - - static void LockProfileTest(uint32_t profile1); - static void UnlockProfileTest(uint32_t profile1); - static bool IsProfileLocked(uint32_t profile1); - static void UnockProfileTest(uint32_t profile1); - static void FullMatchMismatchTest(uint32_t profile1, uint32_t profile2, - uint32_t slot1, uint32_t slot2); - static fa_token_t MakeToken(uint32_t profile_id); - - static vector<uint64_t> user_ids; + static void DisengageGlobalLockout(); }; -vector<uint64_t> FaceAuthTest::user_ids; - unique_ptr<nos::NuggetClientInterface> FaceAuthTest::client; unique_ptr<test_harness::TestHarness> FaceAuthTest::uart_printer; void FaceAuthTest::SetUpTestCase() { srand(time(NULL)); - for (int i = 0; i < MAX_NUM_PROFILES; ++i) { - user_ids.push_back(rand()); - } uart_printer = test_harness::TestHarness::MakeUnique(); client = nugget_tools::MakeNuggetClient(); client->Open(); EXPECT_TRUE(client->IsOpen()) << "Unable to connect"; + + /* We need any embedding vector to have magnitude of 128 */ + EMBEDDING_VECTOR_NULL[127] = 128; + DisengageGlobalLockout(); } void FaceAuthTest::TearDownTestCase() { @@ -86,369 +81,1081 @@ uint8_t CalcCrc8(const uint8_t *data, int len) return (uint8_t)(crc >> 8); } -static fa_task_t MakeTask(uint64_t session_id, uint32_t profile_id, - uint32_t cmd, uint32_t input_data1 = 0, - uint32_t input_data2 = 0, - uint32_t version = FACEAUTH_MIN_ABH_VERSION) { +class Task { + public: + Task(uint32_t profile_id, uint32_t cmd, + uint32_t version = FACEAUTH_MIN_ABH_VERSION) { + memset(&task, 0, sizeof(task)); + task.version = version; + task.session_id = 0xFACEBEEFBEEFFACEull; + task.profile_id = profile_id; + task.cmd = cmd; + } + + Task& SetFirst(uint64_t first) { + task.input.data.first = first; + return *this; + } + + Task& SetChallenge(uint64_t challenge) { + memcpy(task.input.challenge, &challenge, sizeof(challenge)); + return *this; + } + + Task& Finalize() { + task.crc = CalcCrc8(reinterpret_cast<const uint8_t*>(&task), + offsetof(struct fa_task_t, crc)); + return *this; + } + + vector<uint8_t> ToBuffer() { + vector<uint8_t> buffer; + for (size_t i = 0; i < sizeof(fa_task_t); ++i) { + buffer.push_back(*(reinterpret_cast<const uint8_t*>(&task) + i)); + } + return buffer; + } + + private: fa_task_t task; - task.version = version; - task.session_id = session_id; - task.profile_id = profile_id; - task.cmd = cmd; - task.input.data.first = input_data1; - task.input.data.second = input_data2; - task.crc = CalcCrc8(reinterpret_cast<const uint8_t*>(&task), - offsetof(struct fa_task_t, crc)); - return task; -} - -static fa_embedding_t* MakeEmbedding(uint32_t base, uint32_t version = 1) { - static fa_embedding_t embed; - memset(&embed, base, sizeof(fa_embedding_t)); - embed.version = version; - embed.valid = 0; - embed.crc = CalcCrc8(reinterpret_cast<const uint8_t*>(&embed), - offsetof(struct fa_embedding_t, crc)); - return &embed; -} - -static fa_result_t MakeResult(uint64_t session_id, int32_t error, - uint32_t output_data1 = 0, - uint32_t output_data2 = 0, - uint32_t lockout_event = FACEAUTH_LOCKOUT_NOP) { - fa_result_t result; - memset(&result, 0, sizeof(fa_result_t)); - result.version = 1; - result.session_id = session_id; - result.error = error; - result.output.data.first = output_data1; - result.output.data.second = output_data2; - result.lockout_event = lockout_event; - result.complete = 1; - result.crc = CalcCrc8(reinterpret_cast<const uint8_t*>(&result), - offsetof(struct fa_result_t, crc)); - return result; -} - -fa_token_t FaceAuthTest::MakeToken(uint32_t profile_id) { +}; + +class Embedding { + public: + Embedding() { memset(&embed, 0, sizeof(embed)); } + Embedding(vector<uint8_t> base, uint32_t version = 1) { + memset(&embed, 0, sizeof(embed)); + embed.version = version; + embed.valid = 0; + std::copy(base.begin(), base.end(), &embed.face_id[0]); + std::copy(base.begin(), base.end(), &embed.depth_id[0]); + } + + void Finalize() { + embed.crc = CalcCrc8(reinterpret_cast<const uint8_t*>(&embed), + offsetof(struct fa_embedding_t, crc)); + } + + vector<uint8_t> ToBuffer() { + vector<uint8_t> buffer; + for (size_t i = 0; i < sizeof(fa_embedding_t); ++i) { + buffer.push_back(*(reinterpret_cast<const uint8_t*>(&embed) + i)); + } + return buffer; + } + + private: + fa_embedding_t embed; +}; + +class Token { + public: + Token() { memset(&token, 0, sizeof(token)); } + + Token(fa_token_t token) : token(token) {} + + Token(uint64_t challenge, uint64_t user_id, uint64_t auth_id) { + memset(&token, 0, sizeof(token)); + token.challenge = challenge; + token.user_id = user_id; + token.authenticator_id = auth_id; + } + + vector<uint8_t> ToBuffer() { + vector<uint8_t> buffer; + for (size_t i = 0; i < sizeof(fa_token_t); ++i) { + buffer.push_back(*(reinterpret_cast<const uint8_t*>(&token) + i)); + } + return buffer; + } + + fa_token_t GetRaw() { return token; } + + private: fa_token_t token; - token.user_id = user_ids[profile_id]; - return token; +}; + +class Result { + public: + Result() { memset(&result, 0, sizeof(result)); } + + Result(fa_result_t result) : result(result) {} + + Result(int32_t error) { + memset(&result, 0, sizeof(result)); + SetError(error); + } + + fa_result_t GetRaw() { + Finalize(); + return result; + } + + Result& SetError(int32_t error) { + result.error = error; + return *this; + } + + Result& SetChallenge(uint64_t challenge) { + memcpy(result.output.challenge, &challenge, sizeof(challenge)); + return *this; + } + + Result& SetSecond(uint32_t second) { + result.output.data.second = second; + return *this; + } + + Result& SetThird(uint32_t third) { + result.output.data.third = third; + return *this; + } + + uint64_t GetChallenge() { + uint64_t challenge; + memcpy(&challenge, result.output.challenge, sizeof(challenge)); + return challenge; + } + + uint32_t GetFirst() { return result.output.data.first; } + uint32_t GetSecond() { return result.output.data.second; } + + Result& Finalize() { + result.version = 1; + result.session_id = 0xFACEBEEFBEEFFACEull; + result.complete = 1; + result.crc = CalcCrc8(reinterpret_cast<const uint8_t*>(&result), + offsetof(struct fa_result_t, crc)); + return *this; + } + + protected: + fa_result_t result; +}; + +static void EXPECT_REQ(Result r1, Result r2) { + fa_result_t observed = r1.GetRaw(); + fa_result_t expected = r2.GetRaw(); + + EXPECT_EQ(observed.version, expected.version); + EXPECT_EQ(observed.session_id, expected.session_id); + EXPECT_EQ(observed.error, expected.error); + EXPECT_EQ(observed.output.data.first, expected.output.data.first); + EXPECT_EQ(observed.output.data.second, expected.output.data.second); + EXPECT_EQ(observed.output.data.third, expected.output.data.third); + EXPECT_EQ(observed.complete, expected.complete); + EXPECT_EQ(observed.crc, expected.crc); +} + +class ResetLockoutResult : public Result { + public: + ResetLockoutResult(Result result) : Result(result) {} + + ResetLockoutResult(int32_t error) : Result(error) {} + + ResetLockoutResult& SetLockoutEvent(uint32_t lockout_event) { + result.output.data.third = lockout_event; + return *this; + } +}; + +class MigrateResult : public Result { + public: + MigrateResult(Result result) : Result(result) {} + + MigrateResult(int32_t error) : Result(error) {} + + MigrateResult& SetEmbeddingNum(uint32_t num) { + result.output.data.second = num; + return *this; + } + + MigrateResult& SetMatch(bool m) { + result.output.data.third = m; + return *this; + } +}; + +class AuthenticateResult : public Result { + public: + AuthenticateResult(Result result, Token token) + : Result(result), token(token) {} + + AuthenticateResult(int32_t error) : Result(error) {} + + AuthenticateResult& SetMatch(bool m) { + result.output.data.first = m; + return *this; + } + + AuthenticateResult& SetLockoutEvent(uint32_t lockout_event) { + result.output.data.third = lockout_event; + return *this; + } + + Token GetToken() { return token; } + + protected: + Token token; +}; + +static void EXPECT_AEQ(AuthenticateResult r1, AuthenticateResult r2) { + EXPECT_REQ(r1, r2); + + fa_token_t observed = r1.GetToken().GetRaw(); + fa_token_t expected = r2.GetToken().GetRaw(); + + EXPECT_EQ(observed.challenge, expected.challenge); + EXPECT_EQ(observed.user_id, expected.user_id); + EXPECT_EQ(observed.authenticator_id, expected.authenticator_id); } -vector<uint8_t> Task2Buffer(const fa_task_t task, const fa_embedding_t* embed, - const fa_token_t* token) { - vector<uint8_t> buffer; - for (size_t i = 0; i < sizeof(fa_task_t); ++i) { - buffer.push_back(*(reinterpret_cast<const uint8_t*>(&task) + i)); +class Transaction { + public: + Transaction(Task task, Embedding embed, Token token) + : input_task(task), input_embed(embed), input_token(token) {} + + Transaction& Finalize() { + input_task.Finalize(); + input_embed.Finalize(); + return *this; } - for (size_t i = 0; i < sizeof(fa_embedding_t); ++i) { - if (embed) - buffer.push_back(*(reinterpret_cast<const uint8_t*>(embed) + i)); - else - buffer.push_back(0); + + Transaction& Run() { + vector<uint8_t> task = input_task.ToBuffer(); + vector<uint8_t> embed = input_embed.ToBuffer(); + vector<uint8_t> token = input_token.ToBuffer(); + + vector<uint8_t> buffer_rx; + buffer_rx.resize(512); + + vector<uint8_t> buffer_tx; + buffer_tx.insert(buffer_tx.end(), task.begin(), task.end()); + buffer_tx.insert(buffer_tx.end(), embed.begin(), embed.end()); + buffer_tx.insert(buffer_tx.end(), token.begin(), token.end()); + + FaceAuthTest::client->CallApp(APP_ID_FACEAUTH_TEST, 1, buffer_tx, + &buffer_rx); + + struct fa_output_t { + fa_result_t result; + fa_token_t token; + } __attribute__((packed)); + + fa_output_t output = + *(reinterpret_cast<struct fa_output_t*>(buffer_rx.data())); + + output_result = output.result; + output_token = output.token; + + return *this; } - for (size_t i = 0; i < sizeof(fa_token_t); ++i) { - if (token) - buffer.push_back(*(reinterpret_cast<const uint8_t*>(token) + i)); - else - buffer.push_back(0); + + Result GetResult() { return Result(output_result); } + Token GetToken() { return Token(output_token); } + + private: + Task input_task; + Embedding input_embed; + Token input_token; + fa_result_t output_result; + fa_token_t output_token; +}; + +class Device { + public: + static Result Erase(uint32_t profile_id) { + return Transaction(Task(profile_id, FACEAUTH_CMD_ERASE), Embedding(), + Token()) + .Finalize() + .Run() + .GetResult(); + } + + static Result GenerateChallenge() { + Result ret = + Transaction(Task(0, FACEAUTH_CMD_GET_CHALLENGE), Embedding(), Token()) + .Finalize() + .Run() + .GetResult(); + memcpy(&challenge, ret.GetRaw().output.challenge, sizeof(challenge)); + return ret; + } + + static Result RevokeChallenge() { + return Transaction(Task(0, FACEAUTH_CMD_REVOKE_CHALLENGE), Embedding(), + Token()) + .Finalize() + .Run() + .GetResult(); } - return buffer; + static uint64_t GetChallenge() { return challenge; } + + private: + static uint64_t challenge; +}; + +uint64_t Device::challenge; + +void FaceAuthTest::SetUp() { + for (int i = 0; i < MAX_NUM_PROFILES; ++i) + EXPECT_REQ(Device::Erase(i + 1), Result(FACEAUTH_SUCCESS)); } -static const fa_result_t Buffer2Result(const vector<uint8_t>& buffer) -{ - const fa_result_t result = *(reinterpret_cast<const fa_result_t*>( - buffer.data())); - return result; +void FaceAuthTest::DisengageGlobalLockout() { + /* Send Auth Token */ + Result generate_result = Device::GenerateChallenge(); + EXPECT_REQ(generate_result, + Result(FACEAUTH_SUCCESS).SetChallenge(Device::GetChallenge())); + EXPECT_REQ(Transaction(Task(PROFILE_1, FACEAUTH_CMD_ENROLL).Finalize(), + Embedding(EMBEDDING_VECTOR_1, 1), + Token(Device::GetChallenge(), 0, 0)) + .Run() + .GetResult(), + Result(FACEAUTH_ERR_CRC)); } -static void EXPECT_RESULT_EQ(const fa_result_t& r1, const fa_result_t& r2) -{ - EXPECT_EQ(r1.version, r2.version); - EXPECT_EQ(r1.session_id, r2.session_id); - EXPECT_EQ(r1.error, r2.error); - EXPECT_EQ(r1.output.data.first, r2.output.data.first); - EXPECT_EQ(r1.output.data.second, r2.output.data.second); - EXPECT_EQ(r1.lockout_event, r2.lockout_event); - EXPECT_EQ(r1.complete, r2.complete); - EXPECT_EQ(r1.crc, r2.crc); +TEST_F(FaceAuthTest, OldFirmwareVersionShouldError) { + EXPECT_REQ(Transaction(Task(PROFILE_1, FACEAUTH_CMD_ERASE, + FACEAUTH_MIN_ABH_VERSION - 0x100), + Embedding(), Token()) + .Finalize() + .Run() + .GetResult(), + Result(FACEAUTH_ERR_VERSION)); } -const fa_result_t FaceAuthTest::RunTask(const fa_task_t task, - const fa_embedding_t* embed, - const fa_token_t* token) { - vector<uint8_t> buffer_rx; - buffer_rx.resize(1024); +TEST_F(FaceAuthTest, NewFirmwareVersionShouldNotError) { + EXPECT_REQ(Transaction(Task(PROFILE_1, FACEAUTH_CMD_ERASE, + FACEAUTH_MIN_ABH_VERSION + 0x100), + Embedding(), Token()) + .Finalize() + .Run() + .GetResult(), + Result(FACEAUTH_SUCCESS)); +} - vector<uint8_t> buffer_tx = Task2Buffer(task, embed, token); - FaceAuthTest::client->CallApp(APP_ID_FACEAUTH_TEST, 1, buffer_tx, &buffer_rx); +TEST_F(FaceAuthTest, TaskCRCErrorShouldBeDetected) { + EXPECT_REQ( + Transaction(Task(PROFILE_1, FACEAUTH_CMD_ERASE), Embedding(), Token()) + .Run() + .GetResult(), + Result(FACEAUTH_ERR_CRC)); +} - return Buffer2Result(buffer_rx); +TEST_F(FaceAuthTest, ZeroChallengeShouldError) { + EXPECT_REQ(Transaction(Task(PROFILE_1, FACEAUTH_CMD_ENROLL), + Embedding(EMBEDDING_VECTOR_1, 1), Token()) + .Finalize() + .Run() + .GetResult(), + Result(FACEAUTH_ERR_INVALID_CHALLENGE)); + EXPECT_REQ(Transaction(Task(PROFILE_1, FACEAUTH_CMD_SET_FEATURE), + Embedding(EMBEDDING_VECTOR_1, 1), Token()) + .Finalize() + .Run() + .GetResult(), + Result(FACEAUTH_ERR_INVALID_CHALLENGE)); + EXPECT_REQ(Transaction(Task(PROFILE_1, FACEAUTH_CMD_CLR_FEATURE), + Embedding(EMBEDDING_VECTOR_1, 1), Token()) + .Finalize() + .Run() + .GetResult(), + Result(FACEAUTH_ERR_INVALID_CHALLENGE)); } -void FaceAuthTest::Run(const fa_result_t expected, const fa_task_t task, - const fa_embedding_t* embed, const fa_token_t* token) { - EXPECT_RESULT_EQ(expected, RunTask(task, embed, token)); +TEST_F(FaceAuthTest, InvalidChallengeShouldError) { + Result generate_result = Device::GenerateChallenge(); + EXPECT_REQ(generate_result, + Result(FACEAUTH_SUCCESS).SetChallenge(Device::GetChallenge())); + + EXPECT_REQ(Transaction(Task(PROFILE_1, FACEAUTH_CMD_ENROLL), + Embedding(EMBEDDING_VECTOR_1, 1), Token(rand(), 0, 0)) + .Finalize() + .Run() + .GetResult(), + Result(FACEAUTH_ERR_INVALID_CHALLENGE)); + EXPECT_REQ(Transaction(Task(PROFILE_1, FACEAUTH_CMD_SET_FEATURE), + Embedding(EMBEDDING_VECTOR_1, 1), Token(rand(), 0, 0)) + .Finalize() + .Run() + .GetResult(), + Result(FACEAUTH_ERR_INVALID_CHALLENGE)); + EXPECT_REQ(Transaction(Task(PROFILE_1, FACEAUTH_CMD_CLR_FEATURE), + Embedding(EMBEDDING_VECTOR_1, 1), Token(rand(), 0, 0)) + .Finalize() + .Run() + .GetResult(), + Result(FACEAUTH_ERR_INVALID_CHALLENGE)); } -void FaceAuthTest::SetUp() { - for (int profiles = 1; profiles <= MAX_NUM_PROFILES; ++profiles) { - Run(MakeResult(0x0, FACEAUTH_SUCCESS), - MakeTask(0x0, profiles, FACEAUTH_CMD_ERASE)); +TEST_F(FaceAuthTest, EmbeddingCRCErrorShouldBeDetected) { + EXPECT_REQ(Transaction(Task(PROFILE_1, FACEAUTH_CMD_COMP).Finalize(), + Embedding(EMBEDDING_VECTOR_1, 1), Token()) + .Run() + .GetResult(), + Result(FACEAUTH_ERR_CRC)); + EXPECT_REQ(Transaction(Task(PROFILE_1, FACEAUTH_CMD_MIGRATE).Finalize(), + Embedding(EMBEDDING_VECTOR_1, 1), Token()) + .Run() + .GetResult(), + Result(FACEAUTH_ERR_CRC)); + + Result generate_result = Device::GenerateChallenge(); + EXPECT_REQ(generate_result, + Result(FACEAUTH_SUCCESS).SetChallenge(Device::GetChallenge())); + EXPECT_REQ(Transaction(Task(PROFILE_1, FACEAUTH_CMD_ENROLL).Finalize(), + Embedding(EMBEDDING_VECTOR_1, 1), + Token(Device::GetChallenge(), 0, 0)) + .Run() + .GetResult(), + Result(FACEAUTH_ERR_CRC)); +} + +TEST_F(FaceAuthTest, InvalidCommandShouldError) { + Task task(PROFILE_1, 0); + Embedding embed; + Token token; + + EXPECT_REQ(Transaction(task, embed, token).Finalize().Run().GetResult(), + Result(FACEAUTH_ERR_INVALID_ARGS)); +} + +TEST_F(FaceAuthTest, ValidProfileIDTest) { + Embedding embed; + Token token; + + EXPECT_REQ(Transaction(Task(0, FACEAUTH_CMD_GET_USER_INFO), embed, token) + .Finalize() + .Run() + .GetResult(), + Result(FACEAUTH_ERR_INVALID_ARGS)); + + for (int i = 1; i <= MAX_NUM_PROFILES; ++i) { + EXPECT_REQ(Transaction(Task(i, FACEAUTH_CMD_GET_USER_INFO), embed, token) + .Finalize() + .Run() + .GetResult(), + Result(FACEAUTH_SUCCESS)); } + + EXPECT_REQ(Transaction(Task(MAX_NUM_PROFILES + 1, FACEAUTH_CMD_GET_USER_INFO), + embed, token) + .Finalize() + .Run() + .GetResult(), + Result(FACEAUTH_ERR_INVALID_ARGS)); } -TEST_F(FaceAuthTest, SimpleMatchMismatchTest) { - uint64_t session_id = 0xFACE000011110000ull; - session_id++; - - Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_NOMATCH), - MakeTask(session_id, 0x1, FACEAUTH_CMD_COMP), MakeEmbedding(0x11)); - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, 0x1), - MakeTask(session_id, 0x1, FACEAUTH_CMD_ENROLL), MakeEmbedding(0x11)); - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_MATCH), - MakeTask(session_id, 0x1, FACEAUTH_CMD_COMP), MakeEmbedding(0x11)); - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS), - MakeTask(session_id, 0x1, FACEAUTH_CMD_ERASE)); - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_NOMATCH), - MakeTask(session_id, 0x1, FACEAUTH_CMD_COMP), MakeEmbedding(0x11)); -} - -void FaceAuthTest::FullMatchMismatchTest(uint32_t profile1, uint32_t profile2, - uint32_t slot1, uint32_t slot2) { - uint64_t session_id = 0xFACE000022220000ull; - for (uint32_t i = 0; i < 20; ++i) { - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, profile1), - MakeTask(session_id, profile1, FACEAUTH_CMD_ENROLL), - MakeEmbedding((i == slot1) ? 0x11 : 0x0)); - - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, profile2), - MakeTask(session_id, profile2, FACEAUTH_CMD_ENROLL), - MakeEmbedding((i == slot2) ? 0xAA : 0x0)); - } - - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_MATCH), - MakeTask(session_id, profile1, FACEAUTH_CMD_COMP), MakeEmbedding(0x11)); - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_NOMATCH), - MakeTask(session_id, profile1, FACEAUTH_CMD_COMP), MakeEmbedding(0xAA)); - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_NOMATCH), - MakeTask(session_id, profile2, FACEAUTH_CMD_COMP), MakeEmbedding(0x11)); - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_MATCH), - MakeTask(session_id, profile2, FACEAUTH_CMD_COMP), MakeEmbedding(0xAA)); +class User { + public: + User(vector<uint8_t> embed_base) : embed_base(embed_base) { + user_id = rand(); + user_id <<= 32; + user_id += rand(); + } + + User& SetEmbeddingVersion(uint8_t version) { + embed_version = version; + return *this; + } + + User& SetEmbeddingBase(vector<uint8_t> base) { + embed_base = base; + return *this; + } + + User& SetUserID(uint64_t sid) { + user_id = sid; + return *this; + } + + Result GetProfileInfo() { + return Transaction(Task(0, FACEAUTH_CMD_GET_PROFILE_INFO), Embedding(), + Token(0, user_id, 0)) + .Finalize() + .Run() + .GetResult(); + } + + Result GetUserInfo(uint32_t profile_id) { + return Transaction(Task(profile_id, FACEAUTH_CMD_GET_USER_INFO), + Embedding(), Token()) + .Finalize() + .Run() + .GetResult(); + } + + Result Enroll(uint32_t profile_id) { + Result generate_result = Device::GenerateChallenge(); + EXPECT_REQ(generate_result, + Result(FACEAUTH_SUCCESS).SetChallenge(Device::GetChallenge())); + + Result ret = Transaction(Task(profile_id, FACEAUTH_CMD_ENROLL), + Embedding(embed_base, embed_version), + Token(Device::GetChallenge(), user_id, 0)) + .Finalize() + .Run() + .GetResult(); + + uint64_t auth_id_temp = ret.GetChallenge(); + memcpy(&auth_id, &auth_id_temp, sizeof(auth_id)); + EXPECT_REQ(Device::RevokeChallenge(), Result(FACEAUTH_SUCCESS)); + + return ret; + } + + MigrateResult Migrate(uint32_t profile_id, bool should_migrate) { + return Transaction( + Task(profile_id, FACEAUTH_CMD_MIGRATE).SetFirst(should_migrate), + Embedding(embed_base, embed_version), Token(0, user_id, 0)) + .Finalize() + .Run() + .GetResult(); + } + + AuthenticateResult Authenticate(uint32_t profile_id) { + operation_id = rand(); + operation_id <<= 32; + operation_id += rand(); + + Transaction t = + Transaction( + Task(profile_id, FACEAUTH_CMD_COMP).SetChallenge(operation_id), + Embedding(embed_base, embed_version), Token()) + .Finalize() + .Run(); + + return AuthenticateResult(t.GetResult(), t.GetToken()); + } + + ResetLockoutResult ResetLockout(uint32_t profile_id) { + Result generate_result = Device::GenerateChallenge(); + EXPECT_REQ(generate_result, + Result(FACEAUTH_SUCCESS).SetChallenge(Device::GetChallenge())); + + Result ret = + Transaction(Task(profile_id, FACEAUTH_CMD_RESET_LOCKOUT), Embedding(), + Token(Device::GetChallenge(), user_id, 0)) + .Finalize() + .Run() + .GetResult(); + + EXPECT_REQ(Device::RevokeChallenge(), Result(FACEAUTH_SUCCESS)); + + return ret; + } + + bool IsProfileLocked(uint32_t profile_id) { + return (GetUserInfo(profile_id).GetSecond() > 0); + } + + void LockProfile(uint32_t profile_id) { + vector<uint8_t> original_embed_base = embed_base; + embed_base = EMBEDDING_VECTOR_NULL; + /* Fail Authentication 4 times */ + for (int i = 0; i < 4; ++i) { + EXPECT_REQ(Authenticate(profile_id), + AuthenticateResult(FACEAUTH_SUCCESS).SetMatch(false)); + } + + /* Fifth Authentication failure should trigger lockout event */ + EXPECT_REQ(Authenticate(profile_id), + AuthenticateResult(FACEAUTH_SUCCESS) + .SetMatch(false) + .SetLockoutEvent(FACEAUTH_LOCKOUT_ENFORCED)); + + embed_base = original_embed_base; + } + + uint32_t GetFeature(uint32_t profile_id) { + return GetUserInfo(profile_id).GetFirst(); + } + + Result SetFeature(uint32_t profile_id, uint32_t feature) { + Result generate_result = Device::GenerateChallenge(); + EXPECT_REQ(generate_result, + Result(FACEAUTH_SUCCESS).SetChallenge(Device::GetChallenge())); + + Result ret = + Transaction( + Task(profile_id, FACEAUTH_CMD_SET_FEATURE).SetFirst(feature), + Embedding(), Token(Device::GetChallenge(), user_id, 0)) + .Finalize() + .Run() + .GetResult(); + + EXPECT_REQ(Device::RevokeChallenge(), Result(FACEAUTH_SUCCESS)); + + return ret; + } + + Result ClrFeature(uint32_t profile_id, uint32_t feature) { + Result generate_result = Device::GenerateChallenge(); + EXPECT_REQ(generate_result, + Result(FACEAUTH_SUCCESS).SetChallenge(Device::GetChallenge())); + + Result ret = + Transaction( + Task(profile_id, FACEAUTH_CMD_CLR_FEATURE).SetFirst(feature), + Embedding(), Token(Device::GetChallenge(), user_id, 0)) + .Finalize() + .Run() + .GetResult(); + + EXPECT_REQ(Device::RevokeChallenge(), Result(FACEAUTH_SUCCESS)); + + return ret; + } + + uint64_t GetOperationID() { return operation_id; } + uint64_t GetAuthID() { return auth_id; } + uint64_t GetUserID() { return user_id; } + + private: + uint64_t operation_id; + uint64_t auth_id = 0; + uint64_t user_id; + vector<uint8_t> embed_base; + uint8_t embed_version; +}; + +class SuccessfulAuthenticateResult : public AuthenticateResult { + public: + SuccessfulAuthenticateResult(User u) : AuthenticateResult(FACEAUTH_SUCCESS) { + token = Token(u.GetOperationID(), u.GetUserID(), u.GetAuthID()); + SetMatch(true); + } +}; + +TEST_F(FaceAuthTest, GetProfileInfoTest) { + vector<User> users; + for (int i = 0; i < MAX_NUM_PROFILES; ++i) { + users.push_back(User(EMBEDDING_VECTOR_1)); + users[i].SetEmbeddingVersion(1); + } + + users[0].SetUserID(0x1122334455667788); + users[1].SetUserID(0x1122334455667788); + users[3].SetUserID(0x1122334455667788); + + for (int i = 0; i < MAX_NUM_PROFILES; ++i) users[i].Enroll(i + 1); + + union { + uint8_t map[8] = {0}; + uint64_t info; + }; + + for (int i = 0; i < MAX_NUM_PROFILES; ++i) { + for (int j = 0; j < MAX_NUM_PROFILES; ++j) { + map[i] |= ((users[i].GetUserID() == users[j].GetUserID()) << j); + } + } + + for (int i = 0; i < MAX_NUM_PROFILES; ++i) { + map[MAX_NUM_PROFILES] = map[i]; + EXPECT_REQ(users[i].GetProfileInfo(), + Result(FACEAUTH_SUCCESS).SetChallenge(info)); + EXPECT_REQ(users[i].GetUserInfo(i + 1), + Result(FACEAUTH_SUCCESS).SetThird(map[i])); + } +} + +TEST_F(FaceAuthTest, EnrollShouldOnlyAcceptSameUser) { + User user1(EMBEDDING_VECTOR_1); + user1.SetEmbeddingVersion(1); + + User user2(EMBEDDING_VECTOR_NULL); + user2.SetEmbeddingVersion(1); + + /* User 1 Enroll to Profile 1 */ + Result enroll_result = user1.Enroll(PROFILE_1); + EXPECT_REQ(enroll_result, + Result(FACEAUTH_SUCCESS).SetChallenge(user1.GetAuthID())); + + /* User 2 Enroll to Profile 1 should fail */ + enroll_result = user2.Enroll(PROFILE_1); + EXPECT_REQ(enroll_result, Result(FACEAUTH_ERR_INVALID_USER_ID)); + + /* User 1 Enroll to Profile 1 should be successful */ + enroll_result = user1.Enroll(PROFILE_1); + EXPECT_REQ(enroll_result, + Result(FACEAUTH_SUCCESS).SetChallenge(user1.GetAuthID())); +} + +TEST_F(FaceAuthTest, EnrollAfterWipeShouldBeSuccessful) { + User user1(EMBEDDING_VECTOR_1); + user1.SetEmbeddingVersion(1); + + User user2(EMBEDDING_VECTOR_1); + user2.SetEmbeddingVersion(1); + + /* Enroll to Profile 1 */ + Result enroll_result = user1.Enroll(PROFILE_1); + EXPECT_REQ(enroll_result, + Result(FACEAUTH_SUCCESS).SetChallenge(user1.GetAuthID())); + + /* Profile 1 Authentication should now pass */ + AuthenticateResult auth_result = user1.Authenticate(PROFILE_1); + EXPECT_AEQ(auth_result, SuccessfulAuthenticateResult(user1)); + + ASSERT_TRUE(nugget_tools::WipeUserData(client.get())); + + /* Enroll to Profile 1 */ + enroll_result = user2.Enroll(PROFILE_1); + EXPECT_REQ(enroll_result, + Result(FACEAUTH_SUCCESS).SetChallenge(user2.GetAuthID())); + + /* Profile 1 Authentication should now pass */ + auth_result = user2.Authenticate(PROFILE_1); + EXPECT_AEQ(auth_result, SuccessfulAuthenticateResult(user2)); +} + +TEST_F(FaceAuthTest, ValidUserIDCheck) { + User user1(EMBEDDING_VECTOR_1); + user1.SetEmbeddingVersion(1); + + User user2(EMBEDDING_VECTOR_1); + user2.SetEmbeddingVersion(1); + + /* User 1 Enroll to Profile 1 */ + Result enroll_result = user1.Enroll(PROFILE_1); + EXPECT_REQ(enroll_result, + Result(FACEAUTH_SUCCESS).SetChallenge(user1.GetAuthID())); + /* Set Feature User ID Check */ + EXPECT_REQ(user1.SetFeature(PROFILE_1, 0), Result(FACEAUTH_SUCCESS)); + EXPECT_REQ(user2.SetFeature(PROFILE_1, 0), + Result(FACEAUTH_ERR_INVALID_USER_ID)); + /* Clear Feature User ID Check */ + EXPECT_REQ(user1.ClrFeature(PROFILE_1, 0), Result(FACEAUTH_SUCCESS)); + EXPECT_REQ(user2.ClrFeature(PROFILE_1, 0), + Result(FACEAUTH_ERR_INVALID_USER_ID)); +} + +TEST_F(FaceAuthTest, EnrollMismatchVersionShouldFail) { + User user1(EMBEDDING_VECTOR_1); + user1.SetEmbeddingVersion(1); + + /* Enroll using version 1 to profile 1 */ + Result enroll_result = user1.Enroll(PROFILE_1); + EXPECT_REQ(enroll_result, + Result(FACEAUTH_SUCCESS).SetChallenge(user1.GetAuthID())); + + /* Enroll using version 2 to the same profile slot should fail */ + EXPECT_REQ(user1.SetEmbeddingVersion(2).Enroll(PROFILE_1), + Result(FACEAUTH_ERR_EMBEDDING_VERSION)); } TEST_F(FaceAuthTest, SFSFullTest) { - uint64_t session_id = 0xFACE000033330000ull; + User user1(EMBEDDING_VECTOR_1); + user1.SetEmbeddingVersion(1); + + /* Enroll to Profile1 20 times */ for (int i = 0; i < 20; ++i) { - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, 0x1), - MakeTask(session_id, 0x1, FACEAUTH_CMD_ENROLL), MakeEmbedding(0x0)); + Result enroll_result = user1.Enroll(PROFILE_1); + EXPECT_REQ(enroll_result, + Result(FACEAUTH_SUCCESS).SetChallenge(user1.GetAuthID())); } - session_id++; - Run(MakeResult(session_id, FACEAUTH_ERR_SFS_FULL, 0x1), - MakeTask(session_id, 0x1, FACEAUTH_CMD_ENROLL), MakeEmbedding(0x0)); + /* Enrolling one more time should fail */ + EXPECT_REQ(user1.Enroll(PROFILE_1), Result(FACEAUTH_ERR_SFS_FULL)); } -void FaceAuthTest::LockProfileTest(uint32_t profile1) { - uint64_t session_id = 0xFACE000044440000ull; +TEST_F(FaceAuthTest, SimpleMatchMismatchTest) { + User user1(EMBEDDING_VECTOR_1); + user1.SetEmbeddingVersion(1); - for (int i = 0; i < 4; ++i) { - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_NOMATCH), - MakeTask(session_id, profile1, FACEAUTH_CMD_COMP), MakeEmbedding(0x0)); - } + /* Profile 1 is empty: authentication will fail */ + EXPECT_REQ(user1.Authenticate(PROFILE_1), + AuthenticateResult(FACEAUTH_SUCCESS).SetMatch(false)); + + /* Enroll to Profile 1 */ + Result enroll_result = user1.Enroll(PROFILE_1); + EXPECT_REQ(enroll_result, + Result(FACEAUTH_SUCCESS).SetChallenge(user1.GetAuthID())); + + /* Profile 1 Authentication should now pass */ + AuthenticateResult auth_result = user1.Authenticate(PROFILE_1); + EXPECT_AEQ(auth_result, SuccessfulAuthenticateResult(user1)); + + /* Erase Profile 1*/ + EXPECT_REQ(Device::Erase(PROFILE_1), Result(FACEAUTH_SUCCESS)); + + /* Profile 1 is now empty again: authentication should fail */ + EXPECT_REQ(user1.Authenticate(PROFILE_1), + AuthenticateResult(FACEAUTH_SUCCESS).SetMatch(false)); +} + +TEST_F(FaceAuthTest, EmbeddingMismatchVersionComparisonShouldError) { + User user1(EMBEDDING_VECTOR_1); + user1.SetEmbeddingVersion(1); + + /* Enroll to Profile 1 */ + Result enroll_result = user1.Enroll(PROFILE_1); + EXPECT_REQ(enroll_result, + Result(FACEAUTH_SUCCESS).SetChallenge(user1.GetAuthID())); + + /* Upgrade Embedding Version for User 1 */ + user1.SetEmbeddingVersion(2); + + /* Authenticate should now return recalibration error */ + EXPECT_REQ(user1.Authenticate(PROFILE_1), Result(FACEAUTH_ERR_RECALIBRATE)); +} + +TEST_F(FaceAuthTest, MigrateShouldPreventDowngrade) { + User user1(EMBEDDING_VECTOR_1); + user1.SetEmbeddingVersion(5); + + /* User1: enroll to profile 1 */ + Result enroll_result = user1.Enroll(PROFILE_1); + EXPECT_REQ(enroll_result, + Result(FACEAUTH_SUCCESS).SetChallenge(user1.GetAuthID())); - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_NOMATCH, 0, - FACEAUTH_LOCKOUT_ENFORCED), - MakeTask(session_id, profile1, FACEAUTH_CMD_COMP), MakeEmbedding(0x0)); + /* User1: authenticate successfully to profile 1 */ + AuthenticateResult auth_result = user1.Authenticate(PROFILE_1); + EXPECT_AEQ(auth_result, SuccessfulAuthenticateResult(user1)); - session_id++; - Run(MakeResult(session_id, FACEAUTH_ERR_THROTTLE, FACEAUTH_NOMATCH), - MakeTask(session_id, profile1, FACEAUTH_CMD_COMP), MakeEmbedding(0x0)); + /* User1: downgrade and attempt to migrate to profile 3 */ + EXPECT_REQ(user1.SetEmbeddingVersion(4).Migrate(PROFILE_3, 0), + Result(FACEAUTH_ERR_EMBEDDING_DOWNGRADE)); } -bool FaceAuthTest::IsProfileLocked(uint32_t profile1) { - uint64_t session_id = 0xFACE000066660000ull; +TEST_F(FaceAuthTest, MigrateShouldPreventMismatchVersion) { + User user1(EMBEDDING_VECTOR_1); + user1.SetEmbeddingVersion(5); - const fa_result_t observed = - RunTask(MakeTask(session_id, profile1, FACEAUTH_CMD_GET_USER_INFO)); - const fa_result_t expected = - MakeResult(session_id, FACEAUTH_SUCCESS, 0, observed.output.data.second); - EXPECT_RESULT_EQ(expected, observed); - return observed.output.data.second; + /* User1: enroll to profile 1 */ + Result enroll_result = user1.Enroll(PROFILE_1); + EXPECT_REQ(enroll_result, + Result(FACEAUTH_SUCCESS).SetChallenge(user1.GetAuthID())); + + /* User1: authenticate successfully to profile 1 */ + AuthenticateResult auth_result = user1.Authenticate(PROFILE_1); + EXPECT_AEQ(auth_result, SuccessfulAuthenticateResult(user1)); + + /* User1: upgrade and migrate to profile 3 */ + EXPECT_REQ(user1.SetEmbeddingVersion(6).Migrate(PROFILE_3, 1), + MigrateResult(FACEAUTH_SUCCESS).SetEmbeddingNum(1).SetMatch(true)); + EXPECT_REQ(user1.SetEmbeddingVersion(7).Migrate(PROFILE_3, 0), + Result(FACEAUTH_ERR_EMBEDDING_VERSION)); +} + +TEST_F(FaceAuthTest, MigrateShouldCopyUserInfo) { + User user1(EMBEDDING_VECTOR_1); + user1.SetEmbeddingVersion(5); + + /* User1: enroll to profile 1 */ + Result enroll_result = user1.Enroll(PROFILE_1); + EXPECT_REQ(enroll_result, + Result(FACEAUTH_SUCCESS).SetChallenge(user1.GetAuthID())); + + /* User1: set feature */ + EXPECT_REQ(user1.SetFeature(PROFILE_1, 0xFACEDEAD), Result(FACEAUTH_SUCCESS)); + + /* User1: authenticate successfully to profile 1 */ + AuthenticateResult auth_result = user1.Authenticate(PROFILE_1); + EXPECT_AEQ(auth_result, SuccessfulAuthenticateResult(user1)); + + /* User1: migrate to profile 3 */ + EXPECT_REQ(user1.SetEmbeddingVersion(8).Migrate(PROFILE_3, 1), + MigrateResult(FACEAUTH_SUCCESS).SetEmbeddingNum(1).SetMatch(true)); + + EXPECT_EQ(0xFACEDEAD, user1.GetFeature(PROFILE_3)); + + /* User1: authenticate successfully using profile 3 */ + auth_result = user1.Authenticate(PROFILE_3); + EXPECT_AEQ(auth_result, SuccessfulAuthenticateResult(user1)); } -void FaceAuthTest::UnlockProfileTest(uint32_t profile1) { - uint64_t session_id = 0xFACE000077770000ull; - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, 0, 0, FACEAUTH_LOCKOUT_REMOVED), - MakeTask(session_id, profile1, FACEAUTH_CMD_RESET_LOCKOUT)); +TEST_F(FaceAuthTest, SimpleAuthenticateMigrateFlow) { + User user1(EMBEDDING_VECTOR_1); + user1.SetEmbeddingVersion(1); + + User user2(EMBEDDING_VECTOR_1); + user2.SetEmbeddingVersion(1); + + /* User1: enroll to profile 1 */ + Result enroll_result = user1.Enroll(PROFILE_1); + EXPECT_REQ(enroll_result, + Result(FACEAUTH_SUCCESS).SetChallenge(user1.GetAuthID())); + + /* User2: enroll to profile 2 */ + enroll_result = user2.Enroll(PROFILE_2); + EXPECT_REQ(enroll_result, + Result(FACEAUTH_SUCCESS).SetChallenge(user2.GetAuthID())); + + /* User1: authenticate successfully to profile 1 */ + AuthenticateResult auth_result = user1.Authenticate(PROFILE_1); + EXPECT_AEQ(auth_result, SuccessfulAuthenticateResult(user1)); + + /* User1: migrate to profile 3 */ + EXPECT_REQ(user1.Migrate(PROFILE_3, 0), MigrateResult(FACEAUTH_SUCCESS)); + + /* User2: authenticate successfully to profile 2 */ + auth_result = user2.Authenticate(PROFILE_2); + EXPECT_AEQ(auth_result, SuccessfulAuthenticateResult(user2)); + + /* User2: migrate to profile 3 should fail */ + EXPECT_REQ(user2.Migrate(PROFILE_3, 0), + MigrateResult(FACEAUTH_ERR_INVALID_USER_ID)); + + /* User2: migrate to profile 4 */ + EXPECT_REQ(user2.Migrate(PROFILE_4, 1), + MigrateResult(FACEAUTH_SUCCESS).SetEmbeddingNum(1).SetMatch(true)); + EXPECT_REQ(user2.Migrate(PROFILE_4, 1), + MigrateResult(FACEAUTH_SUCCESS).SetEmbeddingNum(2).SetMatch(true)); +} + +TEST_F(FaceAuthTest, FiveAuthenticationFailureSequenceTest) { + User user1(EMBEDDING_VECTOR_1); + user1.SetEmbeddingVersion(1); + + User user2(EMBEDDING_VECTOR_NULL); + user2.SetEmbeddingVersion(1); + + /* Enroll to Profile 1 */ + Result enroll_result = user1.Enroll(PROFILE_1); + EXPECT_REQ(enroll_result, + Result(FACEAUTH_SUCCESS).SetChallenge(user1.GetAuthID())); + + /* Fail Authentication 4 times */ + for (int i = 0; i < 4; ++i) { + EXPECT_REQ(user2.Authenticate(PROFILE_1), + AuthenticateResult(FACEAUTH_SUCCESS).SetMatch(false)); + } + + /* Fifth Authentication failure should trigger lockout event */ + EXPECT_REQ(user2.Authenticate(PROFILE_1), + AuthenticateResult(FACEAUTH_SUCCESS) + .SetMatch(false) + .SetLockoutEvent(FACEAUTH_LOCKOUT_ENFORCED)); + + /* User will be throttled for 30 seconds */ + Result result = user2.GetUserInfo(PROFILE_1); + EXPECT_GE(result.GetSecond(), 25); + EXPECT_REQ( + result, + Result(FACEAUTH_SUCCESS).SetSecond(result.GetSecond()).SetThird(1)); + + /* Following Authentication attempt will be throttled */ + EXPECT_REQ(user2.Authenticate(PROFILE_1), + AuthenticateResult(FACEAUTH_ERR_THROTTLE)); + + /* Reset Lockout should trigger lockout event */ + EXPECT_REQ(user1.ResetLockout(PROFILE_1), + ResetLockoutResult(FACEAUTH_SUCCESS) + .SetLockoutEvent(FACEAUTH_LOCKOUT_REMOVED)); } TEST_F(FaceAuthTest, ExhaustiveLockoutTest) { - EXPECT_EQ(IsProfileLocked(1), false); - EXPECT_EQ(IsProfileLocked(4), false); - EXPECT_EQ(IsProfileLocked(5), false); - EXPECT_EQ(IsProfileLocked(6), false); + vector<User> users; - LockProfileTest(1); - LockProfileTest(5); - LockProfileTest(6); + for (int i = 0; i < MAX_NUM_PROFILES; ++i) { + users.push_back(User(EMBEDDING_VECTOR_1).SetEmbeddingVersion(1)); + Result enroll_result = users[i].Enroll(i + 1); + EXPECT_REQ(enroll_result, + Result(FACEAUTH_SUCCESS).SetChallenge(users[i].GetAuthID())); + EXPECT_EQ(users[i].IsProfileLocked(i + 1), false); + } - EXPECT_EQ(IsProfileLocked(1), true); - EXPECT_EQ(IsProfileLocked(4), false); - EXPECT_EQ(IsProfileLocked(5), true); - EXPECT_EQ(IsProfileLocked(6), true); + bool lock_test_vectors[6] = {true, false, false, false, true, true}; + for (int i = 0; i < MAX_NUM_PROFILES; ++i) { + if (lock_test_vectors[i]) { + users[i].LockProfile(i + 1); + } + } - UnlockProfileTest(1); - UnlockProfileTest(6); + for (int i = 0; i < MAX_NUM_PROFILES; ++i) { + EXPECT_EQ(users[i].IsProfileLocked(i + 1), lock_test_vectors[i]); + } - EXPECT_EQ(IsProfileLocked(1), false); - EXPECT_EQ(IsProfileLocked(4), false); - EXPECT_EQ(IsProfileLocked(5), true); - EXPECT_EQ(IsProfileLocked(6), false); + bool unlock_test_vectors[6] = {true, false, false, false, true, false}; + for (int i = 0; i < MAX_NUM_PROFILES; ++i) { + if (unlock_test_vectors[i]) { + users[i].ResetLockout(i + 1); + } + } + + for (int i = 0; i < MAX_NUM_PROFILES; ++i) { + EXPECT_EQ(users[i].IsProfileLocked(i + 1), + lock_test_vectors[i] && !unlock_test_vectors[i]); + } } -TEST_F(FaceAuthTest, ValidProfileUserIDTest) { - fa_token_t token; - uint64_t session_id = 0xFACE000088880000ull; - session_id++; - token = MakeToken(1); - Run(MakeResult(session_id, FACEAUTH_SUCCESS, 1), - MakeTask(session_id, 0, FACEAUTH_CMD_ENROLL), MakeEmbedding(0x0), &token); - - for (int i = 1; i <= 6; ++i) { - session_id++; - token = MakeToken(i); - Run(MakeResult(session_id, FACEAUTH_SUCCESS, i), - MakeTask(session_id, (i % 2) ? i : 0, FACEAUTH_CMD_ENROLL), - MakeEmbedding(0x0), &token); - } - - session_id++; - token = MakeToken(2); - Run(MakeResult(session_id, FACEAUTH_ERR_INVALID_TOKEN), - MakeTask(session_id, 3, FACEAUTH_CMD_ENROLL), MakeEmbedding(0x0), &token); - session_id++; - Run(MakeResult(session_id, FACEAUTH_ERR_SFS_FULL), - MakeTask(session_id, 0, FACEAUTH_CMD_ENROLL)); -} - -TEST_F(FaceAuthTest, InvalidCommandTest) { - uint64_t session_id = 0xFACE000099990000ull; - session_id++; - Run(MakeResult(session_id, FACEAUTH_ERR_INVALID_ARGS), - MakeTask(session_id, 0x1, 0x0)); -} - -TEST_F(FaceAuthTest, SimpleFeatureTest) { - uint64_t session_id = 0xFACE0000AAAA0000ull; - uint32_t index = 0; +TEST_F(FaceAuthTest, ExhaustiveFeatureTest) { + vector<User> users; + uint32_t feature_msk[MAX_NUM_PROFILES] = {0}; + for (int i = 0; i < MAX_NUM_PROFILES; ++i) { + users.push_back(User(EMBEDDING_VECTOR_NULL).SetEmbeddingVersion(1)); + Result enroll_result = users[i].Enroll(i + 1); + EXPECT_REQ(enroll_result, + Result(FACEAUTH_SUCCESS).SetChallenge(users[i].GetAuthID())); + } + uint32_t index = 0; for (int k = 0; k < 5; ++k) { - for (int i = 1; i <= MAX_NUM_PROFILES; ++i) { - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, feature_msk[i - 1]), - MakeTask(session_id, i, FACEAUTH_CMD_GET_USER_INFO)); - } + for (int i = 0; i < MAX_NUM_PROFILES; ++i) + EXPECT_EQ(users[i].GetFeature(i + 1), feature_msk[i]); - for (int i = 1; i <= MAX_NUM_PROFILES; ++i) { - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS), - MakeTask(session_id, i, FACEAUTH_CMD_SET_FEATURE, (1 << index))); - feature_msk[i - 1] |= (1 << index); + for (int i = 0; i < MAX_NUM_PROFILES; ++i) { + EXPECT_REQ(users[i].SetFeature(i + 1, 1 << index), + Result(FACEAUTH_SUCCESS)); + feature_msk[i] |= (1 << index); index++; } } index = 0; - for (int k = 0; k < 5; ++k) { - for (int i = 1; i <= MAX_NUM_PROFILES; ++i) { - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, feature_msk[i - 1]), - MakeTask(session_id, i, FACEAUTH_CMD_GET_USER_INFO)); - } + for (int i = 0; i < MAX_NUM_PROFILES; ++i) + EXPECT_EQ(users[i].GetFeature(i + 1), feature_msk[i]); - for (int i = 1; i <= MAX_NUM_PROFILES; ++i) { - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS), - MakeTask(session_id, i, FACEAUTH_CMD_CLR_FEATURE, (1 << index))); - feature_msk[i - 1] &= ~(1 << index); + for (int i = 0; i < MAX_NUM_PROFILES; ++i) { + EXPECT_REQ(users[i].ClrFeature(i + 1, 1 << index), + Result(FACEAUTH_SUCCESS)); + feature_msk[i] &= ~(1 << index); index++; } } } -TEST_F(FaceAuthTest, EmbeddingVersionTest) { - uint64_t session_id = 0xFACE0000BBBB0000ull; - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, 1), - MakeTask(session_id, 0x1, FACEAUTH_CMD_ENROLL), MakeEmbedding(0x11)); - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_MATCH), - MakeTask(session_id, 0x1, FACEAUTH_CMD_COMP), MakeEmbedding(0x11)); - session_id++; - Run(MakeResult(session_id, FACEAUTH_ERR_RECALIBRATE, FACEAUTH_NOMATCH), - MakeTask(session_id, 0x1, FACEAUTH_CMD_COMP), MakeEmbedding(0x11, 0x2)); -} - -TEST_F(FaceAuthTest, FirmwareVersionTest) { - uint64_t session_id = 0xFACE0000CCCC0000ull; - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, 1), - MakeTask(session_id, 0x1, FACEAUTH_CMD_ENROLL), MakeEmbedding(0x11)); - session_id++; - Run(MakeResult(session_id, FACEAUTH_ERR_VERSION, FACEAUTH_NOMATCH), - MakeTask(session_id, 0x1, FACEAUTH_CMD_COMP, 0, 0, 0x1), - MakeEmbedding(0x11)); - session_id++; - Run(MakeResult(session_id, FACEAUTH_ERR_VERSION, FACEAUTH_NOMATCH), - MakeTask(session_id, 0x1, FACEAUTH_CMD_COMP, 0, 0, - FACEAUTH_MIN_ABH_VERSION - 0x100), - MakeEmbedding(0x11)); - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_MATCH), - MakeTask(session_id, 0x1, FACEAUTH_CMD_COMP, 0, 0, - FACEAUTH_MIN_ABH_VERSION), - MakeEmbedding(0x11)); - session_id++; - Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_MATCH), - MakeTask(session_id, 0x1, FACEAUTH_CMD_COMP, 0, 0, - FACEAUTH_MIN_ABH_VERSION + 0x100), - MakeEmbedding(0x11)); +static void FullMatchMismatchTest(uint32_t profile_1, uint32_t profile_2) { + User user1(EMBEDDING_VECTOR_1); + user1.SetEmbeddingVersion(1); + + User user2(EMBEDDING_VECTOR_NULL); + user2.SetEmbeddingVersion(1); + + for (uint32_t i = 0; i < 20; ++i) { + Result result; + result = user1.SetEmbeddingBase(EMBEDDING_VECTOR_1).Enroll(profile_1); + EXPECT_REQ(result, + Result(FACEAUTH_SUCCESS).SetChallenge(user1.GetAuthID())); + + result = user2.SetEmbeddingBase(EMBEDDING_VECTOR_2).Enroll(profile_2); + EXPECT_REQ(result, + Result(FACEAUTH_SUCCESS).SetChallenge(user2.GetAuthID())); + } + + user1.SetEmbeddingBase(EMBEDDING_VECTOR_1); + user2.SetEmbeddingBase(EMBEDDING_VECTOR_2); + + AuthenticateResult auth_result = user1.Authenticate(profile_1); + EXPECT_AEQ(auth_result, SuccessfulAuthenticateResult(user1)); + auth_result = user2.Authenticate(profile_1); + EXPECT_REQ(auth_result, AuthenticateResult(FACEAUTH_SUCCESS).SetMatch(false)); + auth_result = user1.Authenticate(profile_2); + EXPECT_REQ(auth_result, AuthenticateResult(FACEAUTH_SUCCESS).SetMatch(false)); + auth_result = user2.Authenticate(profile_2); + EXPECT_AEQ(auth_result, SuccessfulAuthenticateResult(user2)); } TEST_F(FaceAuthTest, ExhaustiveMatchMismatchTest) { - FullMatchMismatchTest(1, 6, 0, 19); - FullMatchMismatchTest(2, 5, 1, 18); - FullMatchMismatchTest(3, 4, 2, 17); - SetUp(); - FullMatchMismatchTest(2, 4, 3, 16); - FullMatchMismatchTest(1, 5, 4, 15); - FullMatchMismatchTest(3, 6, 5, 14); - SetUp(); - FullMatchMismatchTest(3, 5, 6, 13); - FullMatchMismatchTest(1, 4, 7, 12); - FullMatchMismatchTest(2, 6, 8, 11); - SetUp(); - FullMatchMismatchTest(3, 6, 9, 10); + FullMatchMismatchTest(PROFILE_1, PROFILE_6); + FullMatchMismatchTest(PROFILE_2, PROFILE_5); + FullMatchMismatchTest(PROFILE_3, PROFILE_4); } } |