• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     *value = cs;
232     return CMR_OK;
233 }
234 
ReadFile(const char * file,uint8_t ** bufptr,uint32_t * size)235 static int32_t ReadFile(const char *file, uint8_t **bufptr, uint32_t *size)
236 {
237     uint32_t sz = 0;
238     int32_t rc = CMR_OK;
239     uint8_t *buf = NULL;
240     uint32_t nb = 0;
241 
242     sz = CertManagerFileSize(CERT_STATUS_DIR, file);
243     if (sz == 0) {
244         CM_LOG_I("Status file not found\n");
245         goto finally;
246     }
247 
248     if (sz < HEADER_LEN) {
249         CM_LOG_W("Status file size too small. Must be at least %u bytes.\n", HEADER_LEN);
250         rc = CMR_ERROR_STORAGE;
251         goto finally;
252     }
253 
254     buf = CMMalloc(sz);
255     if (buf == NULL) {
256         CM_LOG_W("Failed to allocate memory.\n");
257         rc = CMR_ERROR_MALLOC_FAIL;
258         goto finally;
259     }
260     nb = CertManagerFileRead(CERT_STATUS_DIR, file, 0, buf, sz);
261     if (nb != sz) {
262         CM_LOG_W("Failed to read status file: %u bytes expected but only has %u\n", sz, nb);
263         rc = CMR_ERROR_STORAGE;
264         goto finally;
265     }
266 
267 finally:
268     if (rc != CMR_OK) {
269         FREE_PTR(buf);
270     } else {
271         *bufptr = buf;
272         *size = sz;
273     }
274     return rc;
275 }
276 
LoadTreeStatus(struct RbTree * tree,pthread_rwlock_t * treeLock,uint8_t * buf,uint32_t sz)277 static int32_t LoadTreeStatus(struct RbTree *tree, pthread_rwlock_t *treeLock, uint8_t *buf, uint32_t sz)
278 {
279     int32_t rc = CMR_OK;
280     CM_LOG_W("LoadTreeStatus6");
281     if (buf == NULL || sz == 0) {
282         /* file does not exist or is empty */
283         CM_LOG_D("Status file does not exist or is empty.");
284         return CMR_OK;
285     }
286 
287     uint32_t ver = DECODE_UINT32(buf);
288     /* currently version 1 (with value 0) is supported */
289     if (ver != VERSION_1) {
290         CM_LOG_W("Unsupported version: %u\n", ver);
291         return CMR_ERROR;
292     }
293 
294     uint8_t *tag = buf + sizeof(uint32_t);
295     uint8_t *data = tag + CM_INTEGRITY_TAG_LEN;
296     uint32_t dataLen = sz - sizeof(uint32_t) - CM_INTEGRITY_TAG_LEN;
297     uint8_t mac[CM_INTEGRITY_TAG_LEN] = {0};
298 
299     ASSERT_FUNC(Ikhmac(data, dataLen, mac));
300     if (memcmp(mac, tag, CM_INTEGRITY_TAG_LEN)) {
301         CM_LOG_W("Status file MAC mismatch.\n");
302         return CMR_ERROR;
303     }
304 
305     data += CM_INTEGRITY_SALT_LEN;
306     dataLen -= CM_INTEGRITY_SALT_LEN;
307     if (dataLen > 0) {
308         pthread_rwlock_wrlock(treeLock);
309         rc = RbTreeDecode(tree, DecodeStatus, DecodeFreeStatus, data, dataLen);
310         pthread_rwlock_unlock(treeLock);
311 
312         if (rc != CMR_OK) {
313             CM_LOG_E("Failed to decode status tree: %d", rc);
314             return rc;
315         }
316     }
317     CM_LOG_I("Status loaded for store");
318     return rc;
319 }
320 
LoadStatus(uint32_t store)321 static int32_t LoadStatus(uint32_t store)
322 {
323     uint32_t sz = 0;
324     int32_t rc = CMR_OK;
325     uint8_t *buf = NULL;
326 
327     int storeIndex = GetStoreIndex(store);
328     if (storeIndex < 0) {
329         return CMR_ERROR;
330     }
331     struct RbTree *tree = &g_trees[storeIndex];
332     const char *file = g_statusFiles[storeIndex];
333     pthread_rwlock_t *fileLock = &g_fileLocks[storeIndex];
334     pthread_rwlock_t *treeLock = &g_treeLocks[storeIndex];
335 
336     pthread_rwlock_rdlock(fileLock);
337     rc = ReadFile(file, &buf, &sz);
338     pthread_rwlock_unlock(fileLock);
339 
340     if (rc != CMR_OK) {
341         CM_LOG_E("Failed to read status file: %d", rc);
342         return rc;
343     }
344 
345     rc = LoadTreeStatus(tree, treeLock, buf, sz);
346 
347     if (buf != NULL) {
348         CMFree(buf);
349     }
350     return rc;
351 }
352 
EncodeTree(struct RbTree * tree,uint8_t ** bufptr,uint32_t * size)353 static int32_t EncodeTree(struct RbTree *tree, uint8_t **bufptr, uint32_t *size)
354 {
355     uint32_t sz = 0;
356     int32_t rc = RbTreeEncode(tree, EncodeStatus, NULL, &sz);
357     if (rc != CM_SUCCESS) {
358         CM_LOG_E("get rbtree encode length failed, ret = %d", rc);
359         return rc;
360     }
361     if (sz > MAX_STATUS_TREE_MALLOC_SIZE) {
362         CM_LOG_E("invalid encode tree size[%u]", sz);
363         return CMR_ERROR_INVALID_ARGUMENT;
364     }
365 
366     sz += HEADER_LEN;
367     uint8_t *buf = (uint8_t *)CMMalloc(sz);
368     if (buf == NULL) {
369         CM_LOG_E("Failed to allocate memory.\n");
370         return CMR_ERROR_MALLOC_FAIL;
371     }
372     (void)memset_s(buf, sz, 0, sz);
373 
374     ENCODE_UINT32(buf, VERSION_1);
375 
376     uint8_t *salt = buf + sizeof(uint32_t) + CM_INTEGRITY_TAG_LEN;
377     struct CmBlob r = { CM_INTEGRITY_SALT_LEN, salt };
378     (void)CmGetRandom(&r); /* ignore retcode */
379 
380     uint8_t *data = buf + HEADER_LEN;
381     uint32_t dataLen = sz - HEADER_LEN;
382     rc = RbTreeEncode(tree, EncodeStatus, data, &dataLen);
383     if (rc != CM_SUCCESS) {
384         CM_LOG_E("encode status tree failed, ret = %d", rc);
385         FREE_PTR(buf);
386         return rc;
387     }
388 
389     *bufptr = buf;
390     *size = sz;
391     return rc;
392 }
393 
WriteStatus(uint32_t store)394 static int32_t WriteStatus(uint32_t store)
395 {
396     int storeIndex = GetStoreIndex(store);
397     if (storeIndex < 0) {
398         return CMR_ERROR;
399     }
400     struct RbTree *tree = &g_trees[storeIndex];
401     const char *file = g_statusFiles[storeIndex];
402     pthread_rwlock_t *fileLock = &g_fileLocks[storeIndex];
403     pthread_rwlock_t *treeLock = &g_treeLocks[storeIndex];
404 
405     int32_t rc = CMR_OK;
406     uint8_t *buf = NULL;
407     uint32_t sz = 0;
408 
409     pthread_rwlock_rdlock(treeLock);
410     rc = EncodeTree(tree, &buf, &sz);
411     pthread_rwlock_unlock(treeLock);
412 
413     if (rc != CMR_OK) {
414         CM_LOG_E("Failed to encode status tree: %d", rc);
415         goto finally;
416     }
417 
418     uint8_t *tag = buf + sizeof(uint32_t);
419     uint8_t *data = tag + CM_INTEGRITY_TAG_LEN;
420     uint32_t dataLen = sz - sizeof(uint32_t) - CM_INTEGRITY_TAG_LEN;
421 
422     TRY_FUNC(Ikhmac(data, dataLen, tag), rc);
423 
424     pthread_rwlock_wrlock(fileLock);
425     rc = CertManagerFileWrite(CERT_STATUS_DIR, file, 0, buf, sz);
426     pthread_rwlock_unlock(fileLock);
427     if (rc != CMR_OK) {
428         CM_LOG_E("Failed to write status file: %d", rc);
429     }
430 
431 finally:
432     if (buf != NULL) {
433         CMFree(buf);
434     }
435     return rc;
436 }
437 
FreeTreeNodeValue(RbTreeKey key,RbTreeValue value,const void * context)438 static void FreeTreeNodeValue(RbTreeKey key, RbTreeValue value, const void *context)
439 {
440     (void)key;
441     (void)context;
442     if (value != NULL) {
443         /* value is used internally, it can ensure that the type conversion is safe */
444         FreeStatus((struct CertStatus *)value);
445     }
446 }
447 
DestroyTree(uint32_t store)448 static void DestroyTree(uint32_t store)
449 {
450     int storeIndex = GetStoreIndex(store);
451     if (storeIndex < 0) {
452         return;
453     }
454     struct RbTree *tree = &g_trees[storeIndex];
455     pthread_rwlock_t *treeLock = &g_treeLocks[storeIndex];
456 
457     pthread_rwlock_wrlock(treeLock);
458     RbTreeDestroyEx(tree, FreeTreeNodeValue);
459     pthread_rwlock_unlock(treeLock);
460 }
461 
DestroyStatusTree(void)462 static void DestroyStatusTree(void)
463 {
464     DestroyTree(CM_SYSTEM_TRUSTED_STORE);
465     DestroyTree(CM_USER_TRUSTED_STORE);
466     DestroyTree(CM_PRI_CREDENTIAL_STORE);
467 }
468 
CertManagerStatusInit(void)469 int32_t CertManagerStatusInit(void)
470 {
471     int rc = CMR_OK;
472     if (CmMakeDir(CERT_STATUS_DIR) == CMR_ERROR_MAKE_DIR_FAIL) {
473         CM_LOG_E("Failed to create folder\n");
474         return CMR_ERROR_WRITE_FILE_FAIL;
475     }
476 
477     pthread_rwlock_wrlock(&g_statusLock);
478     for (uint32_t i = 0; i < g_treeCount; i++) {
479         TRY_FUNC(RbTreeNew(&g_trees[i]), rc);
480     }
481 
482     char aliasData[] = CM_INTEGRITY_KEY_URI;
483     struct CmBlob alias = { strlen(aliasData), (uint8_t *)aliasData };
484     TRY_FUNC(CmKeyOpGenMacKeyIfNotExist(&alias), rc);
485     TRY_FUNC(LoadStatus(CM_SYSTEM_TRUSTED_STORE), rc);
486     TRY_FUNC(LoadStatus(CM_USER_TRUSTED_STORE), rc);
487     TRY_FUNC(LoadStatus(CM_PRI_CREDENTIAL_STORE), rc);
488 
489 finally:
490     if (rc != CM_SUCCESS) {
491         DestroyStatusTree();
492     }
493     pthread_rwlock_unlock(&g_statusLock);
494     return rc;
495 }
496 
GetRbTreeKeyFromName(const char * name)497 static RbTreeKey GetRbTreeKeyFromName(const char *name)
498 {
499     /* use the first 4 bytes of file name (exluding the first bit) as the key */
500     uint32_t len = strlen(name);
501     if (len == 0) {
502         return 0;
503     }
504 
505     len = (len < RB_TREE_KEY_LEN) ? len : RB_TREE_KEY_LEN;
506     uint8_t temp[RB_TREE_KEY_LEN] = {0};
507     if (memcpy_s(temp, RB_TREE_KEY_LEN, name, len) != EOK) {
508         return 0;
509     }
510 
511     return DECODE_UINT32(temp) & 0x7fffffff;
512 }
513 
GetRbTreeKeyFromNameBlob(const struct CmBlob * name)514 static RbTreeKey GetRbTreeKeyFromNameBlob(const struct CmBlob *name)
515 {
516     /* name size is ensured bigger than 4; use the first 4 bytes of file name (exluding the first bit) as the key */
517     return DECODE_UINT32(name->data) & 0x7fffffff;
518 }
519 
GetRbTreeKey(uint32_t store,const char * fn)520 static RbTreeKey GetRbTreeKey(uint32_t store, const char *fn)
521 {
522     if (store == CM_SYSTEM_TRUSTED_STORE) {
523         return GetRbTreeKeyFromName(fn);
524     }
525 
526     uint8_t tempBuf[MAX_NAME_DIGEST_LEN] = {0};
527     struct CmBlob nameDigest = { sizeof(tempBuf), tempBuf };
528     struct CmBlob certName = { (uint32_t)strlen(fn) + 1, (uint8_t *)fn };
529     (void)CmGetHash(&certName, &nameDigest); /* ignore return code: nameDigest is 0 */
530 
531     return GetRbTreeKeyFromNameBlob(&nameDigest);
532 }
533 
GetCertStatusNode(const struct RbTreeNode * node)534 static uint32_t GetCertStatusNode(const struct RbTreeNode *node)
535 {
536     if (node == NULL) {
537         /* not in the cache. by .default certificate is enabled. */
538         return CERT_STATUS_ENABLED;
539     }
540 
541     struct CertStatus *cs = node->value;
542     if (cs == NULL) {
543         return CERT_STATUS_ENABLED;
544     }
545     return cs->status;
546 }
547 
SetCertStatusNode(const struct CmContext * ctx,struct RbTree * tree,struct RbTreeNode * node,const char * name,uint32_t status)548 static int32_t SetCertStatusNode(const struct CmContext *ctx, struct RbTree *tree,
549     struct RbTreeNode *node, const char *name, uint32_t status)
550 {
551     if (node != NULL) {
552         /* found a matching node */
553         struct CertStatus *cs = node->value;
554         if (cs == NULL) {
555             CM_LOG_E("No status attached to tree node !!\n");
556             return CMR_ERROR;
557         }
558 
559         if (status == CERT_STATUS_ENABLED) {
560             /* the default status is ENABLED. hence, we just delete it from the tree */
561             FreeStatus(cs);
562             node->value = NULL;
563             return RbTreeDelete(tree, node);
564         }
565 
566         /* for other status values, just overwrite */
567         cs->status = status;
568         return CMR_OK;
569     } else {
570         /* no match was found, insert a new node */
571         struct CertStatus *cs = CMMalloc(sizeof(struct CertStatus));
572         if (cs == NULL) {
573             CM_LOG_E("Unable to allocate memory!!\n");
574             return CMR_ERROR_MALLOC_FAIL;
575         }
576         cs->userId = ctx->userId;
577         cs->uid = ctx->uid;
578         cs->fileName = strdup(name);
579         cs->status = status;
580         int rc = RbTreeInsert(tree, GetRbTreeKeyFromName(name), cs);
581         if (rc != CMR_OK) {
582             CM_LOG_E("Failed to insert new node: %d\n", rc);
583             CMFree(cs->fileName);
584             CMFree(cs);
585         }
586         return rc;
587     }
588 }
589 
SetUserCertStatusNode(const struct CertStatus * valInfo,struct RbTree * tree,struct RbTreeNode * node,const char * name,uint32_t store)590 static int32_t SetUserCertStatusNode(const struct CertStatus *valInfo, struct RbTree *tree,
591     struct RbTreeNode *node, const char *name, uint32_t store)
592 {
593     uint32_t status = valInfo->status;
594 
595     if (node != NULL) {
596         /* found a matching node */
597         struct CertStatus *cStatus = node->value;
598         if (cStatus == NULL) {
599             CM_LOG_E("No status attached to tree node !!\n");
600             return CMR_ERROR;
601         }
602 
603         if (status == CERT_STATUS_ENABLED) {
604             /* the default status is ENABLED. hence, we just delete it from the tree */
605             FreeStatus(cStatus);
606             node->value = NULL;
607             return RbTreeDelete(tree, node);
608         }
609 
610         /* for other status values, just overwrite */
611         cStatus->status = status;
612         return CMR_OK;
613     } else {
614         /* no match was found, insert a new node */
615         struct CertStatus *cStatus = CMMalloc(sizeof(struct CertStatus));
616         if (cStatus == NULL) {
617             CM_LOG_E("Unable to allocate memory!!\n");
618             return CMR_ERROR_MALLOC_FAIL;
619         }
620         cStatus->userId = valInfo->userId;
621         cStatus->uid = valInfo->uid;
622         cStatus->fileName = strdup(name);
623         cStatus->status = status;
624         int rc = RbTreeInsert(tree, GetRbTreeKey(store, name), cStatus);
625         if (rc != CMR_OK) {
626             CM_LOG_E("Failed to insert new node: %d\n", rc);
627             CMFree(cStatus->fileName);
628             CMFree(cStatus);
629         }
630         return rc;
631     }
632 }
633 
634 
635 /* 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)636 static bool StatusMatch(const struct CmContext *context, const struct CertStatus *cs,
637     uint32_t store, const char *fileName)
638 {
639     if (context == NULL || cs == NULL || fileName == NULL) {
640         CM_LOG_E("Paramset is NULL");
641         return false;
642     }
643 
644     if (strcmp(cs->fileName, fileName)) {
645         /* file name must always match */
646         return false;
647     }
648 
649     if (store == CM_USER_TRUSTED_STORE) {
650         /* for user store, the user ID must match the caller */
651         if (cs->userId != context->userId) {
652             return false;
653         }
654     } else if (store == CM_PRI_CREDENTIAL_STORE) {
655         /* for application store, the user ID and app UID must match the caller */
656         if (cs->userId != context->userId ||
657                 cs->uid != context->uid) {
658             return false;
659         }
660     }
661     return true;
662 }
663 
CertManagerFindMatchedFile(const struct CmContext * context,struct RbTreeNode ** treeNode,struct RbTree * tree,struct TreeNode tempPara,const char * fn)664 static int32_t CertManagerFindMatchedFile(const struct CmContext *context, struct RbTreeNode **treeNode,
665     struct RbTree *tree, struct TreeNode tempPara, const char *fn)
666 {
667     uint32_t store = tempPara.store;
668     bool *found = tempPara.found;
669     RbTreeKey key = tempPara.key;
670     struct RbTreeNode *node = *treeNode;
671 
672     while (node != NULL && node != tree->nil) {
673         struct CertStatus *cs = node->value;
674         if (cs == NULL) {
675             /* shouldn't happen */
676             CM_LOG_E("No value set to status node.\n");
677             return CMR_ERROR;
678         }
679 
680         if (StatusMatch(context, cs, store, fn)) {
681             /* match found */
682             *found = true;
683             break;
684         }
685 
686         if (node->right != tree->nil && RbTreeNodeKey(node->right) == key) {
687             node = node->right;
688         } else if (node->left != tree->nil && RbTreeNodeKey(node->left) == key) {
689             node = node->left;
690         } else {
691             /* no match possible */
692             break;
693         }
694     }
695     *treeNode = node;
696     return CMR_OK;
697 }
698 
CertManagerStatus(const struct CmContext * context,struct RbTree * tree,struct CertEnableStatus certStatus,uint32_t store,const char * fn)699 static int32_t CertManagerStatus(const struct CmContext *context, struct RbTree *tree,
700     struct CertEnableStatus certStatus, uint32_t store, const char *fn)
701 {
702     int rc = CMR_OK;
703     bool found = false;
704     struct RbTreeNode *node = NULL;
705     bool getter = certStatus.getter;
706     uint32_t status = certStatus.status;
707     uint32_t *oldStatus = certStatus.oldStatus;
708     RbTreeKey key = GetRbTreeKey(store, fn);
709 
710     rc = RbTreeFindNode(&node, key, tree);
711     if (rc != CMR_OK && rc != CMR_ERROR_NOT_FOUND) {
712         /* someting is wrong */
713         CM_LOG_W("Failed to search in the status cache");
714         return rc;
715     }
716 
717     /* furthrt check if the actual file name matched. */
718     struct TreeNode tempPara = {store, &found, key};
719     rc = CertManagerFindMatchedFile(context, &node, tree, tempPara, fn);
720     if (rc != CMR_OK) {
721         CM_LOG_W("Failed to search file name");
722         return rc;
723     }
724 
725     if (!found) {
726         node = NULL;
727     }
728 
729     *oldStatus = GetCertStatusNode(node);
730     if (!getter && *oldStatus != status) {
731         CM_LOG_I("start setting status");
732         if (store == CM_SYSTEM_TRUSTED_STORE) {
733             ASSERT_FUNC(SetCertStatusNode(context, tree, node, fn, status));
734         } else {
735             struct CertStatus valueInfo = { context->userId, context->uid, status, NULL };
736             ASSERT_FUNC(SetUserCertStatusNode(&valueInfo, tree, node, fn, store));
737         }
738     }
739     return rc;
740 }
741 
CertManagerIsCallerPrivileged(const struct CmContext * context)742 static int32_t CertManagerIsCallerPrivileged(const struct CmContext *context)
743 {
744     (void) context;
745     return CMR_OK;
746 }
747 
CertManagerCheckStorePermission(const struct CmContext * context,uint32_t store,bool statusOnly)748 static int32_t CertManagerCheckStorePermission(const struct CmContext *context, uint32_t store, bool statusOnly)
749 {
750     /* System Store is read-only therefore we don't even try to use it. */
751     if (store == CM_SYSTEM_TRUSTED_STORE) {
752         if (!statusOnly) {
753             CM_LOG_E("Storege type %u should be read on;y\n", store);
754             return CMR_ERROR_NOT_PERMITTED;
755         } else if (CertManagerIsCallerPrivileged(context) != CMR_OK) {
756             CM_LOG_W("Only privileged caller can change status in system stores.\n");
757             return CMR_ERROR_NOT_PERMITTED;
758         }
759     } else if (store == CM_CREDENTIAL_STORE) {
760         CM_LOG_E("Credential certificates should be set via CertManagerIsCallerPrivileged\n");
761         return CMR_ERROR_NOT_SUPPORTED;
762     } else if (store == CM_USER_TRUSTED_STORE) {
763         /* only priviled callers can update the user store */
764         if (CertManagerIsCallerPrivileged(context) != CMR_OK) {
765             CM_LOG_W("Only privileged caller can modify user stores.\n");
766             return CMR_ERROR_NOT_PERMITTED;
767         }
768     } else if (store == CM_PRI_CREDENTIAL_STORE) {
769         /* no additional checks here. context->caller can remove its own */
770     } else {
771         CM_LOG_W("Invalid store type. Only a asingle store should be indicated: %u\n", store);
772         return CMR_ERROR_INVALID_ARGUMENT;
773     }
774 
775     return CMR_OK;
776 }
777 
CertManagerStatusFile(const struct CmContext * context,struct CertFile certFile,uint32_t store,const uint32_t status,uint32_t * stp)778 static int32_t CertManagerStatusFile(const struct CmContext *context, struct CertFile certFile,
779     uint32_t store, const uint32_t status, uint32_t *stp)
780 {
781     ASSERT_ARGS(context && certFile.path && certFile.fileName);
782     ASSERT_ARGS(certFile.path->size && certFile.path->data && certFile.fileName->size && certFile.fileName->data);
783     ASSERT_ARGS((status <= CERT_STATUS_MAX || stp != NULL));
784     ASSERT_FUNC(CertManagerCheckStorePermission(context, store, true));
785 
786     int rc = CMR_OK;
787     uint32_t oldStatus = 0;
788     bool getter = (stp != NULL);
789     int storeIndex = GetStoreIndex(store);
790     if (storeIndex < 0) {
791         return CMR_ERROR;
792     }
793     pthread_rwlock_t *lock = &g_treeLocks[storeIndex];
794     struct RbTree *tree = &g_trees[storeIndex];
795 
796     char fn[MAX_LEN_URI] = {0};
797     if (memcpy_s(fn, MAX_LEN_URI, certFile.fileName->data, certFile.fileName->size) != EOK) {
798         CM_LOG_E("copy filename error");
799         return CMR_ERROR;
800     }
801 
802     if (getter) {
803         pthread_rwlock_rdlock(lock);
804     } else {
805         pthread_rwlock_wrlock(lock);
806     }
807     struct CertEnableStatus certStatus = {getter, &oldStatus, status};
808     rc = CertManagerStatus(context, tree, certStatus, store, fn);
809 
810     pthread_rwlock_unlock(lock);
811     if (rc != CMR_OK && rc != CMR_ERROR_NOT_FOUND) {
812         /* error occured */
813         return rc;
814     }
815     if (getter) {
816         *stp = oldStatus;
817     } else if (oldStatus != status) {
818         /* setter */
819         ASSERT_FUNC(WriteStatus(store));
820     }
821     return CMR_OK;
822 }
823 
SetcertStatus(const struct CmContext * context,const struct CmBlob * certUri,uint32_t store,uint32_t status,uint32_t * stp)824 int32_t SetcertStatus(const struct CmContext *context, const struct CmBlob *certUri,
825     uint32_t store, uint32_t status, uint32_t *stp)
826 {
827     char pathBuf[CERT_MAX_PATH_LEN] = {0};
828     struct CmMutableBlob path = { sizeof(pathBuf), (uint8_t *) pathBuf };
829     struct CertFile certFile = { 0, 0 };
830     int32_t ret = CertManagerFindCertFileNameByUri(context, certUri, store, &path);
831     if (ret != CMR_OK) {
832         CM_LOG_E("CertManagerFindCertFileNameByUri error = %d", ret);
833         return ret;
834     }
835     certFile.path = &(CM_BLOB(&path));
836     certFile.fileName = &(CM_BLOB(certUri));
837 
838     return CertManagerStatusFile(context, certFile, store, status, stp);
839 }
840 
CmSetStatusEnable(const struct CmContext * context,struct CmMutableBlob * pathBlob,const struct CmBlob * certUri,uint32_t store)841 int32_t CmSetStatusEnable(const struct CmContext *context, struct CmMutableBlob *pathBlob,
842     const struct CmBlob *certUri, uint32_t store)
843 {
844     struct CertFile certFile = { 0, 0 };
845     certFile.path = &(CM_BLOB(pathBlob));
846     certFile.fileName = &(CM_BLOB(certUri));
847 
848     return CertManagerStatusFile(context, certFile, store, CERT_STATUS_ENANLED, NULL);
849 }
850 
CmGetCertStatus(const struct CmContext * context,struct CertFileInfo * cFile,uint32_t store,uint32_t * status)851 int32_t CmGetCertStatus(const struct CmContext *context, struct CertFileInfo *cFile,
852     uint32_t store, uint32_t *status)
853 {
854     struct CertFile certFile = { NULL, NULL };
855     certFile.path = &(cFile->path);
856     certFile.fileName = &(cFile->fileName);
857 
858     return CertManagerStatusFile(context, certFile, store, CERT_STATUS_INVALID, status);
859 }
860 #ifdef __cplusplus
861 }
862 #endif
863