• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2025 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_updateflag.h"
17 
18 #include <dirent.h>
19 #include <libgen.h>
20 #include <openssl/x509.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <string.h>
25 
26 #include "cert_manager.h"
27 #include "cert_manager_file_operator.h"
28 #include "cert_manager_mem.h"
29 #include "cert_manager_service.h"
30 #include "cert_manager_storage.h"
31 #include "cert_manager_uri.h"
32 #include "cm_log.h"
33 #include "cm_x509.h"
34 #include "securec.h"
35 #include "cm_util.h"
36 
37 #ifdef __cplusplus
38 extern "C" {
39 #endif
40 
41 static const char UPDATE_FLAG_DIR_PATH[] = "/data/service/el1/public/cert_manager_service/certificates/user";
42 static const char UPDATE_FLAG_FILE_NAME[] = "update.flag";
43 
44 // LCOV_EXCL_START
45 enum UpdateFlagEnum {
46     NEED_UPDATE = '0',
47     ALREADY_UPDATE = '1',
48 };
49 
50 /**
51  * @brief Get the update flag
52  *
53  * @param[out] updateFlag Used to return the update flag
54  * @return int32_t Get results
55  * @retval 0 Success
56  * @retval <0 Failure
57  */
GetUpdateFlag(uint8_t * updateFlag)58 static int32_t GetUpdateFlag(uint8_t *updateFlag)
59 {
60     uint8_t updateFlagTmp = false;
61 
62     if (updateFlag == NULL) {
63         CM_LOG_E("input params is invalid");
64         return CMR_ERROR_INVALID_ARGUMENT;
65     }
66 
67     /* Read the update flag */
68     uint32_t readSize =
69         CmFileRead(UPDATE_FLAG_DIR_PATH, UPDATE_FLAG_FILE_NAME, 0, &updateFlagTmp, sizeof(updateFlagTmp));
70     if (readSize == 0) {
71         CM_LOG_D("Read updateFlag file failed, the updateFlag counts as false");
72         *updateFlag = false;
73     } else if (readSize == sizeof(updateFlagTmp)) {
74         *updateFlag = updateFlagTmp;
75     } else {
76         CM_LOG_E("Failed read UpdateFlag");
77         return CMR_ERROR_STORAGE;
78     }
79 
80     return CM_SUCCESS;
81 }
82 
83 /**
84  * @brief Set the update flag
85  *
86  * @param[out] updateFlag Set the update flag value
87  * @return int32_t Set result
88  * @retval 0 Success
89  * @retval <0 Failure
90  */
SetUpdateFlag(uint8_t updateFlag)91 static int32_t SetUpdateFlag(uint8_t updateFlag)
92 {
93     /* Create an update flag directory */
94     if (CmMakeDir(UPDATE_FLAG_DIR_PATH) == CMR_ERROR_MAKE_DIR_FAIL) {
95         CM_LOG_E("Failed to create UPDATE_FLAG_DIR_PATH");
96         return CMR_ERROR_MAKE_DIR_FAIL;
97     }
98 
99     /* Writes the update flag */
100     int32_t ret = CmFileWrite(UPDATE_FLAG_DIR_PATH, UPDATE_FLAG_FILE_NAME, 0, &updateFlag, sizeof(updateFlag));
101     if (ret != CMR_OK) {
102         CM_LOG_E("Failed to write updateFlag");
103     }
104     return ret;
105 }
106 
IsCertNeedBackup(uint32_t userId,uint32_t uid,const struct CmBlob * certUri,bool * needUpdate)107 int32_t IsCertNeedBackup(uint32_t userId, uint32_t uid, const struct CmBlob *certUri, bool *needUpdate)
108 {
109     int32_t ret = CM_SUCCESS;
110     char configPath[CERT_MAX_PATH_LEN] = { 0 };
111 
112     if (needUpdate == NULL) {
113         CM_LOG_E("input params is invalid");
114         return CMR_ERROR_INVALID_ARGUMENT;
115     }
116 
117     ret = CmGetCertConfPath(userId, uid, certUri, configPath, CERT_MAX_PATH_LEN);
118     if (ret != CM_SUCCESS) {
119         CM_LOG_E("Construct cert config configPath failed.");
120         return ret;
121     }
122 
123     do {
124         ret = CmIsFileExist(NULL, (const char *)configPath);
125         if (ret != CM_SUCCESS) {
126             if (ret != CMR_ERROR_NOT_EXIST) {
127                 CM_LOG_E("check cert config file return err code: %d.", ret);
128             }
129             /* The cert config file does not exist or cannot be determined, need to
130              * backup cert */
131             *needUpdate = true;
132             break;
133         }
134         uint32_t size = 0;
135         char backupPath[CERT_MAX_PATH_LEN] = { 0 };
136         size = CmFileRead(NULL, configPath, 0, (uint8_t *)backupPath, CERT_MAX_PATH_LEN - 1);
137         if (size == 0) {
138             CM_LOG_E("read cert backup file path from configPath failed.");
139             *needUpdate = true;
140             break;
141         }
142 
143         ret = CmIsFileExist(NULL, (const char *)backupPath);
144         if (ret == CMR_OK) {
145             *needUpdate = false;
146             break;
147         } else if (ret != CMR_ERROR_NOT_EXIST) {
148             CM_LOG_E("check cert backup file return err code: %d.", ret);
149         }
150         *needUpdate = true;
151     } while (0);
152 
153     return CM_SUCCESS;
154 }
155 
CmReadCertData(uint32_t store,const struct CmContext * context,const struct CmBlob * certUri,struct CmBlob * userCertData)156 int32_t CmReadCertData(uint32_t store, const struct CmContext *context, const struct CmBlob *certUri,
157                        struct CmBlob *userCertData)
158 {
159     int32_t ret = CM_SUCCESS;
160     char uriStr[CERT_MAX_PATH_LEN] = { 0 };
161     char uidPath[CERT_MAX_PATH_LEN] = { 0 };
162 
163     /* Construct certificate path */
164     ret = ConstructUidPath(context, store, uidPath, CERT_MAX_PATH_LEN);
165     if (ret != CM_SUCCESS) {
166         return ret;
167     }
168 
169     if (snprintf_s(uriStr, CERT_MAX_PATH_LEN, CERT_MAX_PATH_LEN - 1, "%.*s", certUri->size, certUri->data) < 0) {
170         CM_LOG_E("Construct cert uri string failed.");
171         return CMR_ERROR_MEM_OPERATION_PRINT;
172     }
173 
174     /* Reading certificate data */
175     ret = CmStorageGetBuf(uidPath, uriStr, userCertData);
176     if (ret != CM_SUCCESS) {
177         CM_LOG_E("Failed to get certificate data, ret = %d", ret);
178         return ret;
179     }
180 
181     return CM_SUCCESS;
182 }
183 
ConvertCertDataToPem(const struct CmBlob * userCertData,const X509 * userCertX509,struct CmBlob * userCertPemData,bool * userCertPemDataNeedFree)184 static int32_t ConvertCertDataToPem(const struct CmBlob *userCertData, const X509 *userCertX509,
185     struct CmBlob *userCertPemData, bool *userCertPemDataNeedFree)
186 {
187     if (userCertData->data[0] != '-') {
188         int32_t ret = CmX509ToPEM(userCertX509, userCertPemData);
189         if (ret != CM_SUCCESS) {
190             CM_LOG_E("CmX509ToPEM fail");
191             return ret;
192         }
193         *userCertPemDataNeedFree = true;
194     } else {
195         userCertPemData->data = userCertData->data;
196         userCertPemData->size = userCertData->size;
197         *userCertPemDataNeedFree = false;
198     }
199 
200     return CM_SUCCESS;
201 }
202 
CmConstructContextFromUri(const char * certUri,struct CmContext * context)203 int32_t CmConstructContextFromUri(const char *certUri, struct CmContext *context)
204 {
205     if ((certUri == NULL) || (context == NULL)) {
206         CM_LOG_E("input params is invaild");
207         return CMR_ERROR_INVALID_ARGUMENT;
208     }
209 
210     struct CMUri cmUri = { 0 };
211     int32_t ret = CertManagerUriDecode(&cmUri, certUri);
212     if ((ret != CM_SUCCESS)) {
213         CM_LOG_E("Failed to decode struct CMUri from certUri, ret = %d", ret);
214         return ret;
215     }
216 
217     do {
218         if ((cmUri.user == NULL) || (cmUri.app == NULL) || (cmUri.object == NULL)) {
219             CM_LOG_E("cmUri.user or cmUri.app or cmUri.object is NULL error");
220             ret = CMR_ERROR_INVALID_ARGUMENT_URI;
221             break;
222         }
223 
224         if (CmIsNumeric(cmUri.user, strlen(cmUri.user) + 1, &(context->userId)) != CM_SUCCESS ||
225             CmIsNumeric(cmUri.app, strlen(cmUri.app) + 1, &(context->uid)) != CM_SUCCESS) {
226             CM_LOG_E("parse string to uint32 failed.");
227             ret = CMR_ERROR_INVALID_ARGUMENT_URI;
228             break;
229         }
230 
231         if (snprintf_s(context->packageName, sizeof(context->packageName), sizeof(context->packageName) - 1, "%s",
232             cmUri.object) < 0) {
233             CM_LOG_E("Failed to fill context->packageName");
234             ret = CMR_ERROR_MEM_OPERATION_PRINT;
235             break;
236         }
237     } while (0);
238 
239     (void)CertManagerFreeUri(&cmUri);
240 
241     return ret;
242 }
243 
BackupUserCert(const X509 * userCertX509,const struct CmBlob * userCert,const struct CmContext * context,const struct CmBlob * certUri)244 static int32_t BackupUserCert(const X509 *userCertX509, const struct CmBlob *userCert, const struct CmContext *context,
245                               const struct CmBlob *certUri)
246 {
247     char userCertConfigFilePath[CERT_MAX_PATH_LEN] = { 0 };
248     char userCertBackupFilePath[CERT_MAX_PATH_LEN] = { 0 };
249 
250     int32_t ret = CmGetCertConfPath(context->userId, context->uid, certUri, userCertConfigFilePath, CERT_MAX_PATH_LEN);
251     if (ret != CM_SUCCESS) {
252         CM_LOG_E("CmGetCertConfPath fail");
253         return ret;
254     }
255 
256     ret = CmRemoveBackupUserCert(context, certUri, userCertConfigFilePath);
257     if (ret != CMR_OK) {
258         CM_LOG_E("Remove user cert config and backup file failed, ret: %d", ret);
259     }
260 
261     ret = CmGetCertBackupFilePath(userCertX509, context->userId, userCertBackupFilePath, CERT_MAX_PATH_LEN);
262     if (ret != CM_SUCCESS) {
263         CM_LOG_E("CmGetCertBackupFilePath fail");
264         return ret;
265     }
266     ret = CmGenerateSaConf(userCertConfigFilePath, NULL, userCertBackupFilePath);
267     if (ret != CM_SUCCESS) {
268         CM_LOG_E("GenerateSaConf: save CertBackupFilePath fail");
269         return ret;
270     }
271 
272     ret = CmStoreUserCert(NULL, userCert, userCertBackupFilePath);
273     if (ret != CM_SUCCESS) {
274         CM_LOG_E("StoreUserCert fail");
275         return ret;
276     }
277 
278     return CM_SUCCESS;
279 }
280 
CmBackupUserCert(const struct CmContext * context,const struct CmBlob * certUri,const struct CmBlob * certData)281 int32_t CmBackupUserCert(const struct CmContext *context, const struct CmBlob *certUri, const struct CmBlob *certData)
282 {
283     if ((context == NULL) || (CmCheckBlob(certUri) != CM_SUCCESS) || (CmCheckBlob(certData) != CM_SUCCESS)) {
284         CM_LOG_E("Invalid input arguments");
285         return CMR_ERROR_INVALID_ARGUMENT;
286     }
287 
288     X509 *userCertX509 = InitCertContext(certData->data, certData->size);
289     if (userCertX509 == NULL) {
290         CM_LOG_E("Parse X509 cert fail");
291         return CMR_ERROR_INVALID_CERT_FORMAT;
292     }
293 
294     int32_t ret = CM_SUCCESS;
295     struct CmBlob certPemData = { 0, NULL };
296     bool certPemDataNeedFree = false;
297     do {
298         ret = ConvertCertDataToPem(certData, userCertX509, &certPemData, &certPemDataNeedFree);
299         if (ret != CM_SUCCESS) {
300             CM_LOG_E("ConvertCertDataToPem fail");
301             break;
302         }
303 
304         ret = BackupUserCert(userCertX509, (const struct CmBlob *)&certPemData, context, certUri);
305         if (ret != CM_SUCCESS) {
306             CM_LOG_E("BackupUserCert fail");
307             break;
308         }
309     } while (0);
310 
311     if (certPemDataNeedFree == true)
312         CM_FREE_BLOB(certPemData);
313 
314     FreeCertContext(userCertX509);
315 
316     return ret;
317 }
318 
UpdateUserCert(uint32_t userId,uint32_t uid,const char * certPath)319 static int32_t UpdateUserCert(uint32_t userId, uint32_t uid, const char *certPath)
320 {
321     int32_t ret = CM_SUCCESS;
322     char *uriStr = NULL;
323     struct CmBlob certUri = { 0 };
324 
325     if (certPath == NULL) {
326         CM_LOG_E("input params is invaild");
327         return CMR_ERROR_INVALID_ARGUMENT;
328     }
329     uriStr = basename((char *)certPath);
330     certUri.data = (uint8_t *)uriStr;
331     certUri.size = strlen(uriStr);
332 
333     bool needUpdate = false;
334     ret = IsCertNeedBackup(userId, uid, &certUri, &needUpdate);
335     if (ret != CM_SUCCESS) {
336         CM_LOG_E("Check cert is need update failed, ret = %d", ret);
337         return ret;
338     } else if (needUpdate == false) {
339         /* No need to update */
340         return CM_SUCCESS;
341     }
342 
343     struct CmContext context = { 0 };
344     ret = CmConstructContextFromUri((const char *)uriStr, &context);
345     if (ret != CM_SUCCESS) {
346         CM_LOG_E("ConstructContextFromUri failed, ret = %d", ret);
347         return CM_FAILURE;
348     }
349 
350     uint32_t store = CM_USER_TRUSTED_STORE;
351     struct CmBlob certificateData = { 0, NULL };
352     ret = CmReadCertData(store, &context, &certUri, &certificateData);
353     if (ret != CM_SUCCESS) {
354         CM_LOG_E("CmReadCertData failed, ret = %d", ret);
355         return CM_FAILURE;
356     }
357 
358     ret = CmBackupUserCert(&context, &certUri, &certificateData);
359     if (ret != CM_SUCCESS) {
360         CM_LOG_E("update user certUri failed, ret = %d", ret);
361         ret = CM_FAILURE;
362     }
363 
364     CM_FREE_BLOB(certificateData);
365 
366     return ret;
367 }
368 
UpdateUserCerts(uint32_t userId,const char * userIdPath)369 static int32_t UpdateUserCerts(uint32_t userId, const char *userIdPath)
370 {
371     DIR *dir = opendir(userIdPath);
372     if (dir == NULL) {
373         CM_LOG_E("opendir userIdPath failed");
374         return CM_FAILURE;
375     }
376 
377     struct dirent *dire = NULL;
378     /* Traverse the user/{userId} directory */
379     while ((dire = readdir(dir)) != NULL) {
380         if ((strcmp(dire->d_name, ".") == 0) || (strcmp(dire->d_name, "..") == 0)) {
381             continue;
382         }
383         char uidPath[CERT_MAX_PATH_LEN] = { 0 };
384         if (snprintf_s(uidPath, CERT_MAX_PATH_LEN, CERT_MAX_PATH_LEN - 1, "%s/%s", userIdPath, dire->d_name) < 0) {
385             CM_LOG_E("Construct userId path failed");
386             continue;
387         }
388 
389         int32_t ret = 0;
390         uint32_t fileCounts = 0;
391         struct CmBlob fileNames[MAX_COUNT_CERTIFICATE] = { 0 };
392         /* Gets all files under the uidPath */
393         ret = CmUidLayerGetFileCountAndNames(uidPath, fileNames, MAX_COUNT_CERTIFICATE, &fileCounts);
394         if (ret != CM_SUCCESS) {
395             CM_LOG_E("Get file count and names from path of userId layer failed");
396             continue;
397         }
398 
399         /* Traverse all files under the uidPath */
400         for (uint32_t i = 0; i < fileCounts; i++) {
401             struct CmBlob *certFilePath = &fileNames[i];
402 
403             uint32_t uid = 0;
404             /* Update certificate file */
405             if (CmIsNumeric(dire->d_name, strlen(dire->d_name) + 1, &uid) != CM_SUCCESS) {
406                 CM_LOG_E("parse string to uint32 failed.");
407                 continue;
408             }
409 
410             ret = UpdateUserCert(userId, uid, (const char *)certFilePath->data);
411             if (ret != CM_SUCCESS) {
412                 CM_LOG_E("Failed to update cert file for the certFilePath");
413                 continue;
414             }
415         }
416 
417         CmFreeFileNames(fileNames, fileCounts);
418     };
419 
420     closedir(dir);
421 
422     return CM_SUCCESS;
423 }
424 
UpdateAllUserCerts(void)425 static int32_t UpdateAllUserCerts(void)
426 {
427     DIR *dir = NULL;
428     struct dirent *dire = NULL;
429     uint32_t userId = 0;
430     char userIdPath[CERT_MAX_PATH_LEN] = { 0 };
431 
432     /* do nothing when dir is not exist */
433     if (CmIsDirExist(USER_CA_STORE) != CMR_OK) {
434         CM_LOG_D("Root dir is not exist");
435         return CM_SUCCESS;
436     }
437 
438     if ((dir = opendir(USER_CA_STORE)) == NULL) {
439         CM_LOG_E("open USER_CA_STORE dir failed");
440         return CM_FAILURE;
441     }
442 
443     /* Traverse the user directory */
444     while ((dire = readdir(dir)) != NULL) {
445         if ((dire->d_type != DT_DIR) || (strcmp(dire->d_name, ".") == 0) || (strcmp(dire->d_name, "..") == 0)) {
446             /* If it is not a directory or a special directory, skip it */
447             continue;
448         }
449 
450         if (snprintf_s(userIdPath, CERT_MAX_PATH_LEN, CERT_MAX_PATH_LEN - 1, "%s%s", USER_CA_STORE, dire->d_name) < 0) {
451             CM_LOG_E("Construct userId path failed");
452             continue;
453         }
454 
455         /* Updates all certificates for the specified user */
456         if (CmIsNumeric(dire->d_name, strlen(dire->d_name) + 1, &userId) != CM_SUCCESS) {
457             CM_LOG_E("parse string to uint32 failed.");
458             continue;
459         }
460 
461         int32_t ret = UpdateUserCerts(userId, userIdPath);
462         if (ret != CM_SUCCESS) {
463             CM_LOG_E("Failed to update all certificates for the userIdPath");
464             continue;
465         }
466     };
467 
468     closedir(dir);
469 
470     return CM_SUCCESS;
471 }
472 
CmBackupAllSaUserCerts(void)473 int32_t CmBackupAllSaUserCerts(void)
474 {
475     int32_t ret = 0;
476     uint8_t updateFlag = 0;
477 
478     /* Obtain the update flag */
479     ret = GetUpdateFlag(&updateFlag);
480     if (ret != CM_SUCCESS) {
481         CM_LOG_E("GetUpdateFlag failed");
482         return ret;
483     }
484 
485     if (updateFlag == ALREADY_UPDATE) {
486         CM_LOG_D("updateFlag is ALREADY_UPDATE, so not need update");
487         return CM_SUCCESS;
488     }
489 
490     /* Update all certificate files */
491     ret = UpdateAllUserCerts();
492     if (ret != CM_SUCCESS) {
493         CM_LOG_E("UpdateAllUserCerts failed");
494         return ret;
495     }
496 
497     /* Set the Update flag */
498     ret = SetUpdateFlag(ALREADY_UPDATE);
499     if (ret != CM_SUCCESS) {
500         CM_LOG_E("SetUpdateFlag failed");
501         return ret;
502     }
503 
504     return CM_SUCCESS;
505 }
506 
507 #ifdef __cplusplus
508 }
509 #endif
510 // LCOV_EXCL_STOP