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