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
121 if (g_scheduleList->getSize(g_scheduleList) >= MAX_SCHEDULE_NUM) {
122 LOG_ERROR("too many schedules already");
123 DestroyCoAuthSchedule(schedule);
124 return RESULT_GENERAL_ERROR;
125 }
126 ResultCode result = g_scheduleList->insert(g_scheduleList, schedule);
127 if (result != RESULT_SUCCESS) {
128 LOG_ERROR("insert failed");
129 DestroyCoAuthSchedule(schedule);
130 }
131 return result;
132 }
133
IsScheduleMatch(void * data,void * condition)134 IAM_STATIC bool IsScheduleMatch(void *data, void *condition)
135 {
136 if ((condition == NULL) || (data == NULL)) {
137 LOG_ERROR("get null data");
138 return false;
139 }
140 uint64_t scheduleId = *(uint64_t *)condition;
141 CoAuthSchedule *coAuthSchedule = (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)221 IAM_STATIC ResultCode MountExecutorOnce(const LinkedList *executors, CoAuthSchedule *coAuthSchedule,
222 uint32_t sensorHint, uint32_t executorRole)
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 coAuthSchedule->executors[coAuthSchedule->executorSize] = *executor;
240 ++(coAuthSchedule->executorSize);
241 return RESULT_SUCCESS;
242 }
243 LOG_ERROR("mount executor failed");
244 return RESULT_NOT_FOUND;
245 }
246
MountExecutor(const ScheduleParam * param,CoAuthSchedule * coAuthSchedule)247 IAM_STATIC ResultCode MountExecutor(const ScheduleParam *param, CoAuthSchedule *coAuthSchedule)
248 {
249 ExecutorCondition condition = {};
250 SetExecutorConditionAuthType(&condition, param->authType);
251 if (param->collectorSensorHint != INVALID_SENSOR_HINT || param->verifierSensorHint != INVALID_SENSOR_HINT) {
252 SetExecutorConditionExecutorMatcher(&condition, param->executorMatcher);
253 }
254 LinkedList *executors = QueryExecutor(&condition);
255 if (executors == NULL) {
256 LOG_ERROR("query executor failed");
257 return RESULT_UNKNOWN;
258 }
259 ResultCode ret;
260 if (param->collectorSensorHint == INVALID_SENSOR_HINT || param->verifierSensorHint == INVALID_SENSOR_HINT ||
261 param->collectorSensorHint == param->verifierSensorHint) {
262 uint32_t allInOneSensorHint = param->verifierSensorHint | param->collectorSensorHint;
263 ret = MountExecutorOnce(executors, coAuthSchedule, allInOneSensorHint, ALL_IN_ONE);
264 if (ret == RESULT_SUCCESS) {
265 goto EXIT;
266 }
267 }
268 if (param->scheduleMode == SCHEDULE_MODE_IDENTIFY) {
269 LOG_ERROR("identification only supports all in one");
270 ret = RESULT_GENERAL_ERROR;
271 goto EXIT;
272 }
273 ret = MountExecutorOnce(executors, coAuthSchedule, param->verifierSensorHint, VERIFIER);
274 if (ret != RESULT_SUCCESS) {
275 LOG_ERROR("verifier is not found");
276 goto EXIT;
277 }
278 ret = MountExecutorOnce(executors, coAuthSchedule, param->collectorSensorHint, COLLECTOR);
279 if (ret != RESULT_SUCCESS) {
280 LOG_ERROR("collector is not found");
281 }
282
283 EXIT:
284 DestroyLinkedList(executors);
285 return ret;
286 }
287
GetScheduleVeriferSensorHint(const CoAuthSchedule * coAuthSchedule)288 uint32_t GetScheduleVeriferSensorHint(const CoAuthSchedule *coAuthSchedule)
289 {
290 if (coAuthSchedule == NULL) {
291 LOG_ERROR("coAuthSchedule is null");
292 return INVALID_SENSOR_HINT;
293 }
294 for (uint32_t i = 0; i < coAuthSchedule->executorSize; ++i) {
295 const ExecutorInfoHal *executor = coAuthSchedule->executors + i;
296 if (executor->executorRole == VERIFIER || executor->executorRole == ALL_IN_ONE) {
297 return executor->executorSensorHint;
298 }
299 }
300 LOG_ERROR("not found");
301 return INVALID_SENSOR_HINT;
302 }
303
GenerateSchedule(const ScheduleParam * param)304 CoAuthSchedule *GenerateSchedule(const ScheduleParam *param)
305 {
306 if (param == NULL) {
307 LOG_ERROR("param is invalid");
308 return NULL;
309 }
310 CoAuthSchedule *coAuthSchedule = Malloc(sizeof(CoAuthSchedule));
311 if (coAuthSchedule == NULL) {
312 LOG_ERROR("coAuthSchedule is null");
313 return NULL;
314 }
315 if (memset_s(coAuthSchedule, sizeof(CoAuthSchedule), 0, sizeof(CoAuthSchedule)) != EOK) {
316 LOG_ERROR("reset coAuthSchedule failed");
317 Free(coAuthSchedule);
318 return NULL;
319 }
320 ResultCode ret = GenerateValidScheduleId(&coAuthSchedule->scheduleId);
321 if (ret != RESULT_SUCCESS) {
322 LOG_ERROR("get scheduleId failed");
323 goto FAIL;
324 }
325 coAuthSchedule->associateId = param->associateId;
326 coAuthSchedule->scheduleMode = param->scheduleMode;
327 coAuthSchedule->authType = param->authType;
328 if (param->templateIds != NULL) {
329 ret = CopyTemplateArrays(param->templateIds, &(coAuthSchedule->templateIds));
330 if (ret != RESULT_SUCCESS) {
331 LOG_ERROR("copy template failed");
332 goto FAIL;
333 }
334 }
335
336 ret = MountExecutor(param, coAuthSchedule);
337 if (ret != RESULT_SUCCESS) {
338 LOG_ERROR("mount failed");
339 goto FAIL;
340 }
341 return coAuthSchedule;
342 FAIL:
343 DestroyCoAuthSchedule(coAuthSchedule);
344 return NULL;
345 }
346
IsTemplateArraysValid(const Uint64Array * templateIds)347 bool IsTemplateArraysValid(const Uint64Array *templateIds)
348 {
349 if (templateIds == NULL) {
350 LOG_ERROR("templateIds is null");
351 return false;
352 }
353 if (templateIds->len > MAX_TEMPLATE_OF_SCHEDULE || (templateIds->len != 0 && templateIds->data == NULL)) {
354 LOG_ERROR("templateIds's content is invalid");
355 return false;
356 }
357 return true;
358 }
359
CopyTemplateArrays(const Uint64Array * in,Uint64Array * out)360 ResultCode CopyTemplateArrays(const Uint64Array *in, Uint64Array *out)
361 {
362 if (!IsTemplateArraysValid(in) || out == NULL || out->data != NULL) {
363 LOG_ERROR("param is invalid");
364 return RESULT_BAD_PARAM;
365 }
366 if (in->len == 0) {
367 out->len = 0;
368 return RESULT_SUCCESS;
369 }
370 out->len = in->len;
371 out->data = (uint64_t *)Malloc(sizeof(uint64_t) * out->len);
372 if (out->data == NULL) {
373 LOG_ERROR("out data is null");
374 out->len = 0;
375 return RESULT_NO_MEMORY;
376 }
377 if (memcpy_s(out->data, (sizeof(uint64_t) * out->len), in->data, (sizeof(uint64_t) * in->len)) != EOK) {
378 LOG_ERROR("copy failed");
379 Free(out->data);
380 out->data = NULL;
381 out->len = 0;
382 return RESULT_BAD_COPY;
383 }
384 return RESULT_SUCCESS;
385 }