1 /*
2 * Copyright (c) 2022-2024 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_storage.h"
17
18 #include <openssl/x509.h>
19 #include <unistd.h>
20
21 #include "cert_manager_file_operator.h"
22 #include "cert_manager_mem.h"
23 #include "cert_manager_uri.h"
24 #include "cm_log.h"
25 #include "cm_type.h"
26 #include "securec.h"
27
GetRootPath(uint32_t store,char * rootPath,uint32_t pathLen)28 int32_t GetRootPath(uint32_t store, char *rootPath, uint32_t pathLen)
29 {
30 errno_t ret;
31
32 /* keep \0 at end */
33 switch (store) {
34 case CM_CREDENTIAL_STORE:
35 ret = memcpy_s(rootPath, pathLen - 1, CREDNTIAL_STORE, strlen(CREDNTIAL_STORE));
36 break;
37 case CM_SYSTEM_TRUSTED_STORE:
38 ret = memcpy_s(rootPath, pathLen - 1, SYSTEM_CA_STORE, strlen(SYSTEM_CA_STORE));
39 break;
40 case CM_USER_TRUSTED_STORE:
41 ret = memcpy_s(rootPath, pathLen - 1, USER_CA_STORE, strlen(USER_CA_STORE));
42 break;
43 case CM_PRI_CREDENTIAL_STORE:
44 ret = memcpy_s(rootPath, pathLen - 1, PRI_CREDNTIAL_STORE, strlen(PRI_CREDNTIAL_STORE));
45 break;
46 case CM_SYS_CREDENTIAL_STORE:
47 ret = memcpy_s(rootPath, pathLen - 1, SYS_CREDNTIAL_STORE, strlen(SYS_CREDNTIAL_STORE));
48 break;
49 default:
50 return CMR_ERROR_INVALID_ARGUMENT;
51 }
52
53 if (ret != EOK) {
54 CM_LOG_E("copy path failed, store = %u", store);
55 return CMR_ERROR_INVALID_OPERATION;
56 }
57
58 return CM_SUCCESS;
59 }
60
ConstructUserIdPath(const struct CmContext * context,uint32_t store,char * userIdPath,uint32_t pathLen)61 int32_t ConstructUserIdPath(const struct CmContext *context, uint32_t store,
62 char *userIdPath, uint32_t pathLen)
63 {
64 char rootPath[CERT_MAX_PATH_LEN] = { 0 };
65 int32_t ret = GetRootPath(store, rootPath, CERT_MAX_PATH_LEN);
66 if (ret != CM_SUCCESS) {
67 return ret;
68 }
69
70 if (snprintf_s(userIdPath, pathLen, pathLen - 1, "%s%u", rootPath, context->userId) < 0) {
71 CM_LOG_E("construct user id path failed");
72 return CMR_ERROR_INVALID_OPERATION;
73 }
74
75 ret = CmMakeDir(userIdPath);
76 if (ret == CMR_ERROR_MAKE_DIR_FAIL) {
77 CM_LOG_E("mkdir userId path failed");
78 return ret;
79 } /* ret may be CMR_ERROR_ALREADY_EXISTS */
80
81 return CM_SUCCESS;
82 }
83
ConstructUidPath(const struct CmContext * context,uint32_t store,char * uidPath,uint32_t pathLen)84 int32_t ConstructUidPath(const struct CmContext *context, uint32_t store,
85 char *uidPath, uint32_t pathLen)
86 {
87 char userIdPath[CERT_MAX_PATH_LEN] = { 0 };
88 int32_t ret = ConstructUserIdPath(context, store, userIdPath, CERT_MAX_PATH_LEN);
89 if (ret != CM_SUCCESS) {
90 return ret;
91 }
92
93 if (snprintf_s(uidPath, pathLen, pathLen - 1, "%s/%u", userIdPath, context->uid) < 0) {
94 CM_LOG_E("construct uid path failed");
95 return CMR_ERROR_INVALID_OPERATION;
96 }
97
98 ret = CmMakeDir(uidPath);
99 if (ret == CMR_ERROR_MAKE_DIR_FAIL) {
100 CM_LOG_E("mkdir uid path failed");
101 return ret;
102 } /* ret may be CMR_ERROR_ALREADY_EXISTS */
103
104 return CM_SUCCESS;
105 }
106
ConstructAuthListPath(const struct CmContext * context,uint32_t store,char * authListPath,uint32_t pathLen)107 int32_t ConstructAuthListPath(const struct CmContext *context, uint32_t store,
108 char *authListPath, uint32_t pathLen)
109 {
110 char uidPath[CERT_MAX_PATH_LEN] = { 0 };
111 int32_t ret = ConstructUidPath(context, store, uidPath, CERT_MAX_PATH_LEN);
112 if (ret != CM_SUCCESS) {
113 return ret;
114 }
115
116 if (snprintf_s(authListPath, pathLen, pathLen - 1, "%s/%s", uidPath, "authlist") < 0) {
117 CM_LOG_E("construct authlist failed");
118 return CMR_ERROR_INVALID_OPERATION;
119 }
120
121 ret = CmMakeDir(authListPath);
122 if (ret == CMR_ERROR_MAKE_DIR_FAIL) {
123 CM_LOG_E("mkdir auth list path failed");
124 return ret;
125 } /* ret may be CMR_ERROR_ALREADY_EXISTS */
126
127 return CM_SUCCESS;
128 }
129
CmStorageGetBuf(const char * path,const char * fileName,struct CmBlob * storageBuf)130 int32_t CmStorageGetBuf(const char *path, const char *fileName, struct CmBlob *storageBuf)
131 {
132 uint32_t fileSize = CmFileSize(path, fileName);
133 if (fileSize > MAX_OUT_BLOB_SIZE) {
134 CM_LOG_E("file size[%u] invalid", fileSize);
135 return CMR_ERROR_INVALID_OPERATION;
136 }
137
138 if (fileSize == 0) {
139 CM_LOG_E("file is not exist");
140 return CMR_ERROR_NOT_EXIST;
141 }
142
143 uint8_t *data = (uint8_t *)CMMalloc(fileSize);
144 if (data == NULL) {
145 CM_LOG_E("malloc file buffer failed");
146 return CMR_ERROR_MALLOC_FAIL;
147 }
148
149 uint32_t readSize = CmFileRead(path, fileName, 0, data, fileSize);
150 if (readSize == 0) {
151 CM_LOG_E("read file size 0 invalid");
152 CMFree(data);
153 return CMR_ERROR_NOT_EXIST;
154 }
155
156 storageBuf->data = data;
157 storageBuf->size = fileSize;
158 return CM_SUCCESS;
159 }
160
CmStorageGetAppCert(const struct CmContext * context,uint32_t store,const struct CmBlob * keyUri,struct CmBlob * certBlob)161 int32_t CmStorageGetAppCert(const struct CmContext *context, uint32_t store,
162 const struct CmBlob *keyUri, struct CmBlob *certBlob)
163 {
164 uint32_t uid = 0;
165 int32_t ret = CertManagerGetUidFromUri(keyUri, &uid);
166 if (ret != CM_SUCCESS) {
167 return ret;
168 }
169
170 struct CmContext uriContext = { context->userId, uid, { 0 } };
171 char uidPath[CERT_MAX_PATH_LEN] = { 0 };
172 ret = ConstructUidPath(&uriContext, store, uidPath, CERT_MAX_PATH_LEN);
173 if (ret != CM_SUCCESS) {
174 return ret;
175 }
176
177 return CmStorageGetBuf(uidPath, (const char *)keyUri->data, certBlob);
178 }
179
CmGetCertFilePath(const struct CmContext * context,uint32_t store,struct CmMutableBlob * pathBlob)180 int32_t CmGetCertFilePath(const struct CmContext *context, uint32_t store, struct CmMutableBlob *pathBlob)
181 {
182 char pathPtr[CERT_MAX_PATH_LEN] = {0};
183
184 if ((pathBlob == NULL) || (pathBlob->data == NULL)) {
185 CM_LOG_E("Null pointer failure");
186 return CMR_ERROR_NULL_POINTER;
187 }
188
189 int32_t ret = ConstructUidPath(context, store, pathPtr, CERT_MAX_PATH_LEN);
190 if (ret != CM_SUCCESS) {
191 CM_LOG_E("Get file path faild");
192 return CM_FAILURE;
193 }
194
195 char *path = (char *)pathBlob->data;
196 if (sprintf_s(path, CERT_MAX_PATH_LEN, "%s", pathPtr) < 0) {
197 return CM_FAILURE;
198 }
199 pathBlob->size = strlen(path) + 1;
200
201 return CM_SUCCESS;
202 }
203
204 /**
205 * @brief Construct the absolute path to the {confRootDir} directory
206 *
207 * @param[out] confRootDir The buffer that holds the absolute path of the {confRootDir} directory
208 * @param[in] dirLen Maximum length of the confRootDir buffer
209 * @return int32_t result
210 * @retval 0 success
211 * @retval <0 failure
212 */
GetCertConfRootDir(char * confRootDir,uint32_t dirLen)213 static int32_t GetCertConfRootDir(char *confRootDir, uint32_t dirLen)
214 {
215 int32_t ret = CM_SUCCESS;
216 mode_t mode = 0;
217
218 if (confRootDir == NULL) {
219 CM_LOG_E("Input params invalid");
220 return CMR_ERROR_INVALID_ARGUMENT;
221 }
222
223 if (dirLen < sizeof(CERT_BACKUP_CONFIG_ROOT_DIR)) {
224 CM_LOG_E("dirLen(%u) is too small for save user cert backup config file root path", dirLen);
225 return CMR_ERROR_BUFFER_TOO_SMALL;
226 }
227
228 /* Create the root directory for storing user backup config files */
229 mode = S_IRWXU; /* The permission on the user_config directory should be 0700 */
230 ret = CmUserBakupMakeDir(CERT_BACKUP_CONFIG_ROOT_DIR, (const mode_t *)&mode);
231 if (ret != CMR_OK) {
232 CM_LOG_E("Create CERT_BACKUP_CONFIG_ROOT_DIR failed, err code: %d", ret);
233 return CMR_ERROR_MAKE_DIR_FAIL;
234 }
235
236 if (snprintf_s(confRootDir, dirLen, dirLen - 1, "%s", CERT_BACKUP_CONFIG_ROOT_DIR) < 0) {
237 CM_LOG_E("Construct confRootDir failed");
238 return CM_FAILURE;
239 }
240
241 return CM_SUCCESS;
242 }
243
CmGetCertConfUserIdDir(uint32_t userId,char * confUserIdDir,uint32_t dirLen)244 int32_t CmGetCertConfUserIdDir(uint32_t userId, char *confUserIdDir, uint32_t dirLen)
245 {
246 if (confUserIdDir == NULL) {
247 CM_LOG_E("Input params invalid");
248 return CMR_ERROR_INVALID_ARGUMENT;
249 }
250
251 int32_t ret = CM_SUCCESS;
252 char rootPath[CERT_MAX_PATH_LEN] = { 0 };
253 ret = GetCertConfRootDir(rootPath, CERT_MAX_PATH_LEN);
254 if (ret != CM_SUCCESS) {
255 CM_LOG_E("Get user cert root path failed");
256 return CM_FAILURE;
257 }
258
259 char pathTmp[CERT_MAX_PATH_LEN] = { 0 };
260 /* Concatenate the {confRootDir}/{userid} directory */
261 if (snprintf_s(pathTmp, CERT_MAX_PATH_LEN, CERT_MAX_PATH_LEN - 1, "%s/%u", rootPath, userId) < 0) {
262 CM_LOG_E("Construct userIdPath failed, rootPath: %s, userId: %u", rootPath, userId);
263 return CM_FAILURE;
264 }
265 /* Create the {confRootDir}/{userid} directory */
266 ret = CmUserBakupMakeDir(pathTmp, NULL);
267 if (ret != CMR_OK) {
268 CM_LOG_E("Create userIdPath failed, err code: %d", ret);
269 return CMR_ERROR_MAKE_DIR_FAIL;
270 }
271
272 if (snprintf_s(confUserIdDir, dirLen, dirLen - 1, "%s", pathTmp) < 0) {
273 CM_LOG_E("Failed to construct confUserIdDir");
274 return CM_FAILURE;
275 }
276
277 return CM_SUCCESS;
278 }
279
CmGetCertConfUidDir(uint32_t userId,uint32_t uid,char * certConfUidDir,uint32_t dirLen)280 int32_t CmGetCertConfUidDir(uint32_t userId, uint32_t uid, char *certConfUidDir, uint32_t dirLen)
281 {
282 if (certConfUidDir == NULL) {
283 CM_LOG_E("Input params invalid");
284 return CMR_ERROR_INVALID_ARGUMENT;
285 }
286
287 int32_t ret = CM_SUCCESS;
288 char confUserIdDir[CERT_MAX_PATH_LEN] = { 0 };
289 ret = CmGetCertConfUserIdDir(userId, confUserIdDir, CERT_MAX_PATH_LEN);
290 if (ret != CM_SUCCESS) {
291 CM_LOG_E("Construct confUserIdDir(userId: %u) failed", userId);
292 return CM_FAILURE;
293 }
294
295 char pathTmp[CERT_MAX_PATH_LEN] = { 0 };
296 /* Concatenate the {confRootDir}/{userid}/{uid} directory */
297 if (snprintf_s(pathTmp, CERT_MAX_PATH_LEN, CERT_MAX_PATH_LEN - 1, "%s/%u", confUserIdDir, uid) < 0) {
298 CM_LOG_E("Construct uidPath failed, uid: %u", uid);
299 return CM_FAILURE;
300 }
301 /* Create the {confRootDir}/{userid}/{uid} directory */
302 ret = CmUserBakupMakeDir(pathTmp, NULL);
303 if (ret != CMR_OK) {
304 CM_LOG_E("Create uidPath failed, err code: %d", ret);
305 return CMR_ERROR_MAKE_DIR_FAIL;
306 }
307
308 if (snprintf_s(certConfUidDir, dirLen, dirLen - 1, "%s", pathTmp) < 0) {
309 CM_LOG_E("Failed to construct certConfUidDir");
310 return CM_FAILURE;
311 }
312
313 return CM_SUCCESS;
314 }
315
CmGetCertConfPath(uint32_t userId,uint32_t uid,const struct CmBlob * certUri,char * confFilePath,uint32_t confFilePathLen)316 int32_t CmGetCertConfPath(uint32_t userId, uint32_t uid, const struct CmBlob *certUri, char *confFilePath,
317 uint32_t confFilePathLen)
318 {
319 if ((CmCheckBlob(certUri) != CM_SUCCESS) || (confFilePath == NULL) || (confFilePathLen == 0)) {
320 CM_LOG_E("input params is invaild");
321 return CMR_ERROR_INVALID_ARGUMENT;
322 }
323
324 int32_t ret = CM_SUCCESS;
325 char certConfUidDir[CERT_MAX_PATH_LEN] = { 0 };
326 ret = CmGetCertConfUidDir(userId, uid, certConfUidDir, CERT_MAX_PATH_LEN);
327 if (ret != CM_SUCCESS) {
328 CM_LOG_E("Get user cert root path failed");
329 return CM_FAILURE;
330 }
331
332 if (snprintf_s(confFilePath, confFilePathLen, confFilePathLen - 1, "%s/%.*s%s", certConfUidDir, certUri->size,
333 certUri->data, CERT_CONFIG_FILE_SUFFIX) < 0) {
334 CM_LOG_E("Failed to construct user cert config file path");
335 return CM_FAILURE;
336 }
337 return CM_SUCCESS;
338 }
339
340 /**
341 * @brief Get the user certificate backup file root directory
342 *
343 * @param[out] certBackupRootDir Save the buffer of the user certificate backup file root directory
344 * @param[in] dirLen Maximum length of the certBackupRootDir buffer
345 * @return int32_t result
346 * @retval 0 success
347 * @retval <0 failure
348 */
GetCertBackupRootDir(char * certBackupRootDir,uint32_t dirLen)349 static int32_t GetCertBackupRootDir(char *certBackupRootDir, uint32_t dirLen)
350 {
351 if (certBackupRootDir == NULL) {
352 CM_LOG_E("Input params invalid");
353 return CMR_ERROR_INVALID_ARGUMENT;
354 }
355
356 if (dirLen < sizeof(CERT_BACKUP_ROOT_DIR)) {
357 CM_LOG_E("dirLen(%u) is too small for save user cert backup root path", dirLen);
358 return CMR_ERROR_BUFFER_TOO_SMALL;
359 }
360
361 int32_t ret = CM_SUCCESS;
362 mode_t mode = 0;
363 /* Create the root directory for storing user backup files */
364 mode = S_IRWXU | S_IXOTH; /* The permission on the user_open directory should be 0701 */
365 ret = CmUserBakupMakeDir(CERT_BACKUP_ROOT_DIR, (const mode_t *)&mode);
366 if (ret != CMR_OK) {
367 CM_LOG_E("Create CERT_BACKUP_ROOT_DIR failed, err code: %d", ret);
368 return CMR_ERROR_MAKE_DIR_FAIL;
369 }
370
371 if (snprintf_s(certBackupRootDir, dirLen, dirLen - 1, "%s", CERT_BACKUP_ROOT_DIR) < 0) {
372 CM_LOG_E("Construct certBackupRootDir failed");
373 return CM_FAILURE;
374 }
375
376 return CM_SUCCESS;
377 }
378
CmGetCertBackupDir(uint32_t userId,char * certBackupDir,uint32_t certBackupDirLen)379 int32_t CmGetCertBackupDir(uint32_t userId, char *certBackupDir, uint32_t certBackupDirLen)
380 {
381 int32_t ret = CM_SUCCESS;
382 char rootPath[CERT_MAX_PATH_LEN] = { 0 };
383
384 ret = GetCertBackupRootDir(rootPath, CERT_MAX_PATH_LEN);
385 if (ret != CM_SUCCESS) {
386 CM_LOG_E("Get user cert root path failed");
387 return ret;
388 }
389
390 char userIdPath[CERT_MAX_PATH_LEN] = { 0 };
391 /* Concatenate the {userId} directory for the certificate backup */
392 if (snprintf_s(userIdPath, CERT_MAX_PATH_LEN, CERT_MAX_PATH_LEN - 1, "%s/%u", rootPath, userId) < 0) {
393 CM_LOG_E("Construct userIdPath failed");
394 return CMR_ERROR_INVALID_OPERATION;
395 }
396 /* Create the {userId} directory for the certificate backup */
397 ret = CmUserBakupMakeDir(userIdPath, NULL);
398 if (ret != CMR_OK) {
399 CM_LOG_E("Create userIdPath failed, err code: %d", ret);
400 return CMR_ERROR_MAKE_DIR_FAIL;
401 }
402
403 if (snprintf_s(certBackupDir, certBackupDirLen, certBackupDirLen - 1, "%s", userIdPath) < 0) {
404 CM_LOG_E("Construct certBackupDir failed");
405 return CMR_ERROR_INVALID_OPERATION;
406 }
407 return CM_SUCCESS;
408 }
409
410 /**
411 * @brief Get the minimum serial number of the backup file available for the user CA certificate
412 *
413 * @param[in] certSubjectNameHash hash value of a CA certificate SubjectName
414 * @return int Get the minimum serial number or error code
415 * @retval >=0 Get the minimum serial number
416 * @retval <0 Error code
417 */
CmGetCertMinSeqNum(uint32_t userId,unsigned long certSubjectNameHash)418 static int32_t CmGetCertMinSeqNum(uint32_t userId, unsigned long certSubjectNameHash)
419 {
420 int32_t ret = CM_SUCCESS;
421 char certBackupDir[CERT_MAX_PATH_LEN] = { 0 };
422
423 ret = CmGetCertBackupDir(userId, certBackupDir, CERT_MAX_PATH_LEN);
424 if (ret != CM_SUCCESS) {
425 CM_LOG_E("Construct userCertBackupDirPath failed");
426 return ret;
427 }
428
429 int32_t sequenceNumber = CM_FAILURE;
430 char backupFileSearchPath[CERT_MAX_PATH_LEN] = { 0 };
431 for (int32_t seq = 0; seq < MAX_COUNT_CERTIFICATE; seq++) {
432 if (snprintf_s(backupFileSearchPath, CERT_MAX_PATH_LEN, CERT_MAX_PATH_LEN - 1,
433 "%s/" CERT_BACKUP_FILENAME_FORMAT, certBackupDir, certSubjectNameHash, seq) < 0) {
434 CM_LOG_E("Call snprintf_s return failed");
435 return CM_FAILURE;
436 }
437
438 if (access(backupFileSearchPath, F_OK) == 0) {
439 CM_LOG_D("backupFileSearchPath is exist");
440 continue;
441 } else {
442 CM_LOG_D("backupFileSearchPath is not exist");
443 sequenceNumber = seq;
444 break;
445 }
446 }
447
448 CM_LOG_D("Get sequenceNumber(%d)", sequenceNumber);
449 return sequenceNumber;
450 }
451
CmGetCertBackupFileName(const X509 * userCertX509,uint32_t userId,char * certBackupFileName,uint32_t certBackupFileNameLen)452 int32_t CmGetCertBackupFileName(const X509 *userCertX509, uint32_t userId, char *certBackupFileName,
453 uint32_t certBackupFileNameLen)
454 {
455 if (userCertX509 == NULL || certBackupFileName == NULL) {
456 CM_LOG_E("Input params invalid");
457 return CMR_ERROR_INVALID_ARGUMENT;
458 }
459
460 int sequenceNumber = 0;
461 unsigned long certSubjectNameHash = 0;
462
463 /* Calculate the hash value of CA certificate subject_name */
464 certSubjectNameHash = X509_NAME_hash(X509_get_subject_name(userCertX509));
465
466 sequenceNumber = CmGetCertMinSeqNum(userId, certSubjectNameHash);
467 if (sequenceNumber < 0) {
468 CM_LOG_E("Get User Cert Min Useable SequenceNumber failed");
469 return CM_FAILURE;
470 }
471
472 if (snprintf_s(certBackupFileName, certBackupFileNameLen, certBackupFileNameLen - 1, CERT_BACKUP_FILENAME_FORMAT,
473 certSubjectNameHash, sequenceNumber) < 0) {
474 CM_LOG_E("Call snprintf_s return failed");
475 return CMR_ERROR_INVALID_OPERATION;
476 }
477 return CM_SUCCESS;
478 }
479
CmGetCertBackupFilePath(const X509 * userCertX509,uint32_t userId,char * backupFilePath,uint32_t backupFilePathLen)480 int32_t CmGetCertBackupFilePath(const X509 *userCertX509, uint32_t userId, char *backupFilePath,
481 uint32_t backupFilePathLen)
482 {
483 if (userCertX509 == NULL || backupFilePath == NULL) {
484 CM_LOG_E("Input params invalid");
485 return CMR_ERROR_INVALID_ARGUMENT;
486 }
487
488 int32_t ret = CM_SUCCESS;
489 char certBackupDir[CERT_MAX_PATH_LEN] = { 0 };
490 ret = CmGetCertBackupDir(userId, certBackupDir, CERT_MAX_PATH_LEN);
491 if (ret != CM_SUCCESS) {
492 CM_LOG_E("Construct userCertBackupDirPath failed");
493 return ret;
494 }
495
496 char certBackupFileName[CERT_MAX_PATH_LEN] = { 0 };
497 ret = CmGetCertBackupFileName(userCertX509, userId, certBackupFileName, CERT_MAX_PATH_LEN);
498 if (ret != CM_SUCCESS) {
499 CM_LOG_E("Get certBackupFileName failed");
500 return ret;
501 }
502
503 if (snprintf_s(backupFilePath, backupFilePathLen, backupFilePathLen - 1, "%s/%s", certBackupDir,
504 certBackupFileName) < 0) {
505 CM_LOG_E("Call snprintf_s return failed");
506 ret = CMR_ERROR_INVALID_OPERATION;
507 }
508 return ret;
509 }
510