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