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