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