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