• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 #include <app_nugget.h>
3 #include <nos/NuggetClientInterface.h>
4 #include <gtest/gtest.h>
5 
6 #include <memory>
7 
8 #include "user/faceauth/include/fa_common.h"
9 
10 #include "nugget_tools.h"
11 #include "util.h"
12 
13 using std::string;
14 using std::vector;
15 using std::unique_ptr;
16 
17 namespace {
18 
19 class FaceAuthTest: public testing::Test {
20  protected:
21   void SetUp() override;
22 
23   static void SetUpTestCase();
24   static void TearDownTestCase();
25 
26   static unique_ptr<nos::NuggetClientInterface> client;
27   static unique_ptr<test_harness::TestHarness> uart_printer;
28 
29   static const fa_result_t RunTask(const fa_task_t task,
30                                    const fa_embedding_t* embed = NULL,
31                                    const fa_token_t* token = NULL);
32   static void Run(const fa_result_t expected, const fa_task_t task,
33                   const fa_embedding_t* embed = NULL,
34                   const fa_token_t* token = NULL);
35 
36   static void LockProfileTest(uint32_t profile1);
37   static void UnlockProfileTest(uint32_t profile1);
38   static bool IsProfileLocked(uint32_t profile1);
39   static void UnockProfileTest(uint32_t profile1);
40   static void FullMatchMismatchTest(uint32_t profile1, uint32_t profile2,
41                                     uint32_t slot1, uint32_t slot2);
42   static fa_token_t MakeToken(uint32_t profile_id);
43 
44   static vector<uint64_t> user_ids;
45 };
46 
47 vector<uint64_t> FaceAuthTest::user_ids;
48 
49 unique_ptr<nos::NuggetClientInterface> FaceAuthTest::client;
50 unique_ptr<test_harness::TestHarness> FaceAuthTest::uart_printer;
51 
SetUpTestCase()52 void FaceAuthTest::SetUpTestCase() {
53   srand(time(NULL));
54   for (int i = 0; i < MAX_NUM_PROFILES; ++i) {
55     user_ids.push_back(rand());
56   }
57   uart_printer = test_harness::TestHarness::MakeUnique();
58 
59   client = nugget_tools::MakeNuggetClient();
60   client->Open();
61   EXPECT_TRUE(client->IsOpen()) << "Unable to connect";
62 }
63 
TearDownTestCase()64 void FaceAuthTest::TearDownTestCase() {
65   client->Close();
66   client = unique_ptr<nos::NuggetClientInterface>();
67 
68   uart_printer = nullptr;
69 }
70 
CalcCrc8(const uint8_t * data,int len)71 uint8_t CalcCrc8(const uint8_t *data, int len)
72 {
73   unsigned crc = 0;
74   int i, j;
75 
76   for (j = len; j; j--, data++) {
77     crc ^= (*data << 8);
78     for (i = 8; i; i--) {
79       if (crc & 0x8000) {
80         crc ^= (0x1070 << 3);
81       }
82       crc <<= 1;
83     }
84   }
85 
86   return (uint8_t)(crc >> 8);
87 }
88 
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)89 static fa_task_t MakeTask(uint64_t session_id, uint32_t profile_id,
90                           uint32_t cmd, uint32_t input_data1 = 0,
91                           uint32_t input_data2 = 0,
92                           uint32_t version = FACEAUTH_MIN_ABH_VERSION) {
93   fa_task_t task;
94   task.version = version;
95   task.session_id = session_id;
96   task.profile_id = profile_id;
97   task.cmd = cmd;
98   task.input.data.first = input_data1;
99   task.input.data.second = input_data2;
100   task.crc = CalcCrc8(reinterpret_cast<const uint8_t*>(&task),
101                       offsetof(struct fa_task_t, crc));
102   return task;
103 }
104 
MakeEmbedding(uint32_t base,uint32_t version=1)105 static fa_embedding_t* MakeEmbedding(uint32_t base, uint32_t version = 1) {
106   static fa_embedding_t embed;
107   memset(&embed, base, sizeof(fa_embedding_t));
108   embed.version = version;
109   embed.valid = 0;
110   embed.crc = CalcCrc8(reinterpret_cast<const uint8_t*>(&embed),
111                        offsetof(struct fa_embedding_t, crc));
112   return &embed;
113 }
114 
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)115 static fa_result_t MakeResult(uint64_t session_id, int32_t error,
116                               uint32_t output_data1 = 0,
117                               uint32_t output_data2 = 0,
118                               uint32_t lockout_event = FACEAUTH_LOCKOUT_NOP) {
119   fa_result_t result;
120   memset(&result, 0, sizeof(fa_result_t));
121   result.version = 1;
122   result.session_id = session_id;
123   result.error = error;
124   result.output.data.first = output_data1;
125   result.output.data.second = output_data2;
126   result.lockout_event = lockout_event;
127   result.complete = 1;
128   result.crc = CalcCrc8(reinterpret_cast<const uint8_t*>(&result),
129                         offsetof(struct fa_result_t, crc));
130   return result;
131 }
132 
MakeToken(uint32_t profile_id)133 fa_token_t FaceAuthTest::MakeToken(uint32_t profile_id) {
134   fa_token_t token;
135   token.user_id = user_ids[profile_id];
136   return token;
137 }
138 
Task2Buffer(const fa_task_t task,const fa_embedding_t * embed,const fa_token_t * token)139 vector<uint8_t> Task2Buffer(const fa_task_t task, const fa_embedding_t* embed,
140                             const fa_token_t* token) {
141   vector<uint8_t> buffer;
142   for (size_t i = 0; i < sizeof(fa_task_t); ++i) {
143     buffer.push_back(*(reinterpret_cast<const uint8_t*>(&task) + i));
144   }
145   for (size_t i = 0; i < sizeof(fa_embedding_t); ++i) {
146     if (embed)
147       buffer.push_back(*(reinterpret_cast<const uint8_t*>(embed) + i));
148     else
149       buffer.push_back(0);
150   }
151   for (size_t i = 0; i < sizeof(fa_token_t); ++i) {
152     if (token)
153       buffer.push_back(*(reinterpret_cast<const uint8_t*>(token) + i));
154     else
155       buffer.push_back(0);
156   }
157 
158   return buffer;
159 }
160 
Buffer2Result(const vector<uint8_t> & buffer)161 static const fa_result_t Buffer2Result(const vector<uint8_t>& buffer)
162 {
163   const fa_result_t result = *(reinterpret_cast<const fa_result_t*>(
164                                buffer.data()));
165   return result;
166 }
167 
EXPECT_RESULT_EQ(const fa_result_t & r1,const fa_result_t & r2)168 static void EXPECT_RESULT_EQ(const fa_result_t& r1, const fa_result_t& r2)
169 {
170   EXPECT_EQ(r1.version, r2.version);
171   EXPECT_EQ(r1.session_id, r2.session_id);
172   EXPECT_EQ(r1.error, r2.error);
173   EXPECT_EQ(r1.output.data.first, r2.output.data.first);
174   EXPECT_EQ(r1.output.data.second, r2.output.data.second);
175   EXPECT_EQ(r1.lockout_event, r2.lockout_event);
176   EXPECT_EQ(r1.complete, r2.complete);
177   EXPECT_EQ(r1.crc, r2.crc);
178 }
179 
RunTask(const fa_task_t task,const fa_embedding_t * embed,const fa_token_t * token)180 const fa_result_t FaceAuthTest::RunTask(const fa_task_t task,
181                                         const fa_embedding_t* embed,
182                                         const fa_token_t* token) {
183   vector<uint8_t> buffer_rx;
184   buffer_rx.resize(1024);
185 
186   vector<uint8_t> buffer_tx = Task2Buffer(task, embed, token);
187   FaceAuthTest::client->CallApp(APP_ID_FACEAUTH_TEST, 1, buffer_tx, &buffer_rx);
188 
189   return Buffer2Result(buffer_rx);
190 }
191 
Run(const fa_result_t expected,const fa_task_t task,const fa_embedding_t * embed,const fa_token_t * token)192 void FaceAuthTest::Run(const fa_result_t expected, const fa_task_t task,
193                        const fa_embedding_t* embed, const fa_token_t* token) {
194   EXPECT_RESULT_EQ(expected, RunTask(task, embed, token));
195 }
196 
SetUp()197 void FaceAuthTest::SetUp() {
198   for (int profiles = 1; profiles <= MAX_NUM_PROFILES; ++profiles) {
199     Run(MakeResult(0x0, FACEAUTH_SUCCESS),
200         MakeTask(0x0, profiles, FACEAUTH_CMD_ERASE));
201   }
202 }
203 
TEST_F(FaceAuthTest,SimpleMatchMismatchTest)204 TEST_F(FaceAuthTest, SimpleMatchMismatchTest) {
205   uint64_t session_id = 0xFACE000011110000ull;
206   session_id++;
207 
208   Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_NOMATCH),
209       MakeTask(session_id, 0x1, FACEAUTH_CMD_COMP), MakeEmbedding(0x11));
210   session_id++;
211   Run(MakeResult(session_id, FACEAUTH_SUCCESS, 0x1),
212       MakeTask(session_id, 0x1, FACEAUTH_CMD_ENROLL), MakeEmbedding(0x11));
213   session_id++;
214   Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_MATCH),
215       MakeTask(session_id, 0x1, FACEAUTH_CMD_COMP), MakeEmbedding(0x11));
216   session_id++;
217   Run(MakeResult(session_id, FACEAUTH_SUCCESS),
218       MakeTask(session_id, 0x1, FACEAUTH_CMD_ERASE));
219   session_id++;
220   Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_NOMATCH),
221       MakeTask(session_id, 0x1, FACEAUTH_CMD_COMP), MakeEmbedding(0x11));
222 }
223 
FullMatchMismatchTest(uint32_t profile1,uint32_t profile2,uint32_t slot1,uint32_t slot2)224 void FaceAuthTest::FullMatchMismatchTest(uint32_t profile1, uint32_t profile2,
225                                          uint32_t slot1, uint32_t slot2) {
226   uint64_t session_id = 0xFACE000022220000ull;
227   for (uint32_t i = 0; i < 20; ++i) {
228     session_id++;
229     Run(MakeResult(session_id, FACEAUTH_SUCCESS, profile1),
230         MakeTask(session_id, profile1, FACEAUTH_CMD_ENROLL),
231         MakeEmbedding((i == slot1) ? 0x11 : 0x0));
232 
233     session_id++;
234     Run(MakeResult(session_id, FACEAUTH_SUCCESS, profile2),
235         MakeTask(session_id, profile2, FACEAUTH_CMD_ENROLL),
236         MakeEmbedding((i == slot2) ? 0xAA : 0x0));
237   }
238 
239   session_id++;
240   Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_MATCH),
241       MakeTask(session_id, profile1, FACEAUTH_CMD_COMP), MakeEmbedding(0x11));
242   session_id++;
243   Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_NOMATCH),
244       MakeTask(session_id, profile1, FACEAUTH_CMD_COMP), MakeEmbedding(0xAA));
245   session_id++;
246   Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_NOMATCH),
247       MakeTask(session_id, profile2, FACEAUTH_CMD_COMP), MakeEmbedding(0x11));
248   session_id++;
249   Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_MATCH),
250       MakeTask(session_id, profile2, FACEAUTH_CMD_COMP), MakeEmbedding(0xAA));
251 }
252 
TEST_F(FaceAuthTest,SFSFullTest)253 TEST_F(FaceAuthTest, SFSFullTest) {
254   uint64_t session_id = 0xFACE000033330000ull;
255   for (int i = 0; i < 20; ++i) {
256     session_id++;
257     Run(MakeResult(session_id, FACEAUTH_SUCCESS, 0x1),
258         MakeTask(session_id, 0x1, FACEAUTH_CMD_ENROLL), MakeEmbedding(0x0));
259   }
260 
261   session_id++;
262   Run(MakeResult(session_id, FACEAUTH_ERR_SFS_FULL, 0x1),
263       MakeTask(session_id, 0x1, FACEAUTH_CMD_ENROLL), MakeEmbedding(0x0));
264 }
265 
LockProfileTest(uint32_t profile1)266 void FaceAuthTest::LockProfileTest(uint32_t profile1) {
267   uint64_t session_id = 0xFACE000044440000ull;
268 
269   for (int i = 0; i < 4; ++i) {
270     session_id++;
271     Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_NOMATCH),
272         MakeTask(session_id, profile1, FACEAUTH_CMD_COMP), MakeEmbedding(0x0));
273   }
274 
275   session_id++;
276   Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_NOMATCH, 0,
277                  FACEAUTH_LOCKOUT_ENFORCED),
278       MakeTask(session_id, profile1, FACEAUTH_CMD_COMP), MakeEmbedding(0x0));
279 
280   session_id++;
281   Run(MakeResult(session_id, FACEAUTH_ERR_THROTTLE, FACEAUTH_NOMATCH),
282       MakeTask(session_id, profile1, FACEAUTH_CMD_COMP), MakeEmbedding(0x0));
283 }
284 
IsProfileLocked(uint32_t profile1)285 bool FaceAuthTest::IsProfileLocked(uint32_t profile1) {
286   uint64_t session_id = 0xFACE000066660000ull;
287 
288   const fa_result_t observed =
289       RunTask(MakeTask(session_id, profile1, FACEAUTH_CMD_GET_USER_INFO));
290   const fa_result_t expected =
291       MakeResult(session_id, FACEAUTH_SUCCESS, 0, observed.output.data.second);
292   EXPECT_RESULT_EQ(expected, observed);
293   return observed.output.data.second;
294 }
295 
UnlockProfileTest(uint32_t profile1)296 void FaceAuthTest::UnlockProfileTest(uint32_t profile1) {
297   uint64_t session_id = 0xFACE000077770000ull;
298   session_id++;
299   Run(MakeResult(session_id, FACEAUTH_SUCCESS, 0, 0, FACEAUTH_LOCKOUT_REMOVED),
300       MakeTask(session_id, profile1, FACEAUTH_CMD_RESET_LOCKOUT));
301 }
302 
TEST_F(FaceAuthTest,ExhaustiveLockoutTest)303 TEST_F(FaceAuthTest, ExhaustiveLockoutTest) {
304   EXPECT_EQ(IsProfileLocked(1), false);
305   EXPECT_EQ(IsProfileLocked(4), false);
306   EXPECT_EQ(IsProfileLocked(5), false);
307   EXPECT_EQ(IsProfileLocked(6), false);
308 
309   LockProfileTest(1);
310   LockProfileTest(5);
311   LockProfileTest(6);
312 
313   EXPECT_EQ(IsProfileLocked(1), true);
314   EXPECT_EQ(IsProfileLocked(4), false);
315   EXPECT_EQ(IsProfileLocked(5), true);
316   EXPECT_EQ(IsProfileLocked(6), true);
317 
318   UnlockProfileTest(1);
319   UnlockProfileTest(6);
320 
321   EXPECT_EQ(IsProfileLocked(1), false);
322   EXPECT_EQ(IsProfileLocked(4), false);
323   EXPECT_EQ(IsProfileLocked(5), true);
324   EXPECT_EQ(IsProfileLocked(6), false);
325 }
326 
TEST_F(FaceAuthTest,ValidProfileUserIDTest)327 TEST_F(FaceAuthTest, ValidProfileUserIDTest) {
328   fa_token_t token;
329   uint64_t session_id = 0xFACE000088880000ull;
330   session_id++;
331   token = MakeToken(1);
332   Run(MakeResult(session_id, FACEAUTH_SUCCESS, 1),
333       MakeTask(session_id, 0, FACEAUTH_CMD_ENROLL), MakeEmbedding(0x0), &token);
334 
335   for (int i = 1; i <= 6; ++i) {
336     session_id++;
337     token = MakeToken(i);
338     Run(MakeResult(session_id, FACEAUTH_SUCCESS, i),
339         MakeTask(session_id, (i % 2) ? i : 0, FACEAUTH_CMD_ENROLL),
340         MakeEmbedding(0x0), &token);
341   }
342 
343   session_id++;
344   token = MakeToken(2);
345   Run(MakeResult(session_id, FACEAUTH_ERR_INVALID_TOKEN),
346       MakeTask(session_id, 3, FACEAUTH_CMD_ENROLL), MakeEmbedding(0x0), &token);
347   session_id++;
348   Run(MakeResult(session_id, FACEAUTH_ERR_SFS_FULL),
349       MakeTask(session_id, 0, FACEAUTH_CMD_ENROLL));
350 }
351 
TEST_F(FaceAuthTest,InvalidCommandTest)352 TEST_F(FaceAuthTest, InvalidCommandTest) {
353   uint64_t session_id = 0xFACE000099990000ull;
354   session_id++;
355   Run(MakeResult(session_id, FACEAUTH_ERR_INVALID_ARGS),
356       MakeTask(session_id, 0x1, 0x0));
357 }
358 
TEST_F(FaceAuthTest,SimpleFeatureTest)359 TEST_F(FaceAuthTest, SimpleFeatureTest) {
360   uint64_t session_id = 0xFACE0000AAAA0000ull;
361   uint32_t index = 0;
362   uint32_t feature_msk[MAX_NUM_PROFILES] = {0};
363 
364   for (int k = 0; k < 5; ++k) {
365     for (int i = 1; i <= MAX_NUM_PROFILES; ++i) {
366       session_id++;
367       Run(MakeResult(session_id, FACEAUTH_SUCCESS, feature_msk[i - 1]),
368           MakeTask(session_id, i, FACEAUTH_CMD_GET_USER_INFO));
369     }
370 
371     for (int i = 1; i <= MAX_NUM_PROFILES; ++i) {
372       session_id++;
373       Run(MakeResult(session_id, FACEAUTH_SUCCESS),
374           MakeTask(session_id, i, FACEAUTH_CMD_SET_FEATURE, (1 << index)));
375       feature_msk[i - 1] |= (1 << index);
376       index++;
377     }
378   }
379 
380   index = 0;
381 
382   for (int k = 0; k < 5; ++k) {
383     for (int i = 1; i <= MAX_NUM_PROFILES; ++i) {
384       session_id++;
385       Run(MakeResult(session_id, FACEAUTH_SUCCESS, feature_msk[i - 1]),
386           MakeTask(session_id, i, FACEAUTH_CMD_GET_USER_INFO));
387     }
388 
389     for (int i = 1; i <= MAX_NUM_PROFILES; ++i) {
390       session_id++;
391       Run(MakeResult(session_id, FACEAUTH_SUCCESS),
392           MakeTask(session_id, i, FACEAUTH_CMD_CLR_FEATURE, (1 << index)));
393       feature_msk[i - 1] &= ~(1 << index);
394       index++;
395     }
396   }
397 }
398 
TEST_F(FaceAuthTest,EmbeddingVersionTest)399 TEST_F(FaceAuthTest, EmbeddingVersionTest) {
400   uint64_t session_id = 0xFACE0000BBBB0000ull;
401   session_id++;
402   Run(MakeResult(session_id, FACEAUTH_SUCCESS, 1),
403       MakeTask(session_id, 0x1, FACEAUTH_CMD_ENROLL), MakeEmbedding(0x11));
404   session_id++;
405   Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_MATCH),
406       MakeTask(session_id, 0x1, FACEAUTH_CMD_COMP), MakeEmbedding(0x11));
407   session_id++;
408   Run(MakeResult(session_id, FACEAUTH_ERR_RECALIBRATE, FACEAUTH_NOMATCH),
409       MakeTask(session_id, 0x1, FACEAUTH_CMD_COMP), MakeEmbedding(0x11, 0x2));
410 }
411 
TEST_F(FaceAuthTest,FirmwareVersionTest)412 TEST_F(FaceAuthTest, FirmwareVersionTest) {
413   uint64_t session_id = 0xFACE0000CCCC0000ull;
414   session_id++;
415   Run(MakeResult(session_id, FACEAUTH_SUCCESS, 1),
416       MakeTask(session_id, 0x1, FACEAUTH_CMD_ENROLL), MakeEmbedding(0x11));
417   session_id++;
418   Run(MakeResult(session_id, FACEAUTH_ERR_VERSION, FACEAUTH_NOMATCH),
419       MakeTask(session_id, 0x1, FACEAUTH_CMD_COMP, 0, 0, 0x1),
420       MakeEmbedding(0x11));
421   session_id++;
422   Run(MakeResult(session_id, FACEAUTH_ERR_VERSION, FACEAUTH_NOMATCH),
423       MakeTask(session_id, 0x1, FACEAUTH_CMD_COMP, 0, 0,
424                FACEAUTH_MIN_ABH_VERSION - 0x100),
425       MakeEmbedding(0x11));
426   session_id++;
427   Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_MATCH),
428       MakeTask(session_id, 0x1, FACEAUTH_CMD_COMP, 0, 0,
429                FACEAUTH_MIN_ABH_VERSION),
430       MakeEmbedding(0x11));
431   session_id++;
432   Run(MakeResult(session_id, FACEAUTH_SUCCESS, FACEAUTH_MATCH),
433       MakeTask(session_id, 0x1, FACEAUTH_CMD_COMP, 0, 0,
434                FACEAUTH_MIN_ABH_VERSION + 0x100),
435       MakeEmbedding(0x11));
436 }
437 
TEST_F(FaceAuthTest,ExhaustiveMatchMismatchTest)438 TEST_F(FaceAuthTest, ExhaustiveMatchMismatchTest) {
439   FullMatchMismatchTest(1, 6, 0, 19);
440   FullMatchMismatchTest(2, 5, 1, 18);
441   FullMatchMismatchTest(3, 4, 2, 17);
442   SetUp();
443   FullMatchMismatchTest(2, 4, 3, 16);
444   FullMatchMismatchTest(1, 5, 4, 15);
445   FullMatchMismatchTest(3, 6, 5, 14);
446   SetUp();
447   FullMatchMismatchTest(3, 5, 6, 13);
448   FullMatchMismatchTest(1, 4, 7, 12);
449   FullMatchMismatchTest(2, 6, 8, 11);
450   SetUp();
451   FullMatchMismatchTest(3, 6, 9, 10);
452 }
453 }
454 
455