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