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.h"
17
18 #include <unistd.h>
19
20 #include "cert_manager_auth_mgr.h"
21 #include "cert_manager_file.h"
22 #include "cert_manager_file_operator.h"
23 #include "cert_manager_key_operation.h"
24 #include "cert_manager_mem.h"
25 #include "cert_manager_permission_check.h"
26 #include "cert_manager_status.h"
27 #include "cert_manager_storage.h"
28 #include "cert_manager_uri.h"
29 #include "cm_log.h"
30 #include "cm_type.h"
31 #include "cm_x509.h"
32
33 #include "securec.h"
34
35 #include "hks_api.h"
36
37 #define MAX_PATH_LEN 256
38
39 #ifdef __cplusplus
40 extern "C" {
41 #endif
42
43 static bool g_hksInitialized = false;
44
CertManagerInitialize(void)45 int32_t CertManagerInitialize(void)
46 {
47 if (!g_hksInitialized) {
48 ASSERT_CM_CALL(HksInitialize());
49 g_hksInitialized = true;
50 }
51
52 if (CmMakeDir(CERT_DIR) == CMR_ERROR_MAKE_DIR_FAIL) {
53 CM_LOG_E("Failed to create folder\n");
54 return CMR_ERROR_WRITE_FILE_FAIL;
55 }
56
57 ASSERT_FUNC(CertManagerStatusInit());
58
59 return CMR_OK;
60 }
61
GetFilePath(const struct CmContext * context,uint32_t store,char * pathPtr,char * suffix,uint32_t * suffixLen)62 static int32_t GetFilePath(const struct CmContext *context, uint32_t store, char *pathPtr,
63 char *suffix, uint32_t *suffixLen)
64 {
65 int32_t ret, retVal;
66 if (suffix == NULL || suffixLen == NULL) {
67 CM_LOG_E("NULL pointer failure");
68 return CMR_ERROR_NULL_POINTER;
69 }
70
71 switch (store) {
72 if (context == NULL) {
73 CM_LOG_E("Null pointer failture");
74 return CMR_ERROR_NULL_POINTER;
75 }
76 case CM_CREDENTIAL_STORE:
77 case CM_USER_TRUSTED_STORE:
78 case CM_PRI_CREDENTIAL_STORE:
79 if (store == CM_CREDENTIAL_STORE) {
80 ret = sprintf_s(pathPtr, MAX_PATH_LEN, "%s%u", CREDNTIAL_STORE, context->userId);
81 } else if (store == CM_PRI_CREDENTIAL_STORE) {
82 ret = sprintf_s(pathPtr, MAX_PATH_LEN, "%s%u", APP_CA_STORE, context->userId);
83 } else {
84 ret = sprintf_s(pathPtr, MAX_PATH_LEN, "%s%u", USER_CA_STORE, context->userId);
85 }
86
87 retVal = sprintf_s(suffix, MAX_SUFFIX_LEN, "%u", context->uid);
88 if (ret < 0 || retVal < 0) {
89 CM_LOG_E("Construct file Path failed ret:%d, retVal:%d", ret, retVal);
90 return CMR_ERROR;
91 }
92 break;
93 case CM_SYSTEM_TRUSTED_STORE:
94 ret = sprintf_s(pathPtr, MAX_PATH_LEN, "%s", SYSTEM_CA_STORE);
95 if (ret < 0) {
96 return CMR_ERROR;
97 }
98 break;
99
100 default:
101 return CMR_ERROR_NOT_SUPPORTED;
102 }
103 *suffixLen = (uint32_t)strlen(suffix);
104 return CMR_OK;
105 }
106
CmGetFilePath(const struct CmContext * context,uint32_t store,struct CmMutableBlob * pathBlob)107 static int32_t CmGetFilePath(const struct CmContext *context, uint32_t store, struct CmMutableBlob *pathBlob)
108 {
109 char pathPtr[MAX_PATH_LEN] = {0};
110 uint32_t suffixLen = 0;
111 char suffixBuf[MAX_SUFFIX_LEN] = {0};
112
113 if ((pathBlob == NULL) || (pathBlob->data == NULL)) {
114 CM_LOG_E("Null pointer failure");
115 return CMR_ERROR_NULL_POINTER;
116 }
117 int32_t ret = GetFilePath(context, store, pathPtr, suffixBuf, &suffixLen);
118 if (ret != CMR_OK) {
119 CM_LOG_E("Get file path faild");
120 return CMR_ERROR;
121 }
122
123 /* Create folder if it does not exist */
124 if (CmMakeDir(pathPtr) == CMR_ERROR_MAKE_DIR_FAIL) {
125 CM_LOG_E("Failed to create path folder");
126 return CMR_ERROR_WRITE_FILE_FAIL;
127 }
128
129 if (pathBlob->size - 1 < strlen(pathPtr) + suffixLen) {
130 CM_LOG_E("Failed to copy path");
131 return CMR_ERROR_BUFFER_TOO_SMALL;
132 }
133
134 char *path = (char *)pathBlob->data;
135 if (suffixLen == 0) {
136 if (sprintf_s(path, MAX_PATH_LEN, "%s", pathPtr) < 0) {
137 return CM_FAILURE;
138 }
139 } else {
140 if (sprintf_s(path, MAX_PATH_LEN, "%s/%s", pathPtr, suffixBuf) < 0) {
141 return CM_FAILURE;
142 }
143 }
144
145 pathBlob->size = strlen(path) + 1;
146 if (CmMakeDir(path) == CMR_ERROR_MAKE_DIR_FAIL) {
147 CM_LOG_E("Failed to create folder");
148 return CMR_ERROR_WRITE_FILE_FAIL;
149 }
150 return CMR_OK;
151 }
152
FindObjectCert(const struct CmBlob * certUri,const struct CmMutableBlob * fNames,uint32_t certCount)153 static int32_t FindObjectCert(const struct CmBlob *certUri, const struct CmMutableBlob *fNames, uint32_t certCount)
154 {
155 for (uint32_t i = 0; i < certCount; i++) {
156 if (fNames[i].data == NULL) {
157 CM_LOG_E("Corrupted file name at index: %u", i);
158 return CMR_ERROR_STORAGE;
159 }
160 /* Check if url is matching with the cert filename */
161 if ((certUri->size <= fNames[i].size) && (memcmp(certUri->data, fNames[i].data, certUri->size) == 0)) {
162 return CM_SUCCESS;
163 }
164 }
165 return CMR_ERROR_NOT_FOUND;
166 }
167
CertManagerFindCertFileNameByUri(const struct CmContext * context,const struct CmBlob * certUri,uint32_t store,struct CmMutableBlob * path)168 int32_t CertManagerFindCertFileNameByUri(const struct CmContext *context, const struct CmBlob *certUri,
169 uint32_t store, struct CmMutableBlob *path)
170 {
171 ASSERT_ARGS(context && certUri && certUri->data);
172
173 int32_t ret = CmGetFilePath(context, store, path);
174 if (ret != CM_SUCCESS) {
175 CM_LOG_E("Failed obtain path for store %x\n", store);
176 return ret;
177 }
178
179 struct CmMutableBlob fileNames = { 0, NULL };
180 ret = CertManagerGetFilenames(&fileNames, (char *)path->data);
181 if (ret != CM_SUCCESS) {
182 CM_LOG_E("Failed obtain filenames from path");
183 return CMR_ERROR_STORAGE;
184 }
185
186 struct CmMutableBlob *fNames = (struct CmMutableBlob *)fileNames.data;
187 ret = FindObjectCert(certUri, fNames, fileNames.size);
188 FreeFileNames(fNames, fileNames.size);
189 if (ret != CM_SUCCESS) {
190 CM_LOG_E("No cert matched, err: %d", ret);
191 }
192 return ret;
193 }
194
CmRemoveAppCert(const struct CmContext * context,const struct CmBlob * keyUri,const uint32_t store)195 int32_t CmRemoveAppCert(const struct CmContext *context, const struct CmBlob *keyUri,
196 const uint32_t store)
197 {
198 ASSERT_ARGS(context && keyUri && keyUri->data && keyUri->size);
199 int32_t ret;
200 if (store == CM_CREDENTIAL_STORE) {
201 ret = CmAuthDeleteAuthInfo(context, keyUri);
202 if (ret != CM_SUCCESS) {
203 CM_LOG_E("delete auth info failed when remove app certificate."); /* ignore ret code, only record log */
204 }
205 }
206
207 char pathBuf[CERT_MAX_PATH_LEN] = {0};
208 struct CmMutableBlob path = { sizeof(pathBuf), (uint8_t*) pathBuf };
209
210 ret = CmGetFilePath(context, store, &path);
211 if (ret != CMR_OK) {
212 CM_LOG_E("Failed obtain path for store %u", store);
213 return ret;
214 }
215
216 ret = CertManagerFileRemove(pathBuf, (char *)keyUri->data);
217 if (ret != CMR_OK) {
218 CM_LOG_E("CertManagerFileRemove failed ret: %d", ret);
219 return ret;
220 }
221 ret = CmKeyOpDeleteKey(keyUri);
222 if (ret != CM_SUCCESS) { /* ignore the return of deleteKey */
223 CM_LOG_I("CertManagerKeyRemove failed, ret: %d", ret);
224 }
225
226 return CMR_OK;
227 }
228
ClearAuthInfo(const struct CmContext * context,const struct CmBlob * keyUri,const uint32_t store)229 static void ClearAuthInfo(const struct CmContext *context, const struct CmBlob *keyUri, const uint32_t store)
230 {
231 if (store != CM_CREDENTIAL_STORE) {
232 return;
233 }
234
235 int32_t ret = CmAuthDeleteAuthInfo(context, keyUri);
236 if (ret != CM_SUCCESS) {
237 CM_LOG_E("delete auth info failed."); /* ignore ret code, only record log */
238 }
239 }
240
CmAppCertGetFilePath(const struct CmContext * context,const uint32_t store,struct CmBlob * path)241 static int32_t CmAppCertGetFilePath(const struct CmContext *context, const uint32_t store, struct CmBlob *path)
242 {
243 int32_t ret = CM_FAILURE;
244
245 switch (store) {
246 case CM_CREDENTIAL_STORE :
247 ret = sprintf_s((char*)path->data, MAX_PATH_LEN, "%s%u/%u", CREDNTIAL_STORE, context->userId, context->uid);
248 break;
249 case CM_PRI_CREDENTIAL_STORE :
250 ret = sprintf_s((char*)path->data, MAX_PATH_LEN, "%s%u", APP_CA_STORE, context->userId);
251 break;
252 default:
253 break;
254 }
255 if (ret < 0) {
256 return CM_FAILURE;
257 }
258 return CM_SUCCESS;
259 }
260
CmFreeFileNames(struct CmBlob * fileNames,const uint32_t fileSize)261 void CmFreeFileNames(struct CmBlob *fileNames, const uint32_t fileSize)
262 {
263 if (fileNames == NULL) {
264 CM_LOG_E("CmFreeFileNames fileNames is null");
265 return;
266 }
267
268 for (uint32_t i = 0; i < fileSize; i++) {
269 if (fileNames[i].data != NULL) {
270 CMFree(fileNames[i].data);
271 fileNames[i].size = 0;
272 }
273 }
274 }
275
CmGetUri(const char * filePath,struct CmBlob * uriBlob)276 int32_t CmGetUri(const char *filePath, struct CmBlob *uriBlob)
277 {
278 if ((filePath == NULL) || (uriBlob == NULL) || (uriBlob->data == NULL)) {
279 CM_LOG_E("CmGetUri param is null");
280 return CM_FAILURE;
281 }
282
283 uint32_t filePathLen = strlen(filePath);
284 if ((filePathLen == 0) || (filePathLen > CM_MAX_FILE_NAME_LEN)) {
285 return CMR_ERROR_INVALID_ARGUMENT;
286 }
287
288 int32_t i = (int32_t)(filePathLen - 1);
289 for (; i >= 0; i--) {
290 if (filePath[i] == '/') {
291 break;
292 }
293 }
294
295 int32_t index = i + 1; /* index range: 0 to filePathLen */
296 uint32_t uriLen = filePathLen - (uint32_t)index + 1; /* include '\0' at end, range: 1 to filePathLen + 1 */
297 if (memcpy_s(uriBlob->data, uriBlob->size, &filePath[index], uriLen) != EOK) {
298 return CMR_ERROR_BUFFER_TOO_SMALL;
299 }
300 uriBlob->size = uriLen;
301
302 return CM_SUCCESS;
303 }
304
CmRemoveSpecifiedAppCert(const struct CmContext * context,const uint32_t store)305 static int32_t CmRemoveSpecifiedAppCert(const struct CmContext *context, const uint32_t store)
306 {
307 uint32_t fileCount = 0;
308 int32_t retCode, ret = CM_SUCCESS;
309 char pathBuf[CERT_MAX_PATH_LEN] = {0};
310 char uriBuf[MAX_LEN_URI] = {0};
311 struct CmBlob fileNames[MAX_COUNT_CERTIFICATE];
312 struct CmBlob path = { sizeof(pathBuf), (uint8_t*)pathBuf };
313 struct CmBlob uriBlob = { sizeof(uriBuf), (uint8_t*)uriBuf };
314 uint32_t len = MAX_COUNT_CERTIFICATE * sizeof(struct CmBlob);
315 (void)memset_s(fileNames, len, 0, len);
316
317 do {
318 if (CmAppCertGetFilePath(context, store, &path) != CM_SUCCESS) {
319 ret = CM_FAILURE;
320 CM_LOG_E("Get file path for store:%u faild", store);
321 break;
322 }
323
324 if (CmUserIdLayerGetFileCountAndNames(pathBuf, fileNames, MAX_COUNT_CERTIFICATE, &fileCount) != CM_SUCCESS) {
325 ret = CM_FAILURE;
326 CM_LOG_E("Get file count and names from path faild");
327 break;
328 }
329
330 for (uint32_t i = 0; i < fileCount; i++) {
331 if (CertManagerFileRemove(NULL, (char *)fileNames[i].data) != CM_SUCCESS) {
332 CM_LOG_E("App cert %u remove faild", i);
333 continue;
334 }
335
336 uriBlob.size = sizeof(uriBuf);
337 (void)memset_s(uriBuf, uriBlob.size, 0, uriBlob.size);
338 if (CmGetUri((char *)fileNames[i].data, &uriBlob) != CM_SUCCESS) {
339 CM_LOG_E("Get uri failed");
340 continue;
341 }
342
343 retCode = CmKeyOpDeleteKey(&uriBlob);
344 if (retCode != CM_SUCCESS) { /* ignore the return of deleteKey */
345 CM_LOG_I("App key %u remove failed ret: %d", i, retCode);
346 }
347 ClearAuthInfo(context, &uriBlob, store);
348 }
349 } while (0);
350
351 CmFreeFileNames(fileNames, MAX_COUNT_CERTIFICATE);
352 return ret;
353 }
354
CmRemoveAllAppCert(const struct CmContext * context)355 int32_t CmRemoveAllAppCert(const struct CmContext *context)
356 {
357 if (!CmHasPrivilegedPermission() || !CmHasCommonPermission()) {
358 CM_LOG_E("permission check failed");
359 return CMR_ERROR_PERMISSION_DENIED;
360 }
361 if (!CmIsSystemApp()) {
362 CM_LOG_E("remove app cert: caller is not system app");
363 return CMR_ERROR_NOT_SYSTEMP_APP;
364 }
365
366 /* Only public and private credential removed can be returned */
367 /* remove pubic credential app cert */
368 int32_t ret = CmRemoveSpecifiedAppCert(context, CM_CREDENTIAL_STORE);
369 if (ret != CM_SUCCESS) {
370 CM_LOG_E("remove pubic credential app cert faild");
371 }
372
373 /* remove private credential app cert */
374 ret = CmRemoveSpecifiedAppCert(context, CM_PRI_CREDENTIAL_STORE);
375 if (ret != CM_SUCCESS) {
376 CM_LOG_E("remove private credential app cert faild");
377 }
378
379 return ret;
380 }
381
CmServiceGetAppCertList(const struct CmContext * context,uint32_t store,struct CmBlob * fileNames,const uint32_t fileSize,uint32_t * fileCount)382 int32_t CmServiceGetAppCertList(const struct CmContext *context, uint32_t store, struct CmBlob *fileNames,
383 const uint32_t fileSize, uint32_t *fileCount)
384 {
385 char pathBuf[CERT_MAX_PATH_LEN] = {0};
386 struct CmBlob path = { sizeof(pathBuf), (uint8_t*)pathBuf };
387
388 int32_t ret = CmAppCertGetFilePath(context, store, &path);
389 if (ret != CM_SUCCESS) {
390 CM_LOG_E("Get file path for store:%u faild", store);
391 return CM_FAILURE;
392 }
393
394 CM_LOG_I("Get app cert list path");
395
396 if (store == CM_CREDENTIAL_STORE) {
397 ret = CmUidLayerGetFileCountAndNames(pathBuf, fileNames, fileSize, fileCount);
398 } else {
399 ret = CmUserIdLayerGetFileCountAndNames(pathBuf, fileNames, fileSize, fileCount);
400 }
401 if (ret != CM_SUCCESS) {
402 CM_LOG_E("Get file count and names from path faild ret:%d", ret);
403 return ret;
404 }
405
406 CM_LOG_I("Get app cert list fileCount:%u", *fileCount);
407
408 return CM_SUCCESS;
409 }
410
CherkCertCountBeyondMax(const char * path,const char * fileName)411 static int32_t CherkCertCountBeyondMax(const char *path, const char *fileName)
412 {
413 int32_t ret = CM_FAILURE;
414
415 do {
416 int32_t tempCount = GetCertCount(path);
417 if (tempCount < MAX_COUNT_CERTIFICATE) {
418 ret = CM_SUCCESS;
419 break;
420 }
421
422 char fullFileName[CM_MAX_FILE_NAME_LEN] = {0};
423 if (snprintf_s(fullFileName, CM_MAX_FILE_NAME_LEN, CM_MAX_FILE_NAME_LEN - 1, "%s/%s", path, fileName) < 0) {
424 CM_LOG_E("mkdir full name failed");
425 ret = CM_FAILURE;
426 break;
427 }
428
429 if (access(fullFileName, F_OK) == 0) {
430 ret = CM_SUCCESS;
431 break;
432 }
433 } while (0);
434 return ret;
435 }
436
ConstructCertUri(const struct CmContext * context,const struct CmBlob * certAlias,struct CmBlob * certUri)437 static int32_t ConstructCertUri(const struct CmContext *context, const struct CmBlob *certAlias,
438 struct CmBlob *certUri)
439 {
440 struct CmBlob commonUri = { 0, NULL };
441 int32_t ret;
442 do {
443 ret = CmConstructCommonUri(context, CM_URI_TYPE_CERTIFICATE, certAlias, &commonUri);
444 if (ret != CM_SUCCESS) {
445 CM_LOG_E("construct cert uri get common uri failed");
446 break;
447 }
448
449 if (certUri->size < commonUri.size) {
450 CM_LOG_E("out cert uri size[%u] too small", certUri->size);
451 ret = CMR_ERROR_BUFFER_TOO_SMALL;
452 break;
453 }
454
455 if (memcpy_s(certUri->data, certUri->size, commonUri.data, commonUri.size) != EOK) {
456 CM_LOG_E("copy cert uri failed");
457 ret = CMR_ERROR_INVALID_OPERATION;
458 break;
459 }
460
461 certUri->size = commonUri.size;
462 } while (0);
463
464 CM_FREE_PTR(commonUri.data);
465 return ret;
466 }
467
CmWriteUserCert(const struct CmContext * context,struct CmMutableBlob * pathBlob,const struct CmBlob * userCert,const struct CmBlob * certAlias,struct CmBlob * certUri)468 int32_t CmWriteUserCert(const struct CmContext *context, struct CmMutableBlob *pathBlob,
469 const struct CmBlob *userCert, const struct CmBlob *certAlias, struct CmBlob *certUri)
470 {
471 if (certAlias->size > MAX_LEN_CERT_ALIAS) {
472 CM_LOG_E("alias size is too large");
473 return CMR_ERROR_INVALID_ARGUMENT;
474 }
475
476 int32_t ret;
477 do {
478 ret = ConstructCertUri(context, certAlias, certUri);
479 if (ret != CM_SUCCESS) {
480 CM_LOG_E("get cert uri failed");
481 break;
482 }
483
484 if (certUri->size > MAX_LEN_URI) {
485 CM_LOG_E("uri size is too large");
486 ret = CMR_ERROR_INVALID_ARGUMENT;
487 break;
488 }
489
490 ret = CherkCertCountBeyondMax((char*)pathBlob->data, (char *)certUri->data);
491 if (ret != CM_SUCCESS) {
492 CM_LOG_E("cert count beyond maxcount, can't install");
493 ret = CMR_ERROR_INVALID_ARGUMENT;
494 break;
495 }
496
497 if (CmFileWrite((char*)pathBlob->data, (char *)certUri->data, 0, userCert->data, userCert->size) != CMR_OK) {
498 CM_LOG_E("Failed to write certificate");
499 ret = CMR_ERROR_WRITE_FILE_FAIL;
500 break;
501 }
502 } while (0);
503 return ret;
504 }
505
CmRemoveUserCert(struct CmMutableBlob * pathBlob,const struct CmBlob * certUri)506 int32_t CmRemoveUserCert(struct CmMutableBlob *pathBlob, const struct CmBlob *certUri)
507 {
508 return CertManagerFileRemove((char *)pathBlob->data, (char *)certUri->data);
509 }
510
RemoveAllUserCert(const struct CmContext * context,uint32_t store,const char * path)511 static int32_t RemoveAllUserCert(const struct CmContext *context, uint32_t store, const char* path)
512 {
513 ASSERT_ARGS(path);
514 struct CmMutableBlob fileNames = { 0, NULL };
515 struct CmMutableBlob pathBlob = { strlen(path) + 1, (uint8_t *)path }; /* include '\0' at end. */
516
517 int32_t ret = CertManagerGetFilenames(&fileNames, path);
518 if (ret != CM_SUCCESS) {
519 CM_LOG_E("Failed obtain filenames from path");
520 return ret;
521 }
522
523 struct CmMutableBlob *fNames = (struct CmMutableBlob *)fileNames.data;
524 for (uint32_t i = 0; i < fileNames.size; i++) {
525 ret = CertManagerFileRemove(path, (char *)fNames[i].data);
526 if (ret != CMR_OK) {
527 CM_LOG_E("User Cert %u remove failed, ret: %d", i, ret);
528 continue;
529 }
530 ret = CmSetStatusEnable(context, &pathBlob, (struct CmBlob *)(&fNames[i]), store);
531 if (ret != CM_SUCCESS) {
532 CM_LOG_E("Update StatusFile %u fail, ret = %d", i, ret);
533 continue;
534 }
535 }
536
537 FreeFileNames(fNames, fileNames.size);
538 return ret;
539 }
540
RemoveAllUidDir(const char * path)541 static int32_t RemoveAllUidDir(const char* path)
542 {
543 return CM_ERROR(CmDirRemove(path));
544 }
545
CmRemoveAllUserCert(const struct CmContext * context,uint32_t store,const struct CmMutableBlob * pathList)546 int32_t CmRemoveAllUserCert(const struct CmContext *context, uint32_t store, const struct CmMutableBlob *pathList)
547 {
548 ASSERT_ARGS(pathList && pathList->data && pathList->size);
549 int32_t ret = CM_SUCCESS;
550 struct CmMutableBlob *path = (struct CmMutableBlob *)pathList->data;
551
552 for (uint32_t i = 0; i < pathList->size; i++) {
553 ret = RemoveAllUserCert(context, store, (char *)path[i].data);
554 if (ret != CM_SUCCESS) {
555 CM_LOG_E("Failed remove usercert at %u_th dir", i);
556 continue;
557 }
558 ret = RemoveAllUidDir((char *)path[i].data);
559 if (ret != CM_SUCCESS) {
560 CM_LOG_E("Remove UidPath fail, ret = %d", ret);
561 continue;
562 }
563 }
564 return ret;
565 }
566
567 #ifdef __cplusplus
568 }
569 #endif