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