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