1 /*
2  * Copyright (C) 2022-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "coauth.h"
17 
18 #include "securec.h"
19 
20 #include "adaptor_algorithm.h"
21 #include "adaptor_log.h"
22 #include "adaptor_memory.h"
23 #include "pool.h"
24 
25 #ifdef IAM_TEST_ENABLE
26 #define IAM_STATIC
27 #else
28 #define IAM_STATIC static
29 #endif
30 
31 // Used to cache the ongoing coAuth scheduling.
32 IAM_STATIC LinkedList *g_scheduleList = NULL;
33 
IsCoAuthInit(void)34 IAM_STATIC bool IsCoAuthInit(void)
35 {
36     return g_scheduleList != NULL;
37 }
38 
DestroyScheduleNode(void * data)39 void DestroyScheduleNode(void *data)
40 {
41     if (data == NULL) {
42         LOG_ERROR("get null data");
43         return;
44     }
45     CoAuthSchedule *schedule = (CoAuthSchedule *)data;
46     if (schedule->templateIds.data != NULL) {
47         Free(schedule->templateIds.data);
48         schedule->templateIds.data = NULL;
49     }
50     Free(schedule);
51 }
52 
CopyCoAuthSchedule(const CoAuthSchedule * coAuthSchedule)53 CoAuthSchedule *CopyCoAuthSchedule(const CoAuthSchedule *coAuthSchedule)
54 {
55     if (coAuthSchedule == NULL || !IsTemplateArraysValid(&(coAuthSchedule->templateIds))) {
56         LOG_ERROR("coAuthSchedule is invalid");
57         return NULL;
58     }
59     CoAuthSchedule *schedule = (CoAuthSchedule *)Malloc(sizeof(CoAuthSchedule));
60     if (schedule == NULL) {
61         LOG_ERROR("schedule is null");
62         return NULL;
63     }
64     if (memcpy_s(schedule, sizeof(CoAuthSchedule), coAuthSchedule, sizeof(CoAuthSchedule)) != EOK) {
65         LOG_ERROR("copy schedule failed");
66         Free(schedule);
67         return NULL;
68     }
69     schedule->templateIds.data = NULL;
70     schedule->templateIds.len = 0;
71     ResultCode ret = CopyTemplateArrays(&(coAuthSchedule->templateIds), &(schedule->templateIds));
72     if (ret != RESULT_SUCCESS) {
73         LOG_ERROR("copy templateIds failed");
74         Free(schedule);
75         return NULL;
76     }
77     return schedule;
78 }
79 
DestroyCoAuthSchedule(CoAuthSchedule * coAuthSchedule)80 void DestroyCoAuthSchedule(CoAuthSchedule *coAuthSchedule)
81 {
82     if (coAuthSchedule == NULL) {
83         return;
84     }
85     DestroyScheduleNode(coAuthSchedule);
86 }
87 
InitCoAuth(void)88 ResultCode InitCoAuth(void)
89 {
90     if (!IsCoAuthInit()) {
91         g_scheduleList = CreateLinkedList(DestroyScheduleNode);
92     }
93     if (g_scheduleList == NULL) {
94         return RESULT_GENERAL_ERROR;
95     }
96     return RESULT_SUCCESS;
97 }
98 
DestoryCoAuth(void)99 void DestoryCoAuth(void)
100 {
101     DestroyLinkedList(g_scheduleList);
102     g_scheduleList = NULL;
103 }
104 
AddCoAuthSchedule(const CoAuthSchedule * coAuthSchedule)105 ResultCode AddCoAuthSchedule(const CoAuthSchedule *coAuthSchedule)
106 {
107     if (!IsCoAuthInit()) {
108         LOG_ERROR("pool not init");
109         return RESULT_NEED_INIT;
110     }
111     if (coAuthSchedule == NULL) {
112         LOG_ERROR("get null schedule");
113         return RESULT_BAD_PARAM;
114     }
115     CoAuthSchedule *schedule = CopyCoAuthSchedule(coAuthSchedule);
116     if (schedule == NULL) {
117         LOG_ERROR("no memory");
118         return RESULT_NO_MEMORY;
119     }
120     if (g_scheduleList->getSize(g_scheduleList) >= MAX_SCHEDULE_NUM) {
121         LOG_ERROR("too many schedules already");
122         DestroyCoAuthSchedule(schedule);
123         return RESULT_GENERAL_ERROR;
124     }
125     ResultCode result = g_scheduleList->insert(g_scheduleList, schedule);
126     if (result != RESULT_SUCCESS) {
127         LOG_ERROR("insert failed");
128         DestroyCoAuthSchedule(schedule);
129     }
130     LOG_INFO("success");
131     return result;
132 }
133 
IsScheduleMatch(const void * data,const void * condition)134 IAM_STATIC bool IsScheduleMatch(const void *data, const void *condition)
135 {
136     if ((condition == NULL) || (data == NULL)) {
137         LOG_ERROR("get null data");
138         return false;
139     }
140     uint64_t scheduleId = *(const uint64_t *)condition;
141     const CoAuthSchedule *coAuthSchedule = (const CoAuthSchedule *)data;
142     return (coAuthSchedule->scheduleId == scheduleId);
143 }
144 
RemoveCoAuthSchedule(uint64_t scheduleId)145 ResultCode RemoveCoAuthSchedule(uint64_t scheduleId)
146 {
147     if (!IsCoAuthInit()) {
148         LOG_ERROR("pool not init");
149         return RESULT_NEED_INIT;
150     }
151     return g_scheduleList->remove(g_scheduleList, (void *)&scheduleId, IsScheduleMatch, true);
152 }
153 
GetCoAuthSchedule(uint64_t scheduleId)154 const CoAuthSchedule *GetCoAuthSchedule(uint64_t scheduleId)
155 {
156     if (!IsCoAuthInit()) {
157         LOG_ERROR("pool not init");
158         return NULL;
159     }
160     LinkedListIterator *iterator = g_scheduleList->createIterator(g_scheduleList);
161     if (iterator == NULL) {
162         LOG_ERROR("create iterator failed");
163         return NULL;
164     }
165     CoAuthSchedule *schedule = NULL;
166     while (iterator->hasNext(iterator)) {
167         schedule = (CoAuthSchedule *)iterator->next(iterator);
168         if (schedule == NULL) {
169             LOG_ERROR("list node is null, please check");
170             continue;
171         }
172         if (schedule->scheduleId != scheduleId) {
173             continue;
174         }
175         g_scheduleList->destroyIterator(iterator);
176         return schedule;
177     }
178     g_scheduleList->destroyIterator(iterator);
179     LOG_ERROR("can't find this schedule");
180     return NULL;
181 }
182 
IsScheduleIdDuplicate(uint64_t scheduleId)183 IAM_STATIC bool IsScheduleIdDuplicate(uint64_t scheduleId)
184 {
185     LinkedListNode *temp = g_scheduleList->head;
186     CoAuthSchedule *schedule = NULL;
187     while (temp != NULL) {
188         schedule = (CoAuthSchedule *)temp->data;
189         if (schedule != NULL && schedule->scheduleId == scheduleId) {
190             return true;
191         }
192         temp = temp->next;
193     }
194 
195     return false;
196 }
197 
GenerateValidScheduleId(uint64_t * scheduleId)198 IAM_STATIC ResultCode GenerateValidScheduleId(uint64_t *scheduleId)
199 {
200     if (g_scheduleList == NULL) {
201         LOG_ERROR("g_poolList is null");
202         return RESULT_BAD_PARAM;
203     }
204 
205     for (uint32_t i = 0; i < MAX_DUPLICATE_CHECK; ++i) {
206         uint64_t tempRandom;
207         if (SecureRandom((uint8_t *)&tempRandom, sizeof(uint64_t)) != RESULT_SUCCESS) {
208             LOG_ERROR("get random failed");
209             return RESULT_GENERAL_ERROR;
210         }
211         if (!IsScheduleIdDuplicate(tempRandom)) {
212             *scheduleId = tempRandom;
213             return RESULT_SUCCESS;
214         }
215     }
216 
217     LOG_ERROR("a rare failure");
218     return RESULT_GENERAL_ERROR;
219 }
220 
MountExecutorOnce(const LinkedList * executors,CoAuthSchedule * coAuthSchedule,uint32_t sensorHint,uint32_t executorRole,Uint8Array deviceUdid)221 IAM_STATIC ResultCode MountExecutorOnce(const LinkedList *executors, CoAuthSchedule *coAuthSchedule,
222     uint32_t sensorHint, uint32_t executorRole, Uint8Array deviceUdid)
223 {
224     LinkedListNode *tempNode = executors->head;
225     while (tempNode != NULL) {
226         if (tempNode->data == NULL) {
227             LOG_ERROR("data is null");
228             return RESULT_UNKNOWN;
229         }
230         ExecutorInfoHal *executor = (ExecutorInfoHal *)tempNode->data;
231         if (executor->executorRole != executorRole) {
232             tempNode = tempNode->next;
233             continue;
234         }
235         if (sensorHint != INVALID_SENSOR_HINT && sensorHint != executor->executorSensorHint) {
236             tempNode = tempNode->next;
237             continue;
238         }
239 
240         if (memcmp(deviceUdid.data, executor->deviceUdid, UDID_LEN) != 0) {
241             tempNode = tempNode->next;
242             continue;
243         }
244         coAuthSchedule->executors[coAuthSchedule->executorSize] = *executor;
245         ++(coAuthSchedule->executorSize);
246         return RESULT_SUCCESS;
247     }
248     LOG_ERROR("mount executor failed");
249     return RESULT_NOT_FOUND;
250 }
251 
MountExecutor(const ScheduleParam * param,CoAuthSchedule * coAuthSchedule)252 IAM_STATIC ResultCode MountExecutor(const ScheduleParam *param, CoAuthSchedule *coAuthSchedule)
253 {
254     ExecutorCondition condition = {};
255     SetExecutorConditionAuthType(&condition, param->authType);
256     if (param->collectorSensorHint != INVALID_SENSOR_HINT || param->verifierSensorHint != INVALID_SENSOR_HINT) {
257         SetExecutorConditionExecutorMatcher(&condition, param->executorMatcher);
258     }
259     LinkedList *executors = QueryExecutor(&condition);
260     if (executors == NULL) {
261         LOG_ERROR("query executor failed");
262         return RESULT_UNKNOWN;
263     }
264 
265     Uint8Array localUdidArray = { .data = (uint8_t *)(param->localUdid), .len = UDID_LEN };
266     Uint8Array collectorUdidArray = { .data = (uint8_t *)(param->collectorUdid), .len = UDID_LEN };
267     ResultCode ret;
268     LOG_INFO("collectorSensorHint: %{public}u, verifierSensorHint: %{public}u", param->collectorSensorHint,
269         param->verifierSensorHint);
270     if ((param->collectorSensorHint == INVALID_SENSOR_HINT || param->verifierSensorHint == INVALID_SENSOR_HINT ||
271         param->collectorSensorHint == param->verifierSensorHint) &&
272         memcmp(param->localUdid, param->collectorUdid, UDID_LEN) == 0) {
273         uint32_t allInOneSensorHint = param->verifierSensorHint | param->collectorSensorHint;
274         LOG_INFO("mount all-in-one executor");
275         ret = MountExecutorOnce(executors, coAuthSchedule, allInOneSensorHint, ALL_IN_ONE, localUdidArray);
276         if (ret != RESULT_SUCCESS) {
277             LOG_INFO("all-in-one executor is not found");
278         }
279         goto EXIT;
280     }
281 
282     LOG_INFO("mount verifier and collector");
283     if (param->scheduleMode == SCHEDULE_MODE_IDENTIFY) {
284         LOG_ERROR("identification only supports all in one");
285         ret = RESULT_GENERAL_ERROR;
286         goto EXIT;
287     }
288     ret = MountExecutorOnce(executors, coAuthSchedule, param->verifierSensorHint, VERIFIER, localUdidArray);
289     if (ret != RESULT_SUCCESS) {
290         LOG_ERROR("verifier is not found");
291         goto EXIT;
292     }
293 
294     ret = MountExecutorOnce(executors, coAuthSchedule, param->collectorSensorHint, COLLECTOR, collectorUdidArray);
295     if (ret != RESULT_SUCCESS) {
296         LOG_ERROR("collector is not found");
297     }
298 
299 EXIT:
300     DestroyLinkedList(executors);
301     return ret;
302 }
303 
GetScheduleVerifierSensorHint(const CoAuthSchedule * coAuthSchedule)304 uint32_t GetScheduleVerifierSensorHint(const CoAuthSchedule *coAuthSchedule)
305 {
306     if (coAuthSchedule == NULL) {
307         LOG_ERROR("coAuthSchedule is null");
308         return INVALID_SENSOR_HINT;
309     }
310     for (uint32_t i = 0; i < coAuthSchedule->executorSize; ++i) {
311         const ExecutorInfoHal *executor = coAuthSchedule->executors + i;
312         if (executor->executorRole == VERIFIER || executor->executorRole == ALL_IN_ONE) {
313             return executor->executorSensorHint;
314         }
315     }
316     LOG_ERROR("not found");
317     return INVALID_SENSOR_HINT;
318 }
319 
GenerateSchedule(const ScheduleParam * param)320 CoAuthSchedule *GenerateSchedule(const ScheduleParam *param)
321 {
322     if (param == NULL) {
323         LOG_ERROR("param is invalid");
324         return NULL;
325     }
326     CoAuthSchedule *coAuthSchedule = Malloc(sizeof(CoAuthSchedule));
327     if (coAuthSchedule == NULL) {
328         LOG_ERROR("coAuthSchedule is null");
329         return NULL;
330     }
331     if (memset_s(coAuthSchedule, sizeof(CoAuthSchedule), 0, sizeof(CoAuthSchedule)) != EOK) {
332         LOG_ERROR("reset coAuthSchedule failed");
333         Free(coAuthSchedule);
334         return NULL;
335     }
336     ResultCode ret = GenerateValidScheduleId(&coAuthSchedule->scheduleId);
337     if (ret != RESULT_SUCCESS) {
338         LOG_ERROR("get scheduleId failed");
339         goto FAIL;
340     }
341     coAuthSchedule->associateId = param->associateId;
342     coAuthSchedule->scheduleMode = param->scheduleMode;
343     coAuthSchedule->authType = param->authType;
344     coAuthSchedule->userType = param->userType;
345     if (param->templateIds != NULL) {
346         ret = CopyTemplateArrays(param->templateIds, &(coAuthSchedule->templateIds));
347         if (ret != RESULT_SUCCESS) {
348             LOG_ERROR("copy template failed");
349             goto FAIL;
350         }
351     }
352 
353     ret = MountExecutor(param, coAuthSchedule);
354     if (ret != RESULT_SUCCESS) {
355         LOG_ERROR("mount failed");
356         goto FAIL;
357     }
358     return coAuthSchedule;
359 FAIL:
360     DestroyCoAuthSchedule(coAuthSchedule);
361     return NULL;
362 }
363 
IsTemplateArraysValid(const Uint64Array * templateIds)364 bool IsTemplateArraysValid(const Uint64Array *templateIds)
365 {
366     if (templateIds == NULL) {
367         LOG_ERROR("templateIds is null");
368         return false;
369     }
370     if (templateIds->len > MAX_TEMPLATE_OF_SCHEDULE || (templateIds->len != 0 && templateIds->data == NULL)) {
371         LOG_ERROR("templateIds's content is invalid");
372         return false;
373     }
374     return true;
375 }
376 
CopyTemplateArrays(const Uint64Array * in,Uint64Array * out)377 ResultCode CopyTemplateArrays(const Uint64Array *in, Uint64Array *out)
378 {
379     if (!IsTemplateArraysValid(in) || out == NULL || out->data != NULL) {
380         LOG_ERROR("param is invalid");
381         return RESULT_BAD_PARAM;
382     }
383     if (in->len == 0) {
384         out->len = 0;
385         return RESULT_SUCCESS;
386     }
387     out->len = in->len;
388     out->data = (uint64_t *)Malloc(sizeof(uint64_t) * out->len);
389     if (out->data == NULL) {
390         LOG_ERROR("out data is null");
391         out->len = 0;
392         return RESULT_NO_MEMORY;
393     }
394     if (memcpy_s(out->data, (sizeof(uint64_t) * out->len), in->data, (sizeof(uint64_t) * in->len)) != EOK) {
395         LOG_ERROR("copy failed");
396         Free(out->data);
397         out->data = NULL;
398         out->len = 0;
399         return RESULT_BAD_COPY;
400     }
401     return RESULT_SUCCESS;
402 }