1 /*
2  * Copyright (c) 2022 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 "cert_manager_auth_list_mgr.h"
17 
18 #include "securec.h"
19 
20 #include "cert_manager.h"
21 #include "cert_manager_file_operator.h"
22 #include "cert_manager_mem.h"
23 #include "cert_manager_storage.h"
24 #include "cert_manager_uri.h"
25 #include "cm_log.h"
26 #include "cm_type.h"
27 
28 #define MAX_PATH_LEN                        512
29 #define MAX_AUTH_COUNT                      256
30 #define AUTH_LIST_VERSON                    0
31 
CheckAuthListFileSizeValid(const struct CmBlob * originList,uint32_t * authCount)32 static int32_t CheckAuthListFileSizeValid(const struct CmBlob *originList, uint32_t *authCount)
33 {
34     if (originList->size < (sizeof(uint32_t) + sizeof(uint32_t))) { /* version and count size */
35         CM_LOG_E("invalid authlist size[%u]", originList->size);
36         return CMR_ERROR_INVALID_OPERATION;
37     }
38 
39     uint32_t count = 0;
40     (void)memcpy_s(&count, sizeof(count), originList->data + sizeof(uint32_t), sizeof(count));
41     if (count > MAX_OUT_BLOB_SIZE) {
42         CM_LOG_E("invalid auth count[%u]", count);
43         return CMR_ERROR_INVALID_OPERATION;
44     }
45 
46     uint32_t size = sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t) * count;
47     if (originList->size != size) {
48         CM_LOG_E("invalid auth list file size[%u], count[%u]", originList->size, count);
49         return CMR_ERROR_INVALID_OPERATION;
50     }
51 
52     *authCount = count;
53     return CM_SUCCESS;
54 }
55 
IsUidExist(const struct CmBlob * list,uint32_t count,uint32_t targetUid,uint32_t * position)56 static bool IsUidExist(const struct CmBlob *list, uint32_t count, uint32_t targetUid, uint32_t *position)
57 {
58     uint32_t uid;
59     uint32_t offset = sizeof(uint32_t) + sizeof(uint32_t);
60     for (uint32_t i = 0; i < count; ++i) {
61         (void)memcpy_s(&uid, sizeof(uint32_t), list->data + offset, sizeof(uint32_t));
62         offset += sizeof(uint32_t);
63         if (uid == targetUid) {
64             *position = offset;
65             return true;
66         }
67     }
68     return false;
69 }
70 
CopyBlob(const struct CmBlob * originList,struct CmBlob * outList)71 static int32_t CopyBlob(const struct CmBlob *originList, struct CmBlob *outList)
72 {
73     uint8_t *data = (uint8_t *)CMMalloc(originList->size);
74     if (data == NULL) {
75         CM_LOG_E("out data malloc failed");
76         return CMR_ERROR_MALLOC_FAIL;
77     }
78 
79     (void)memcpy_s(data, originList->size, originList->data, originList->size);
80 
81     outList->data = data;
82     outList->size = originList->size;
83     return CM_SUCCESS;
84 }
85 
InsertUid(const struct CmBlob * originList,uint32_t uid,struct CmBlob * addedList)86 static int32_t InsertUid(const struct CmBlob *originList, uint32_t uid, struct CmBlob *addedList)
87 {
88     uint32_t count = 0;
89     int32_t ret = CheckAuthListFileSizeValid(originList, &count);
90     if (ret != CM_SUCCESS) {
91         return ret;
92     }
93 
94     uint32_t position = 0;
95     bool isUidExist = IsUidExist(originList, count, uid, &position);
96     if (isUidExist) {
97         /* exist then copy origin */
98         return CopyBlob(originList, addedList);
99     }
100 
101     if (count >= MAX_AUTH_COUNT) {
102         return CMR_ERROR_INVALID_OPERATION;
103     }
104 
105     uint32_t size = originList->size + sizeof(uint32_t); /* add one uid */
106     uint8_t *data = (uint8_t *)CMMalloc(size);
107     if (data == NULL) {
108         return CMR_ERROR_MALLOC_FAIL;
109     }
110 
111     do {
112         ret = CMR_ERROR_INVALID_OPERATION;
113         if (memcpy_s(data, size, originList->data, originList->size) != EOK) {
114             CM_LOG_E("copy origin list failed");
115             break;
116         }
117         if (memcpy_s(data + originList->size, size - originList->size, &uid, sizeof(uint32_t)) != EOK) {
118             CM_LOG_E("copy inserted uid failed");
119             break;
120         }
121 
122         /* refresh count after add */
123         uint32_t countAfterAdd = count + 1;
124         if (memcpy_s(data + sizeof(uint32_t), sizeof(countAfterAdd), &countAfterAdd, sizeof(countAfterAdd)) != EOK) {
125             CM_LOG_E("refresh count after add failed");
126             break;
127         }
128         ret = CM_SUCCESS;
129     } while (0);
130     if (ret != CM_SUCCESS) {
131         CM_FREE_PTR(data);
132         return ret;
133     }
134 
135     addedList->data = data;
136     addedList->size = size;
137     return CM_SUCCESS;
138 }
139 
RemoveUid(const struct CmBlob * originList,uint32_t uid,struct CmBlob * removedList)140 static int32_t RemoveUid(const struct CmBlob *originList, uint32_t uid, struct CmBlob *removedList)
141 {
142     uint32_t count = 0;
143     int32_t ret = CheckAuthListFileSizeValid(originList, &count);
144     if (ret != CM_SUCCESS) {
145         return ret;
146     }
147 
148     uint32_t position = 0;
149     bool isUidExist = IsUidExist(originList, count, uid, &position);
150     if (!isUidExist) {
151         /* not exist then copy origin */
152         return CopyBlob(originList, removedList);
153     }
154 
155     uint32_t size = originList->size - sizeof(uint32_t);  /* delete one uid */
156     uint8_t *data = (uint8_t *)CMMalloc(size);
157     if (data == NULL) {
158         return CMR_ERROR_MALLOC_FAIL;
159     }
160 
161     do {
162         ret = CMR_ERROR_INVALID_OPERATION;
163         uint32_t beforeSize = position - sizeof(uint32_t); /* positon >= 12 */
164         if (memcpy_s(data, size, originList->data, beforeSize) != EOK) {
165             CM_LOG_E("copy origin list before uid failed");
166             break;
167         }
168 
169         if (size > beforeSize) { /* has buffer after uid */
170             if (memcpy_s(data + beforeSize, size - beforeSize, originList->data + position,
171                 originList->size - position) != EOK) {
172                 CM_LOG_E("copy origin list after uid failed");
173                 break;
174             }
175         }
176 
177         /* refresh count after remove */
178         uint32_t countAfterRemove = count - 1; /* count > 1 */
179         if (memcpy_s(data + sizeof(uint32_t), sizeof(countAfterRemove),
180             &countAfterRemove, sizeof(countAfterRemove)) != EOK) {
181             CM_LOG_E("refresh count after delete failed");
182             break;
183         }
184         ret = CM_SUCCESS;
185     } while (0);
186     if (ret != CM_SUCCESS) {
187         CM_FREE_PTR(data);
188         return ret;
189     }
190 
191     removedList->data = data;
192     removedList->size = size;
193     return CM_SUCCESS;
194 }
195 
RefreshAuthListBuf(const char * path,const char * fileName,uint32_t uid,bool isAdd,struct CmBlob * authList)196 static int32_t RefreshAuthListBuf(const char *path, const char *fileName, uint32_t uid, bool isAdd,
197     struct CmBlob *authList)
198 {
199     struct CmBlob list = { 0, NULL };
200     int32_t ret = CmStorageGetBuf(path, fileName, &list);
201     if (ret != CM_SUCCESS) {
202         return ret;
203     }
204 
205     if (isAdd) {
206         ret = InsertUid(&list, uid, authList);
207     } else {
208         ret = RemoveUid(&list, uid, authList);
209     }
210     CM_FREE_PTR(list.data);
211     return ret;
212 }
213 
214 /*
215  * auth list buffer format:
216  * |--version--|--uidCount(n)--|--uid0--|--uid1--|...|--uid(n-1)--|
217  * |   4Byte   |      4Byte    |  4Byte |  4Byte |...|  4Byte     |
218  */
InitAuthListBuf(uint32_t uid,struct CmBlob * authList)219 static int32_t InitAuthListBuf(uint32_t uid, struct CmBlob *authList)
220 {
221     uint32_t count = 1;
222     uint32_t version = AUTH_LIST_VERSON;
223     uint32_t size = sizeof(version) + sizeof(count) + sizeof(uid) * count;
224     uint8_t *data = (uint8_t *)CMMalloc(size);
225     if (data == NULL) {
226         CM_LOG_E("malloc file buffer failed");
227         return CMR_ERROR_MALLOC_FAIL;
228     }
229     (void)memset_s(data, size, 0, size);
230 
231     int32_t ret = CM_SUCCESS;
232     uint32_t offset = 0;
233     do {
234         if (memcpy_s(data + offset, size - offset, &version, sizeof(version)) != EOK) {
235             CM_LOG_E("copy count failed");
236             ret = CMR_ERROR_INVALID_OPERATION;
237             break;
238         }
239         offset += sizeof(version);
240 
241         if (memcpy_s(data + offset, size - offset, &count, sizeof(count)) != EOK) {
242             CM_LOG_E("copy count failed");
243             ret = CMR_ERROR_INVALID_OPERATION;
244             break;
245         }
246         offset += sizeof(count);
247 
248         if (memcpy_s(data  + offset, size - offset, &uid, sizeof(uid)) != EOK) {
249             CM_LOG_E("copy uid failed");
250             ret = CMR_ERROR_INVALID_OPERATION;
251             break;
252         }
253     } while (0);
254     if (ret != CM_SUCCESS) {
255         CM_FREE_PTR(data);
256         return ret;
257     }
258 
259     authList->data = data;
260     authList->size = size;
261     return CM_SUCCESS;
262 }
263 
RefreshAuthList(const char * path,const char * fileName,uint32_t uid,bool isAdd)264 static int32_t RefreshAuthList(const char *path, const char *fileName, uint32_t uid, bool isAdd)
265 {
266     bool isAuthListExist = false;
267     int32_t ret = CmIsFileExist(path, fileName);
268     if (ret == CM_SUCCESS) {
269         isAuthListExist = true;
270     }
271 
272     if (!isAuthListExist && !isAdd) {
273         CM_LOG_D("auth list file not exit when delete uid");
274         return CM_SUCCESS; /* auth list file not exit when delete uid */
275     }
276 
277     struct CmBlob authList = { 0, NULL };
278     if (isAuthListExist) {
279         ret = RefreshAuthListBuf(path, fileName, uid, isAdd, &authList);
280     } else { /* auth list file not exit when add uid */
281         ret = InitAuthListBuf(uid, &authList);
282     }
283     if (ret != CM_SUCCESS) {
284         return ret;
285     }
286 
287     ret = CmFileWrite(path, fileName, 0, authList.data, authList.size);
288     if (ret != CM_SUCCESS) {
289         CM_LOG_E("write file failed");
290     }
291     CM_FREE_PTR(authList.data);
292     return ret;
293 }
294 
FormatAppUidList(const struct CmBlob * list,struct CmAppUidList * appUidList)295 static int32_t FormatAppUidList(const struct CmBlob *list, struct CmAppUidList *appUidList)
296 {
297     uint32_t count = 0;
298     int32_t ret = CheckAuthListFileSizeValid(list, &count);
299     if (ret != CM_SUCCESS) {
300         return ret;
301     }
302 
303     if (count == 0) {
304         appUidList->appUidCount = 0;
305         CM_LOG_D("auth list has no auth uid");
306         return CM_SUCCESS; /* has no auth uid */
307     }
308 
309     uint8_t *data = (uint8_t *)CMMalloc(count * sizeof(uint32_t));
310     if (data == NULL) {
311         CM_LOG_E("malloc app uid buffer failed");
312         return ret = CMR_ERROR_MALLOC_FAIL;
313     }
314 
315     uint32_t offsetOut = 0;
316     uint32_t offset = sizeof(uint32_t) + sizeof(uint32_t);
317     for (uint32_t i = 0; i < count; ++i) {
318         (void)memcpy_s(data + offsetOut, sizeof(uint32_t), list->data + offset, sizeof(uint32_t));
319         offset += sizeof(uint32_t);
320         offsetOut += sizeof(uint32_t);
321     }
322 
323     appUidList->appUidCount = count;
324     appUidList->appUid = (uint32_t *)data;
325     return CM_SUCCESS;
326 }
327 
CmAddAuthUid(const struct CmContext * context,const struct CmBlob * uri,uint32_t uid)328 int32_t CmAddAuthUid(const struct CmContext *context, const struct CmBlob *uri, uint32_t uid)
329 {
330     int32_t ret = CmCheckCredentialExist(context, uri);
331     if (ret != CM_SUCCESS) {
332         return ret;
333     }
334 
335     char authListPath[MAX_PATH_LEN] = { 0 };
336     ret = ConstructAuthListPath(context, CM_CREDENTIAL_STORE, authListPath, MAX_PATH_LEN);
337     if (ret != CM_SUCCESS) {
338         return ret;
339     }
340 
341     ret = RefreshAuthList(authListPath, (char *)uri->data, uid, true);
342     if (ret != CM_SUCCESS) {
343         CM_LOG_E("refresh auth list failed, ret = %d", ret);
344     }
345     return ret;
346 }
347 
CmRemoveAuthUid(const struct CmContext * context,const struct CmBlob * uri,uint32_t uid)348 int32_t CmRemoveAuthUid(const struct CmContext *context, const struct CmBlob *uri, uint32_t uid)
349 {
350     char authListPath[MAX_PATH_LEN] = { 0 };
351     int32_t ret = ConstructAuthListPath(context, CM_CREDENTIAL_STORE, authListPath, MAX_PATH_LEN);
352     if (ret != CM_SUCCESS) {
353         return ret;
354     }
355 
356     ret = RefreshAuthList(authListPath, (char *)uri->data, uid, false);
357     if (ret != CM_SUCCESS) {
358         CM_LOG_E("refresh auth list failed, ret = %d", ret);
359     }
360     return ret;
361 }
362 
CmGetAuthList(const struct CmContext * context,const struct CmBlob * uri,struct CmAppUidList * appUidList)363 int32_t CmGetAuthList(const struct CmContext *context, const struct CmBlob *uri, struct CmAppUidList *appUidList)
364 {
365     char authListPath[MAX_PATH_LEN] = { 0 };
366     int32_t ret = ConstructAuthListPath(context, CM_CREDENTIAL_STORE, authListPath, MAX_PATH_LEN);
367     if (ret != CM_SUCCESS) {
368         return ret;
369     }
370 
371     /* auth list file not exist */
372     ret = CmIsFileExist(authListPath, (char *)uri->data);
373     if (ret != CM_SUCCESS) {
374         CM_LOG_D("auth list file not exist.");
375         appUidList->appUidCount = 0;
376         return CM_SUCCESS;
377     }
378 
379     struct CmBlob list = { 0, NULL };
380     ret = CmStorageGetBuf(authListPath, (char *)uri->data, &list);
381     if (ret != CM_SUCCESS) {
382         return ret;
383     }
384 
385     ret = FormatAppUidList(&list, appUidList);
386     CM_FREE_PTR(list.data);
387     return ret;
388 }
389 
CmDeleteAuthListFile(const struct CmContext * context,const struct CmBlob * uri)390 int32_t CmDeleteAuthListFile(const struct CmContext *context, const struct CmBlob *uri)
391 {
392     char authListPath[MAX_PATH_LEN] = { 0 };
393     int32_t ret = ConstructAuthListPath(context, CM_CREDENTIAL_STORE, authListPath, MAX_PATH_LEN);
394     if (ret != CM_SUCCESS) {
395         return ret;
396     }
397 
398     ret = CmIsFileExist(authListPath, (char *)uri->data);
399     if (ret != CM_SUCCESS) { /* auth list file not exist */
400         return CM_SUCCESS;
401     }
402 
403     ret = CmFileRemove(authListPath, (char *)uri->data);
404     if (ret != CM_SUCCESS) {
405         CM_LOG_E("remove file failed, ret = %d", ret);
406     }
407     return ret;
408 }
409 
CmCheckIsAuthUidExist(const struct CmContext * context,const struct CmBlob * uri,uint32_t targetUid,bool * isInAuthList)410 int32_t CmCheckIsAuthUidExist(const struct CmContext *context, const struct CmBlob *uri,
411     uint32_t targetUid, bool *isInAuthList)
412 {
413     *isInAuthList = false;
414 
415     char authListPath[MAX_PATH_LEN] = { 0 };
416     int32_t ret = ConstructAuthListPath(context, CM_CREDENTIAL_STORE, authListPath, MAX_PATH_LEN);
417     if (ret != CM_SUCCESS) {
418         return ret;
419     }
420 
421     ret = CmIsFileExist(authListPath, (char *)uri->data);
422     if (ret != CM_SUCCESS) { /* auth list file not exist */
423         return CM_SUCCESS;
424     }
425 
426     struct CmBlob list = { 0, NULL };
427     ret = CmStorageGetBuf(authListPath, (char *)uri->data, &list);
428     if (ret != CM_SUCCESS) {
429         return ret;
430     }
431 
432     uint32_t count = 0;
433     ret = CheckAuthListFileSizeValid(&list, &count);
434     if (ret != CM_SUCCESS) {
435         CM_FREE_PTR(list.data);
436         return ret;
437     }
438 
439     uint32_t position = 0;
440     *isInAuthList = IsUidExist(&list, count, targetUid, &position);
441     CM_FREE_PTR(list.data);
442 
443     return CM_SUCCESS;
444 }
445 
CmRemoveAuthUidByUserId(uint32_t userId,uint32_t targetUid,const struct CmBlob * uri)446 int32_t CmRemoveAuthUidByUserId(uint32_t userId, uint32_t targetUid, const struct CmBlob *uri)
447 {
448     uint32_t uid = 0;
449     int32_t ret = CertManagerGetUidFromUri(uri, &uid);
450     if (ret != CM_SUCCESS) {
451         return ret;
452     }
453 
454     struct CmContext context = { userId, uid, { 0 } };
455     return CmRemoveAuthUid(&context, uri, targetUid);
456 }
457 
CmGetAuthListByUserId(uint32_t userId,const struct CmBlob * uri,struct CmAppUidList * appUidList)458 int32_t CmGetAuthListByUserId(uint32_t userId, const struct CmBlob *uri, struct CmAppUidList *appUidList)
459 {
460     uint32_t uid = 0;
461     int32_t ret = CertManagerGetUidFromUri(uri, &uid);
462     if (ret != CM_SUCCESS) {
463         return ret;
464     }
465 
466     struct CmContext context = { userId, uid, { 0 } };
467     return CmGetAuthList(&context, uri, appUidList);
468 }
469 
CmDeleteAuthListFileByUserId(uint32_t userId,const struct CmBlob * uri)470 int32_t CmDeleteAuthListFileByUserId(uint32_t userId, const struct CmBlob *uri)
471 {
472     uint32_t uid = 0;
473     int32_t ret = CertManagerGetUidFromUri(uri, &uid);
474     if (ret != CM_SUCCESS) {
475         return ret;
476     }
477 
478     struct CmContext context = { userId, uid, { 0 } };
479     return CmDeleteAuthListFile(&context, uri);
480 }
481 
CmCheckIsAuthUidExistByUserId(uint32_t userId,uint32_t targetUid,const struct CmBlob * uri,bool * isInAuthList)482 int32_t CmCheckIsAuthUidExistByUserId(uint32_t userId, uint32_t targetUid,
483     const struct CmBlob *uri, bool *isInAuthList)
484 {
485     uint32_t uid = 0;
486     int32_t ret = CertManagerGetUidFromUri(uri, &uid);
487     if (ret != CM_SUCCESS) {
488         return ret;
489     }
490 
491     struct CmContext context = { userId, uid, { 0 } };
492     return CmCheckIsAuthUidExist(&context, uri, targetUid, isInAuthList);
493 }
494 
CmCheckCredentialExist(const struct CmContext * context,const struct CmBlob * uri)495 int32_t CmCheckCredentialExist(const struct CmContext *context, const struct CmBlob *uri)
496 {
497     char uidPath[MAX_PATH_LEN] = { 0 };
498     int32_t ret = ConstructUidPath(context, CM_CREDENTIAL_STORE, uidPath, MAX_PATH_LEN);
499     if (ret != CM_SUCCESS) {
500         return ret;
501     }
502 
503     char *fileName = (char *)uri->data;
504     ret = CmIsFileExist(uidPath, fileName);
505     if (ret != CM_SUCCESS) {
506         CM_LOG_E("Credential file not exist.");
507     }
508     return ret;
509 }
510 
511