• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2025 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_status.h"
17 
18 #include <pthread.h>
19 
20 #include "securec.h"
21 
22 #include "cert_manager.h"
23 #include "cert_manager_crypto_operation.h"
24 #include "cert_manager_file.h"
25 #include "cert_manager_file_operator.h"
26 #include "cert_manager_key_operation.h"
27 #include "cert_manager_mem.h"
28 #include "cm_log.h"
29 #include "cm_type.h"
30 #include "rbtree.h"
31 #include "cert_manager_uri.h"
32 #include "cert_manager_storage.h"
33 
34 #define HEADER_LEN (4 + CM_INTEGRITY_TAG_LEN + CM_INTEGRITY_SALT_LEN)
35 #define APPLICATION_TRUSTED_STORE      2
36 #define ENCODED_INT_COUNT              3
37 
38 #define MAX_NAME_DIGEST_LEN            64
39 #define RB_TREE_KEY_LEN                4
40 
41 #define MAX_STATUS_TREE_MALLOC_SIZE    (5 * 1024 * 1024)   /* max 5M tree file size */
42 
43 #ifdef __cplusplus
44 extern "C" {
45 #endif
46 
47 /* red-black tree to store disabled certificate file names. */
48 static struct RbTree g_trees[] = { {0}, {0}, {0} };
49 static const uint32_t g_treeCount = 3;
50 
51 static const char *g_statusFiles[] = {
52     CERT_STATUS_SYSTEM_STORE,
53     CERT_STATUS_USER_STORE,
54     CERT_STATUS_APPLICATION_STORE,
55 };
56 
57 static pthread_rwlock_t g_treeLocks[] = {
58     PTHREAD_RWLOCK_INITIALIZER,
59     PTHREAD_RWLOCK_INITIALIZER,
60     PTHREAD_RWLOCK_INITIALIZER,
61 };
62 
63 static pthread_rwlock_t g_fileLocks[] = {
64     PTHREAD_RWLOCK_INITIALIZER,
65     PTHREAD_RWLOCK_INITIALIZER,
66     PTHREAD_RWLOCK_INITIALIZER,
67 };
68 
69 static pthread_rwlock_t g_statusLock = PTHREAD_RWLOCK_INITIALIZER;
70 
71 struct CertEnableStatus {
72     bool getter;
73     uint32_t *oldStatus;
74     uint32_t status;
75 };
76 
77 struct TreeNode {
78     uint32_t store;
79     bool *found;
80     RbTreeKey key;
81 };
82 
Ikhmac(uint8_t * data,uint32_t len,uint8_t * mac)83 static int32_t Ikhmac(uint8_t *data, uint32_t len, uint8_t *mac)
84 {
85     struct CmBlob dataBlob = { .size = len, .data = data };
86     struct CmBlob macBlob = { .size = CM_INTEGRITY_TAG_LEN, .data = mac };
87 
88     char aliasData[] = CM_INTEGRITY_KEY_URI;
89     struct CmBlob alias = { strlen(aliasData), (uint8_t *)aliasData };
90     return CmKeyOpCalcMac(&alias, &dataBlob, &macBlob, CM_AUTH_STORAGE_LEVEL_EL1);
91 }
92 
FreeStatus(struct CertStatus * cs)93 static void FreeStatus(struct CertStatus *cs)
94 {
95     if (cs != NULL) {
96         if (cs->fileName != NULL) {
97             CMFree(cs->fileName);
98         }
99         CMFree(cs);
100     }
101 }
102 
GetStoreIndex(uint32_t store)103 static int GetStoreIndex(uint32_t store)
104 {
105     switch (store) {
106         case CM_SYSTEM_TRUSTED_STORE:
107             return 0;
108         case CM_USER_TRUSTED_STORE:
109             return 1;
110         case CM_PRI_CREDENTIAL_STORE:
111             return APPLICATION_TRUSTED_STORE;
112         default:
113             CM_LOG_W("No index for store %u\n", store);
114             return -1;
115     }
116 }
117 
EncodeStatus(RbTreeValue value,uint8_t * buf,uint32_t * size)118 static int EncodeStatus(RbTreeValue value, uint8_t *buf, uint32_t *size)
119 {
120     /* each cert status struct is encoded as (userId | uid | status | fileName)
121        Note that fileName is null terminated */
122 
123     struct CertStatus *cs = (struct CertStatus *) value;
124     if (cs == NULL) {
125         CM_LOG_E("Unexpected NULL value.\n");
126         return CMR_ERROR;
127     }
128 
129     /* encode 3 integers and a string */
130     uint32_t sz = 3 * sizeof(uint32_t) + strlen(cs->fileName) + 1;
131 
132     if (buf == NULL) {
133         /* only return the required size */
134         *size = sz;
135         return CMR_OK;
136     }
137 
138     if (*size < sz) {
139         return CMR_ERROR_BUFFER_TOO_SMALL;
140     }
141     uint8_t *s = buf;
142     uint32_t r = *size;
143 
144     if (memcpy_s(s, r, &cs->userId, sizeof(uint32_t)) != EOK) {
145         CM_LOG_W("Failed to cs->userId ");
146         return CMR_ERROR;
147     }
148     s += sizeof(uint32_t);
149     r -= sizeof(uint32_t);
150 
151     if (memcpy_s(s, r, &cs->uid, sizeof(uint32_t)) != EOK) {
152         CM_LOG_W("Failed to cs->uid ");
153         return CMR_ERROR;
154     }
155     s += sizeof(uint32_t);
156     r -= sizeof(uint32_t);
157 
158     if (memcpy_s(s, r, &cs->status, sizeof(uint32_t)) != EOK) {
159         CM_LOG_W("Failed to cs->status ");
160         return CMR_ERROR;
161     }
162     s += sizeof(uint32_t);
163     r -= sizeof(uint32_t);
164 
165     if (memcpy_s(s, r, cs->fileName, strlen(cs->fileName) + 1) != EOK) {
166         CM_LOG_W("Failed to cs->fileName ");
167         return CMR_ERROR;
168     }
169 
170     *size = sz;
171     return CMR_OK;
172 }
173 
DecodeFreeStatus(RbTreeValue * value)174 static void DecodeFreeStatus(RbTreeValue *value)
175 {
176     if (value == NULL || *value == NULL) {
177         return;
178     }
179 
180     /* value is used internally, it can ensure that the type conversion is safe */
181     FreeStatus((struct CertStatus *)*value);
182     *value = NULL;
183 }
184 
DecodeStatus(RbTreeValue * value,const uint8_t * buf,uint32_t size)185 static int DecodeStatus(RbTreeValue *value, const uint8_t *buf, uint32_t size)
186 {
187     /* each cert status struct is encoded as (userId | uid | status | fileName)
188        Note that fileName is null terminated
189        Require 3 integers and at least 1 character */
190     if (buf == NULL || size < ENCODED_INT_COUNT * sizeof(uint32_t) + 1) {
191         return CMR_ERROR_BUFFER_TOO_SMALL;
192     }
193 
194     if (buf[size - 1] != '\0') {
195         CM_LOG_E("Unexpected cert status value");
196         return CMR_ERROR;
197     }
198 
199     struct CertStatus *cs = (struct CertStatus *)CMMalloc(sizeof(struct CertStatus));
200     if (cs == NULL) {
201         CM_LOG_E("Failed to allocate memory");
202         return CMR_ERROR_MALLOC_FAIL;
203     }
204     (void)memset_s(cs, sizeof(struct CertStatus), 0, sizeof(struct CertStatus));
205 
206     const uint8_t *s = buf;
207 
208     int32_t ret = CM_FAILURE;
209     do {
210         if (memcpy_s(&cs->userId, sizeof(uint32_t), s, sizeof(uint32_t)) != EOK) {
211             break;
212         }
213         s += sizeof(uint32_t);
214 
215         if (memcpy_s(&cs->uid, sizeof(uint32_t), s, sizeof(uint32_t)) != EOK) {
216             break;
217         }
218         s += sizeof(uint32_t);
219 
220         if (memcpy_s(&cs->status, sizeof(uint32_t), s, sizeof(uint32_t)) != EOK) {
221             break;
222         }
223         s += sizeof(uint32_t);
224         ret = CM_SUCCESS;
225     } while (0);
226     if (ret != CM_SUCCESS) {
227         CM_LOG_E("copy to cs failed");
228         CMFree(cs);
229         return ret;
230     }
231 
232     cs->fileName = strdup((char *)s);
233     if (cs->fileName == NULL) {
234         CM_LOG_E("strdup to cs->fileName failed");
235         CMFree(cs);
236         return CMR_ERROR_MALLOC_FAIL;
237     }
238     *value = cs;
239     return CMR_OK;
240 }
241 
ReadFile(const char * file,uint8_t ** bufptr,uint32_t * size)242 static int32_t ReadFile(const char *file, uint8_t **bufptr, uint32_t *size)
243 {
244     uint32_t sz = 0;
245     int32_t rc = CMR_OK;
246     uint8_t *buf = NULL;
247     uint32_t nb = 0;
248 
249     sz = CertManagerFileSize(CERT_STATUS_DIR, file);
250     if (sz == 0) {
251         CM_LOG_D("Status file not found\n");
252         goto finally;
253     }
254 
255     if (sz < HEADER_LEN) {
256         CM_LOG_W("Status file size too small. Must be at least %u bytes.\n", HEADER_LEN);
257         rc = CMR_ERROR_STORAGE;
258         goto finally;
259     }
260 
261     buf = CMMalloc(sz);
262     if (buf == NULL) {
263         CM_LOG_W("Failed to allocate memory.\n");
264         rc = CMR_ERROR_MALLOC_FAIL;
265         goto finally;
266     }
267     nb = CertManagerFileRead(CERT_STATUS_DIR, file, 0, buf, sz);
268     if (nb != sz) {
269         CM_LOG_W("Failed to read status file: %u bytes expected but only has %u\n", sz, nb);
270         rc = CMR_ERROR_STORAGE;
271         goto finally;
272     }
273 
274 finally:
275     if (rc != CMR_OK) {
276         FREE_PTR(buf);
277     } else {
278         *bufptr = buf;
279         *size = sz;
280     }
281     return rc;
282 }
283 
LoadTreeStatus(struct RbTree * tree,pthread_rwlock_t * treeLock,uint8_t * buf,uint32_t sz)284 static int32_t LoadTreeStatus(struct RbTree *tree, pthread_rwlock_t *treeLock, uint8_t *buf, uint32_t sz)
285 {
286     int32_t rc = CMR_OK;
287     if (buf == NULL || sz == 0) {
288         /* file does not exist or is empty */
289         CM_LOG_D("Status file does not exist or is empty.");
290         return CMR_OK;
291     }
292 
293     uint32_t ver = DECODE_UINT32(buf);
294     /* currently version 1 (with value 0) is supported */
295     if (ver != VERSION_1) {
296         CM_LOG_W("Unsupported version: %u\n", ver);
297         return CMR_ERROR;
298     }
299 
300     uint8_t *tag = buf + sizeof(uint32_t);
301     uint8_t *data = tag + CM_INTEGRITY_TAG_LEN;
302     uint32_t dataLen = sz - sizeof(uint32_t) - CM_INTEGRITY_TAG_LEN;
303     uint8_t mac[CM_INTEGRITY_TAG_LEN] = {0};
304 
305     ASSERT_FUNC(Ikhmac(data, dataLen, mac));
306     if (memcmp(mac, tag, CM_INTEGRITY_TAG_LEN)) {
307         CM_LOG_W("Status file MAC mismatch.\n");
308         return CMR_ERROR;
309     }
310 
311     data += CM_INTEGRITY_SALT_LEN;
312     dataLen -= CM_INTEGRITY_SALT_LEN;
313     if (dataLen > 0) {
314         pthread_rwlock_wrlock(treeLock);
315         rc = RbTreeDecode(tree, DecodeStatus, DecodeFreeStatus, data, dataLen);
316         pthread_rwlock_unlock(treeLock);
317 
318         if (rc != CMR_OK) {
319             CM_LOG_E("Failed to decode status tree: %d", rc);
320             return rc;
321         }
322     }
323     CM_LOG_D("Status loaded for store");
324     return rc;
325 }
326 
LoadStatus(uint32_t store)327 static int32_t LoadStatus(uint32_t store)
328 {
329     uint32_t sz = 0;
330     int32_t rc = CMR_OK;
331     uint8_t *buf = NULL;
332 
333     int storeIndex = GetStoreIndex(store);
334     if (storeIndex < 0) {
335         return CMR_ERROR;
336     }
337     struct RbTree *tree = &g_trees[storeIndex];
338     const char *file = g_statusFiles[storeIndex];
339     pthread_rwlock_t *fileLock = &g_fileLocks[storeIndex];
340     pthread_rwlock_t *treeLock = &g_treeLocks[storeIndex];
341 
342     pthread_rwlock_rdlock(fileLock);
343     rc = ReadFile(file, &buf, &sz);
344     pthread_rwlock_unlock(fileLock);
345 
346     if (rc != CMR_OK) {
347         CM_LOG_E("Failed to read status file: %d", rc);
348         return rc;
349     }
350 
351     rc = LoadTreeStatus(tree, treeLock, buf, sz);
352 
353     if (buf != NULL) {
354         CMFree(buf);
355     }
356     return rc;
357 }
358 
EncodeTree(struct RbTree * tree,uint8_t ** bufptr,uint32_t * size)359 static int32_t EncodeTree(struct RbTree *tree, uint8_t **bufptr, uint32_t *size)
360 {
361     uint32_t sz = 0;
362     int32_t rc = RbTreeEncode(tree, EncodeStatus, NULL, &sz);
363     if (rc != CM_SUCCESS) {
364         CM_LOG_E("get rbtree encode length failed, ret = %d", rc);
365         return rc;
366     }
367     if (sz > MAX_STATUS_TREE_MALLOC_SIZE) {
368         CM_LOG_E("invalid encode tree size[%u]", sz);
369         return CMR_ERROR_INVALID_ARGUMENT;
370     }
371 
372     sz += HEADER_LEN;
373     uint8_t *buf = (uint8_t *)CMMalloc(sz);
374     if (buf == NULL) {
375         CM_LOG_E("Failed to allocate memory.\n");
376         return CMR_ERROR_MALLOC_FAIL;
377     }
378     (void)memset_s(buf, sz, 0, sz);
379 
380     ENCODE_UINT32(buf, VERSION_1);
381 
382     uint8_t *salt = buf + sizeof(uint32_t) + CM_INTEGRITY_TAG_LEN;
383     struct CmBlob r = { CM_INTEGRITY_SALT_LEN, salt };
384     (void)CmGetRandom(&r); /* ignore retcode */
385 
386     uint8_t *data = buf + HEADER_LEN;
387     uint32_t dataLen = sz - HEADER_LEN;
388     rc = RbTreeEncode(tree, EncodeStatus, data, &dataLen);
389     if (rc != CM_SUCCESS) {
390         CM_LOG_E("encode status tree failed, ret = %d", rc);
391         FREE_PTR(buf);
392         return rc;
393     }
394 
395     *bufptr = buf;
396     *size = sz;
397     return rc;
398 }
399 
WriteStatus(uint32_t store)400 static int32_t WriteStatus(uint32_t store)
401 {
402     int storeIndex = GetStoreIndex(store);
403     if (storeIndex < 0) {
404         return CMR_ERROR;
405     }
406     struct RbTree *tree = &g_trees[storeIndex];
407     const char *file = g_statusFiles[storeIndex];
408     pthread_rwlock_t *fileLock = &g_fileLocks[storeIndex];
409     pthread_rwlock_t *treeLock = &g_treeLocks[storeIndex];
410 
411     int32_t rc = CMR_OK;
412     uint8_t *buf = NULL;
413     uint32_t sz = 0;
414 
415     pthread_rwlock_rdlock(treeLock);
416     rc = EncodeTree(tree, &buf, &sz);
417     pthread_rwlock_unlock(treeLock);
418 
419     if (rc != CMR_OK) {
420         CM_LOG_E("Failed to encode status tree: %d", rc);
421         goto finally;
422     }
423 
424     uint8_t *tag = buf + sizeof(uint32_t);
425     uint8_t *data = tag + CM_INTEGRITY_TAG_LEN;
426     uint32_t dataLen = sz - sizeof(uint32_t) - CM_INTEGRITY_TAG_LEN;
427 
428     TRY_FUNC(Ikhmac(data, dataLen, tag), rc);
429 
430     pthread_rwlock_wrlock(fileLock);
431     rc = CertManagerFileWrite(CERT_STATUS_DIR, file, 0, buf, sz);
432     pthread_rwlock_unlock(fileLock);
433     if (rc != CMR_OK) {
434         CM_LOG_E("Failed to write status file: %d", rc);
435     }
436 
437 finally:
438     if (buf != NULL) {
439         CMFree(buf);
440     }
441     return rc;
442 }
443 
FreeTreeNodeValue(RbTreeKey key,RbTreeValue value,const void * context)444 static void FreeTreeNodeValue(RbTreeKey key, RbTreeValue value, const void *context)
445 {
446     (void)key;
447     (void)context;
448     if (value != NULL) {
449         /* value is used internally, it can ensure that the type conversion is safe */
450         FreeStatus((struct CertStatus *)value);
451     }
452 }
453 
DestroyTree(uint32_t store)454 static void DestroyTree(uint32_t store)
455 {
456     int storeIndex = GetStoreIndex(store);
457     if (storeIndex < 0) {
458         return;
459     }
460     struct RbTree *tree = &g_trees[storeIndex];
461     pthread_rwlock_t *treeLock = &g_treeLocks[storeIndex];
462 
463     pthread_rwlock_wrlock(treeLock);
464     RbTreeDestroyEx(tree, FreeTreeNodeValue);
465     pthread_rwlock_unlock(treeLock);
466 }
467 
DestroyStatusTree(void)468 static void DestroyStatusTree(void)
469 {
470     DestroyTree(CM_SYSTEM_TRUSTED_STORE);
471     DestroyTree(CM_USER_TRUSTED_STORE);
472     DestroyTree(CM_PRI_CREDENTIAL_STORE);
473 }
474 
CertManagerStatusInit(void)475 int32_t CertManagerStatusInit(void)
476 {
477     int rc = CMR_OK;
478     if (CmMakeDir(CERT_STATUS_DIR) == CMR_ERROR_MAKE_DIR_FAIL) {
479         CM_LOG_E("Failed to create folder\n");
480         return CMR_ERROR_WRITE_FILE_FAIL;
481     }
482 
483     pthread_rwlock_wrlock(&g_statusLock);
484     for (uint32_t i = 0; i < g_treeCount; i++) {
485         TRY_FUNC(RbTreeNew(&g_trees[i]), rc);
486     }
487 
488     char aliasData[] = CM_INTEGRITY_KEY_URI;
489     struct CmBlob alias = { strlen(aliasData), (uint8_t *)aliasData };
490     TRY_FUNC(CmKeyOpGenMacKeyIfNotExist(&alias), rc);
491     TRY_FUNC(LoadStatus(CM_SYSTEM_TRUSTED_STORE), rc);
492     TRY_FUNC(LoadStatus(CM_USER_TRUSTED_STORE), rc);
493     TRY_FUNC(LoadStatus(CM_PRI_CREDENTIAL_STORE), rc);
494 
495 finally:
496     if (rc != CM_SUCCESS) {
497         DestroyStatusTree();
498     }
499     pthread_rwlock_unlock(&g_statusLock);
500     return rc;
501 }
502 
GetRbTreeKeyFromName(const char * name)503 static RbTreeKey GetRbTreeKeyFromName(const char *name)
504 {
505     /* use the first 4 bytes of file name (exluding the first bit) as the key */
506     uint32_t len = strlen(name);
507     if (len == 0) {
508         return 0;
509     }
510 
511     len = (len < RB_TREE_KEY_LEN) ? len : RB_TREE_KEY_LEN;
512     uint8_t temp[RB_TREE_KEY_LEN] = {0};
513     if (memcpy_s(temp, RB_TREE_KEY_LEN, name, len) != EOK) {
514         return 0;
515     }
516 
517     return DECODE_UINT32(temp) & 0x7fffffff;
518 }
519 
GetRbTreeKeyFromNameBlob(const struct CmBlob * name)520 static RbTreeKey GetRbTreeKeyFromNameBlob(const struct CmBlob *name)
521 {
522     /* name size is ensured bigger than 4; use the first 4 bytes of file name (exluding the first bit) as the key */
523     return DECODE_UINT32(name->data) & 0x7fffffff;
524 }
525 
GetRbTreeKey(uint32_t store,const char * fn)526 static RbTreeKey GetRbTreeKey(uint32_t store, const char *fn)
527 {
528     if (store == CM_SYSTEM_TRUSTED_STORE) {
529         return GetRbTreeKeyFromName(fn);
530     }
531 
532     uint8_t tempBuf[MAX_NAME_DIGEST_LEN] = {0};
533     struct CmBlob nameDigest = { sizeof(tempBuf), tempBuf };
534     struct CmBlob certName = { (uint32_t)strlen(fn) + 1, (uint8_t *)fn };
535     (void)CmGetHash(&certName, &nameDigest); /* ignore return code: nameDigest is 0 */
536 
537     return GetRbTreeKeyFromNameBlob(&nameDigest);
538 }
539 
GetCertStatusNode(const struct RbTreeNode * node)540 static uint32_t GetCertStatusNode(const struct RbTreeNode *node)
541 {
542     if (node == NULL) {
543         /* not in the cache. by .default certificate is enabled. */
544         return CERT_STATUS_ENABLED;
545     }
546 
547     struct CertStatus *cs = node->value;
548     if (cs == NULL) {
549         return CERT_STATUS_ENABLED;
550     }
551     return cs->status;
552 }
553 
SetCertStatusNode(const struct CmContext * ctx,struct RbTree * tree,struct RbTreeNode * node,const char * name,uint32_t status)554 static int32_t SetCertStatusNode(const struct CmContext *ctx, struct RbTree *tree,
555     struct RbTreeNode *node, const char *name, uint32_t status)
556 {
557     if (node != NULL) {
558         /* found a matching node */
559         struct CertStatus *cs = node->value;
560         if (cs == NULL) {
561             CM_LOG_E("No status attached to tree node !!\n");
562             return CMR_ERROR;
563         }
564 
565         if (status == CERT_STATUS_ENABLED) {
566             /* the default status is ENABLED. hence, we just delete it from the tree */
567             FreeStatus(cs);
568             node->value = NULL;
569             return RbTreeDelete(tree, node);
570         }
571 
572         /* for other status values, just overwrite */
573         cs->status = status;
574         return CMR_OK;
575     } else {
576         /* no match was found, insert a new node */
577         struct CertStatus *cs = CMMalloc(sizeof(struct CertStatus));
578         if (cs == NULL) {
579             CM_LOG_E("Unable to allocate memory!!\n");
580             return CMR_ERROR_MALLOC_FAIL;
581         }
582         cs->userId = ctx->userId;
583         cs->uid = ctx->uid;
584         cs->fileName = strdup(name);
585         if (cs->fileName == NULL) {
586             CM_LOG_E("strdup to cs->fileName failed\n");
587             CMFree(cs);
588             return CMR_ERROR_MALLOC_FAIL;
589         }
590         cs->status = status;
591         int rc = RbTreeInsert(tree, GetRbTreeKeyFromName(name), cs);
592         if (rc != CMR_OK) {
593             CM_LOG_E("Failed to insert new node: %d\n", rc);
594             CMFree(cs->fileName);
595             CMFree(cs);
596         }
597         return rc;
598     }
599 }
600 
SetUserCertStatusNode(const struct CertStatus * valInfo,struct RbTree * tree,struct RbTreeNode * node,const char * name,uint32_t store)601 static int32_t SetUserCertStatusNode(const struct CertStatus *valInfo, struct RbTree *tree,
602     struct RbTreeNode *node, const char *name, uint32_t store)
603 {
604     uint32_t status = valInfo->status;
605 
606     if (node != NULL) {
607         /* found a matching node */
608         struct CertStatus *cStatus = node->value;
609         if (cStatus == NULL) {
610             CM_LOG_E("No status attached to tree node !!\n");
611             return CMR_ERROR;
612         }
613 
614         if (status == CERT_STATUS_ENABLED) {
615             /* the default status is ENABLED. hence, we just delete it from the tree */
616             FreeStatus(cStatus);
617             node->value = NULL;
618             return RbTreeDelete(tree, node);
619         }
620 
621         /* for other status values, just overwrite */
622         cStatus->status = status;
623         return CMR_OK;
624     } else {
625         /* no match was found, insert a new node */
626         struct CertStatus *cStatus = CMMalloc(sizeof(struct CertStatus));
627         if (cStatus == NULL) {
628             CM_LOG_E("Unable to allocate memory!!\n");
629             return CMR_ERROR_MALLOC_FAIL;
630         }
631         cStatus->userId = valInfo->userId;
632         cStatus->uid = valInfo->uid;
633         cStatus->fileName = strdup(name);
634         if (cStatus->fileName == NULL) {
635             CM_LOG_E("strdup to cs->fileName failed\n");
636             CMFree(cStatus);
637             return CMR_ERROR_MALLOC_FAIL;
638         }
639         cStatus->status = status;
640         int rc = RbTreeInsert(tree, GetRbTreeKey(store, name), cStatus);
641         if (rc != CMR_OK) {
642             CM_LOG_E("Failed to insert new node: %d\n", rc);
643             CMFree(cStatus->fileName);
644             CMFree(cStatus);
645         }
646         return rc;
647     }
648 }
649 
650 
651 /* return true if the status matches the filename and the caller */
StatusMatch(const struct CmContext * context,const struct CertStatus * cs,uint32_t store,const char * fileName)652 static bool StatusMatch(const struct CmContext *context, const struct CertStatus *cs,
653     uint32_t store, const char *fileName)
654 {
655     if (context == NULL || cs == NULL || fileName == NULL) {
656         CM_LOG_E("Paramset is NULL");
657         return false;
658     }
659 
660     if (strcmp(cs->fileName, fileName)) {
661         /* file name must always match */
662         return false;
663     }
664 
665     if (store == CM_USER_TRUSTED_STORE) {
666         /* for user store, the user ID must match the caller */
667         if (cs->userId != context->userId) {
668             return false;
669         }
670     } else if (store == CM_PRI_CREDENTIAL_STORE) {
671         /* for application store, the user ID and app UID must match the caller */
672         if (cs->userId != context->userId ||
673                 cs->uid != context->uid) {
674             return false;
675         }
676     }
677     return true;
678 }
679 
CertManagerFindMatchedFile(const struct CmContext * context,struct RbTreeNode ** treeNode,struct RbTree * tree,struct TreeNode tempPara,const char * fn)680 static int32_t CertManagerFindMatchedFile(const struct CmContext *context, struct RbTreeNode **treeNode,
681     struct RbTree *tree, struct TreeNode tempPara, const char *fn)
682 {
683     uint32_t store = tempPara.store;
684     bool *found = tempPara.found;
685     RbTreeKey key = tempPara.key;
686     struct RbTreeNode *node = *treeNode;
687 
688     while (node != NULL && node != tree->nil) {
689         struct CertStatus *cs = node->value;
690         if (cs == NULL) {
691             /* shouldn't happen */
692             CM_LOG_E("No value set to status node.\n");
693             return CMR_ERROR;
694         }
695 
696         if (StatusMatch(context, cs, store, fn)) {
697             /* match found */
698             *found = true;
699             break;
700         }
701 
702         if (node->right != tree->nil && RbTreeNodeKey(node->right) == key) {
703             node = node->right;
704         } else if (node->left != tree->nil && RbTreeNodeKey(node->left) == key) {
705             node = node->left;
706         } else {
707             /* no match possible */
708             break;
709         }
710     }
711     *treeNode = node;
712     return CMR_OK;
713 }
714 
CertManagerStatus(const struct CmContext * context,struct RbTree * tree,struct CertEnableStatus certStatus,uint32_t store,const char * fn)715 static int32_t CertManagerStatus(const struct CmContext *context, struct RbTree *tree,
716     struct CertEnableStatus certStatus, uint32_t store, const char *fn)
717 {
718     int rc = CMR_OK;
719     bool found = false;
720     struct RbTreeNode *node = NULL;
721     bool getter = certStatus.getter;
722     uint32_t status = certStatus.status;
723     uint32_t *oldStatus = certStatus.oldStatus;
724     RbTreeKey key = GetRbTreeKey(store, fn);
725 
726     rc = RbTreeFindNode(&node, key, tree);
727     if (rc != CMR_OK && rc != CMR_ERROR_NOT_FOUND) {
728         /* someting is wrong */
729         CM_LOG_W("Failed to search in the status cache");
730         return rc;
731     }
732 
733     /* furthrt check if the actual file name matched. */
734     struct TreeNode tempPara = {store, &found, key};
735     rc = CertManagerFindMatchedFile(context, &node, tree, tempPara, fn);
736     if (rc != CMR_OK) {
737         CM_LOG_W("Failed to search file name");
738         return rc;
739     }
740 
741     if (!found) {
742         node = NULL;
743     }
744 
745     *oldStatus = GetCertStatusNode(node);
746     if (!getter && *oldStatus != status) {
747         CM_LOG_D("start setting status");
748         if (store == CM_SYSTEM_TRUSTED_STORE) {
749             ASSERT_FUNC(SetCertStatusNode(context, tree, node, fn, status));
750         } else {
751             struct CertStatus valueInfo = { context->userId, context->uid, status, NULL };
752             ASSERT_FUNC(SetUserCertStatusNode(&valueInfo, tree, node, fn, store));
753         }
754     }
755     return rc;
756 }
757 
CertManagerStatusFile(const struct CmContext * context,struct CertFile certFile,uint32_t store,const uint32_t status,uint32_t * stp)758 static int32_t CertManagerStatusFile(const struct CmContext *context, struct CertFile certFile,
759     uint32_t store, const uint32_t status, uint32_t *stp)
760 {
761     ASSERT_ARGS(context && certFile.path && certFile.fileName);
762     ASSERT_ARGS(certFile.path->size && certFile.path->data && certFile.fileName->size && certFile.fileName->data);
763     ASSERT_ARGS((status <= CERT_STATUS_MAX || stp != NULL));
764 
765     int rc = CMR_OK;
766     uint32_t oldStatus = 0;
767     bool getter = (stp != NULL);
768     int storeIndex = GetStoreIndex(store);
769     if (storeIndex < 0) {
770         return CMR_ERROR;
771     }
772     pthread_rwlock_t *lock = &g_treeLocks[storeIndex];
773     struct RbTree *tree = &g_trees[storeIndex];
774 
775     char fn[MAX_LEN_URI] = {0};
776     if (memcpy_s(fn, MAX_LEN_URI, certFile.fileName->data, certFile.fileName->size) != EOK) {
777         CM_LOG_E("copy filename error");
778         return CMR_ERROR;
779     }
780 
781     if (getter) {
782         pthread_rwlock_rdlock(lock);
783     } else {
784         pthread_rwlock_wrlock(lock);
785     }
786     struct CertEnableStatus certStatus = {getter, &oldStatus, status};
787     rc = CertManagerStatus(context, tree, certStatus, store, fn);
788 
789     pthread_rwlock_unlock(lock);
790     if (rc != CMR_OK && rc != CMR_ERROR_NOT_FOUND) {
791         /* error occured */
792         return rc;
793     }
794     if (getter) {
795         *stp = oldStatus;
796     } else if (oldStatus != status) {
797         /* setter */
798         ASSERT_FUNC(WriteStatus(store));
799     }
800     return CMR_OK;
801 }
802 
SetcertStatus(const struct CmContext * context,const struct CmBlob * certUri,uint32_t store,uint32_t status,uint32_t * stp)803 int32_t SetcertStatus(const struct CmContext *context, const struct CmBlob *certUri,
804     uint32_t store, uint32_t status, uint32_t *stp)
805 {
806     char pathBuf[CERT_MAX_PATH_LEN] = {0};
807     struct CmMutableBlob path = { sizeof(pathBuf), (uint8_t *) pathBuf };
808     struct CertFile certFile = { 0, 0 };
809     int32_t ret = CertManagerFindCertFileNameByUri(context, certUri, store, false, &path);
810     if (ret != CMR_OK) {
811         /*
812          * If the store type is not CM_SYSTEM_TRUSTED_STORE, ret is returned.
813          * Otherwise, try to obtain the gm system ca path.
814          */
815         CM_LOG_E("CertManagerFindCertFileNameByUri error = %d", ret);
816         if (store != CM_SYSTEM_TRUSTED_STORE) {
817             return ret;
818         }
819 
820         path.size = sizeof(pathBuf); /* clear path data and size */
821         (void)memset_s(path.data, path.size, 0, path.size);
822         ret = CertManagerFindCertFileNameByUri(context, certUri, store, true, &path);
823         if (ret != CMR_OK) {
824             CM_LOG_E("CertManagerFindCertFileNameByUri gm system ca error = %d", ret);
825             return ret;
826         }
827     }
828     certFile.path = &(CM_BLOB(&path));
829     certFile.fileName = &(CM_BLOB(certUri));
830 
831     return CertManagerStatusFile(context, certFile, store, status, stp);
832 }
833 
CmSetStatusEnable(const struct CmContext * context,struct CmMutableBlob * pathBlob,const struct CmBlob * certUri,uint32_t store)834 int32_t CmSetStatusEnable(const struct CmContext *context, struct CmMutableBlob *pathBlob,
835     const struct CmBlob *certUri, uint32_t store)
836 {
837     struct CertFile certFile = { 0, 0 };
838     certFile.path = &(CM_BLOB(pathBlob));
839     certFile.fileName = &(CM_BLOB(certUri));
840 
841     return CertManagerStatusFile(context, certFile, store, CERT_STATUS_ENANLED, NULL);
842 }
843 
CmGetCertStatus(const struct CmContext * context,struct CertFileInfo * cFile,uint32_t store,uint32_t * status)844 int32_t CmGetCertStatus(const struct CmContext *context, struct CertFileInfo *cFile,
845     uint32_t store, uint32_t *status)
846 {
847     struct CertFile certFile = { NULL, NULL };
848     certFile.path = &(cFile->path);
849     certFile.fileName = &(cFile->fileName);
850 
851     return CertManagerStatusFile(context, certFile, store, CERT_STATUS_INVALID, status);
852 }
853 
CmGetCertConfigStatus(const char * fileName,uint32_t * status)854 int32_t CmGetCertConfigStatus(const char *fileName, uint32_t *status)
855 {
856     if (fileName == NULL || status == NULL) {
857         CM_LOG_E("Check param invalid");
858         return CMR_ERROR_INVALID_ARGUMENT;
859     }
860     struct CMUri uriObj = { 0 };
861     int32_t ret = CertManagerUriDecode(&uriObj, fileName);
862     if (ret != CM_SUCCESS) {
863         CM_LOG_E("Failed to decode uri, ret = %d", ret);
864         return ret;
865     }
866     char confFilePath[CERT_MAX_PATH_LEN] = { 0 };
867     if (sprintf_s(confFilePath, CERT_MAX_PATH_LEN, "%s/%s/%s/%s%s", CERT_BACKUP_CONFIG_ROOT_DIR, uriObj.user,
868         uriObj.app, fileName, CERT_CONFIG_FILE_SUFFIX) < 0) {
869         CM_LOG_E("Failed sprintf conf file path");
870         (void)CertManagerFreeUri(&uriObj);
871         return CMR_ERROR_BUFFER_TOO_SMALL;
872     }
873     (void)CertManagerFreeUri(&uriObj);
874 
875     ret = CmIsFileExist(NULL, confFilePath);
876     if (ret != CM_SUCCESS) {
877         CM_LOG_I("Cert config file not exist");
878         *status = CERT_STATUS_DISABLED;
879     } else {
880         CM_LOG_I("Cert config file exist");
881         *status = CERT_STATUS_ENABLED;
882     }
883     return CM_SUCCESS;
884 }
885 #ifdef __cplusplus
886 }
887 #endif
888