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