1 /*
2  * Copyright (c) 2022 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_query.h"
17 
18 #include "securec.h"
19 #include "cm_cert_property_rdb.h"
20 #include "cm_log.h"
21 #include "cm_type.h"
22 #include "cm_x509.h"
23 #include "cert_manager_file.h"
24 #include "cert_manager_mem.h"
25 #include "cert_manager_uri.h"
26 #include "cert_manager_storage.h"
27 #include "cert_manager_status.h"
28 #include "cert_manager_file_operator.h"
29 
30 #define MAX_PATH_LEN                  256
31 
MallocCertPath(struct CmMutableBlob * cPath,const char * path)32 static int32_t MallocCertPath(struct CmMutableBlob *cPath, const char *path)
33 {
34     uint32_t pathSize = strlen(path) + 1;
35     cPath->data = (uint8_t *)CMMalloc(pathSize);
36     if (cPath->data == NULL) {
37         CM_LOG_E("malloc cPathLists failed");
38         return CMR_ERROR_MALLOC_FAIL;
39     }
40     cPath->size = pathSize;
41     (void)memset_s(cPath->data, pathSize, 0, pathSize);
42     return CM_SUCCESS;
43 }
44 
CmFreePathList(struct CmMutableBlob * pList,uint32_t pathCount)45 void CmFreePathList(struct CmMutableBlob *pList, uint32_t pathCount)
46 {
47     if (pList == NULL) {
48         return;
49     }
50 
51     for (uint32_t i = 0; i < pathCount; i++) {
52         pList[i].size = 0;
53         CM_FREE_PTR(pList[i].data);
54     }
55     CM_FREE_PTR(pList);
56 }
57 
ConstrutPathList(const char * useridPath,struct CmMutableBlob * cPathList,uint32_t dirCount)58 static int32_t ConstrutPathList(const char *useridPath, struct CmMutableBlob *cPathList, uint32_t dirCount)
59 {
60     int32_t ret = CM_SUCCESS;
61     void *d = CmOpenDir(useridPath);
62     if (d == NULL) {
63         CM_LOG_E("Failed to open directory");
64         return CM_FAILURE;
65     }
66 
67     uint32_t i = 0;
68     struct CmFileDirentInfo dire = {0};
69     while (CmGetSubDir(d, &dire) == CMR_OK) {
70         if (i >= dirCount) {
71             CM_LOG_E("uid dir count beyond dirCount");
72             break;
73         }
74 
75         char pathBuf[MAX_PATH_LEN] = {0};
76         if (sprintf_s(pathBuf, MAX_PATH_LEN, "%s/%s", useridPath, dire.fileName) < 0) {
77             CM_LOG_E("copy uid path failed");
78             ret = CM_FAILURE;
79             break;
80         }
81 
82         ret = MallocCertPath(&cPathList[i], pathBuf); /* uniformly free memory by caller */
83         if (ret != CM_SUCCESS) {
84             break;
85         }
86 
87         if (sprintf_s((char *)cPathList[i].data, cPathList[i].size, "%s", pathBuf) < 0) {
88             ret = CM_FAILURE;
89             break;
90         }
91         i++;
92     }
93 
94     (void) CmCloseDir(d);
95     if (i != dirCount) { /* real dir count less than dirCount */
96         ret = CM_FAILURE;
97     }
98     return ret;
99 }
100 
CreateCertPathList(const char * useridPath,struct CmMutableBlob * pathList)101 static int32_t CreateCertPathList(const char *useridPath, struct CmMutableBlob *pathList)
102 {
103     int32_t uidCount = GetNumberOfDirs(useridPath);
104     if (uidCount < 0) {
105         CM_LOG_E("Failed to obtain number of uid from path");
106         return CM_FAILURE;
107     }
108 
109     if (uidCount == 0) {
110         return CM_SUCCESS;
111     }
112 
113     if (uidCount > MAX_COUNT_CERTIFICATE) {
114         CM_LOG_E("uidCount beyond max");
115         return CM_FAILURE;
116     }
117 
118     uint32_t arraySize = sizeof(struct CmMutableBlob) * (uint32_t)uidCount;
119     struct CmMutableBlob *cPathList = (struct CmMutableBlob *)CMMalloc(arraySize);
120     if (cPathList == NULL) {
121         CM_LOG_E("malloc cPathList failed");
122         return CMR_ERROR_MALLOC_FAIL;
123     }
124     (void)memset_s(cPathList, arraySize, 0, arraySize);
125 
126     int32_t ret = ConstrutPathList(useridPath, cPathList, (uint32_t)uidCount);
127     if (ret != CM_SUCCESS) {
128         CM_LOG_E("construct cPathList failed");
129         CmFreePathList(cPathList, uidCount);
130         return ret;
131     }
132 
133     pathList->data = (uint8_t *)cPathList;
134     pathList->size = (uint32_t)uidCount;
135 
136     return CM_SUCCESS;
137 }
138 
CmGetCertPathList(const struct CmContext * context,uint32_t store,struct CmMutableBlob * pathList)139 int32_t CmGetCertPathList(const struct CmContext *context, uint32_t store, struct CmMutableBlob *pathList)
140 {
141     char userIdPath[MAX_PATH_LEN] = {0};
142 
143     int32_t ret = ConstructUserIdPath(context, store, userIdPath, MAX_PATH_LEN);
144     if (ret != CM_SUCCESS) {
145         CM_LOG_E("Failed obtain userpath for store %u", store);
146         return ret;
147     }
148 
149     ret = CreateCertPathList(userIdPath, pathList);
150     if (ret != CM_SUCCESS) {
151         CM_LOG_E("Failed create pathList for userid %u", context->userId);
152         return ret;
153     }
154 
155     return CM_SUCCESS;
156 }
157 
CmGetSysCertPathList(const struct CmContext * context,struct CmMutableBlob * pathList)158 int32_t CmGetSysCertPathList(const struct CmContext *context, struct CmMutableBlob *pathList)
159 {
160     uint32_t sysPathCnt = 1; /* system root ca path only have one layer */
161     uint32_t listSize = sizeof(struct CmMutableBlob) * sysPathCnt;
162     struct CmMutableBlob *cPathList = (struct CmMutableBlob *)CMMalloc(listSize);
163     if (cPathList == NULL) {
164         CM_LOG_E("malloc cPathList failed");
165         return CMR_ERROR_MALLOC_FAIL;
166     }
167     (void)memset_s(cPathList, listSize, 0, listSize);
168 
169     int32_t ret = MallocCertPath(&cPathList[0], SYSTEM_CA_STORE);
170     if (ret != CM_SUCCESS) {
171         CM_LOG_E("malloc cPathList[0] failed");
172         CmFreePathList(cPathList, sysPathCnt);
173         return ret;
174     }
175 
176     if (sprintf_s((char *)cPathList[0].data, cPathList[0].size, "%s", SYSTEM_CA_STORE) < 0) {
177         CM_LOG_E("sprintf_s path failed");
178         CmFreePathList(cPathList, sysPathCnt);
179         return CMR_ERROR_INVALID_OPERATION;
180     }
181 
182     pathList->data = (uint8_t *)cPathList;
183     pathList->size = sysPathCnt;
184 
185     return CM_SUCCESS;
186 }
187 
CmFreeCertFiles(struct CertFileInfo * cFileList,uint32_t certCount)188 void CmFreeCertFiles(struct CertFileInfo *cFileList, uint32_t certCount)
189 {
190     if (cFileList == NULL) {
191         return;
192     }
193 
194     for (uint32_t i = 0; i < certCount; i++) {
195         cFileList[i].path.size = 0;
196         CM_FREE_PTR(cFileList[i].path.data);
197 
198         cFileList[i].fileName.size = 0;
199         CM_FREE_PTR(cFileList[i].fileName.data);
200     }
201     CMFree(cFileList);
202 }
203 
MallocCertNameAndPath(struct CertFileInfo * certFile,const char * path,const char * fName)204 static int32_t MallocCertNameAndPath(struct CertFileInfo *certFile, const char *path,
205     const char *fName)
206 {
207     uint32_t pathSize = strlen(path) + 1;
208     certFile->path.data = (uint8_t *)CMMalloc(pathSize);
209     if (certFile->path.data == NULL) {
210         CM_LOG_E("malloc path data failed");
211         return CMR_ERROR_MALLOC_FAIL;
212     }
213     certFile->path.size = pathSize;
214     (void)memset_s(certFile->path.data, pathSize, 0, pathSize);
215 
216     uint32_t nameSize = strlen(fName) + 1;
217     certFile->fileName.data = (uint8_t *)CMMalloc(nameSize);
218     if (certFile->fileName.data  == NULL) {
219         CM_LOG_E("malloc filename data failed");
220         return CMR_ERROR_MALLOC_FAIL;
221     }
222     certFile->fileName.size = nameSize;
223     (void)memset_s(certFile->fileName.data, nameSize, 0, nameSize);
224 
225     return CM_SUCCESS;
226 }
227 
GetCertNameAndPath(struct CertFileInfo * certFile,const char * path,const char * fileName)228 static int32_t GetCertNameAndPath(struct CertFileInfo *certFile, const char *path, const char *fileName)
229 {
230     int32_t ret = MallocCertNameAndPath(certFile, path, fileName); /* uniformly free memory by caller */
231     if (ret != CM_SUCCESS) {
232         CM_LOG_E("malloc certfile for cert failed");
233         return ret;
234     }
235 
236     if (sprintf_s((char *)certFile->path.data, certFile->path.size, "%s", path) < 0) {
237         CM_LOG_E("copy path failed");
238         return CM_FAILURE;
239     }
240 
241     if (sprintf_s((char *)certFile->fileName.data, certFile->fileName.size, "%s", fileName) < 0) {
242         CM_LOG_E("copy file name failed");
243         return CM_FAILURE;
244     }
245 
246     return ret;
247 }
248 
CreateCertFile(struct CertFileInfo * cFileList,const char * path,uint32_t * certCount)249 static int32_t CreateCertFile(struct CertFileInfo *cFileList, const char *path, uint32_t *certCount)
250 {
251     if (path == NULL) {
252         CM_LOG_E("invaild path");
253         return CMR_ERROR_INVALID_ARGUMENT;
254     }
255 
256     int32_t fileNums = GetCertCount(path);
257     if (fileNums == 0) {
258         CM_LOG_D("no cert file in path");
259         return CM_SUCCESS;
260     }
261 
262     if (fileNums < 0) {
263         CM_LOG_E("Failed to obtain number of files");
264         return CM_FAILURE;
265     }
266 
267     void *d = CmOpenDir(path);
268     if (d == NULL) {
269         CM_LOG_E("Failed to open directory");
270         return CM_FAILURE;
271     }
272 
273     int32_t ret;
274     uint32_t i = *certCount;
275     struct CmFileDirentInfo dire = {0};
276     while (CmGetDirFile(d, &dire) == CMR_OK) {
277         if (i >= MAX_COUNT_CERTIFICATE) {
278             CM_LOG_E("cert count beyond MAX");
279             break;
280         }
281 
282         ret = GetCertNameAndPath(&cFileList[i], path, dire.fileName);
283         if (ret != CM_SUCCESS) {
284             CM_LOG_E("malloc certfile for cert failed");
285             break;
286         }
287 
288         i++;
289     }
290 
291     (void) CmCloseDir(d);
292     uint32_t realCount = i - *certCount;
293     *certCount += realCount;
294     if (realCount != (uint32_t)fileNums) {
295         return CM_FAILURE;
296     }
297     return ret;
298 }
299 
CreateCertFileList(const struct CmMutableBlob * pathList,struct CmMutableBlob * certFileList)300 int32_t CreateCertFileList(const struct CmMutableBlob *pathList, struct CmMutableBlob *certFileList)
301 {
302     if (pathList->size == 0) {
303         return CM_SUCCESS;
304     }
305 
306     uint32_t arraySize = sizeof(struct CertFileInfo) * MAX_COUNT_CERTIFICATE;
307     struct CertFileInfo *cFileList = (struct CertFileInfo *)CMMalloc(arraySize);
308     if (cFileList == NULL) {
309         CM_LOG_E("malloc cFileList failed");
310         return CMR_ERROR_MALLOC_FAIL;
311     }
312     (void)memset_s(cFileList, arraySize, 0, arraySize);
313 
314     int32_t ret = CM_SUCCESS;
315     uint32_t certCount = 0;
316     struct CmMutableBlob *uidPath = (struct CmMutableBlob *)pathList->data;
317 
318     for (uint32_t i = 0; i < pathList->size; i++) {
319         ret = CreateCertFile(cFileList, (char *)uidPath[i].data, &certCount);
320         if (ret != CM_SUCCESS) {
321             CM_LOG_E("Create CertFile fail of %u_th", i);
322             CmFreeCertFiles(cFileList, certCount);
323             return ret;
324         }
325     }
326     certFileList->data = (uint8_t *)cFileList;
327     certFileList->size = certCount;
328     return ret;
329 }
330 
CmMallocCertBlob(struct CertBlob * certBlob,uint32_t certCount)331 static int32_t CmMallocCertBlob(struct CertBlob *certBlob, uint32_t certCount)
332 {
333     if (certBlob == NULL) {
334         return CMR_ERROR_NULL_POINTER;
335     }
336 
337     for (uint32_t i = 0; i < certCount; i++) {
338         certBlob->uri[i].size = MAX_LEN_URI;
339         certBlob->uri[i].data = (uint8_t *)CMMalloc(MAX_LEN_URI);
340         if (certBlob->uri[i].data == NULL) {
341             return CMR_ERROR_MALLOC_FAIL;
342         }
343         (void)memset_s(certBlob->uri[i].data, MAX_LEN_URI, 0, MAX_LEN_URI);
344 
345         certBlob->subjectName[i].size = MAX_LEN_SUBJECT_NAME;
346         certBlob->subjectName[i].data = (uint8_t *)CMMalloc(MAX_LEN_SUBJECT_NAME);
347         if (certBlob->subjectName[i].data == NULL) {
348             return CMR_ERROR_MALLOC_FAIL;
349         }
350         (void)memset_s(certBlob->subjectName[i].data, MAX_LEN_SUBJECT_NAME, 0, MAX_LEN_SUBJECT_NAME);
351 
352         certBlob->certAlias[i].size = MAX_LEN_CERT_ALIAS;
353         certBlob->certAlias[i].data = (uint8_t *)CMMalloc(MAX_LEN_CERT_ALIAS);
354         if (certBlob->certAlias[i].data == NULL) {
355             return CMR_ERROR_MALLOC_FAIL;
356         }
357         (void)memset_s(certBlob->certAlias[i].data, MAX_LEN_CERT_ALIAS, 0, MAX_LEN_CERT_ALIAS);
358     }
359     return CM_SUCCESS;
360 }
361 
GetUserCertAlias(const char * uri,struct CmBlob * alias)362 static int32_t GetUserCertAlias(const char *uri, struct CmBlob *alias)
363 {
364     int32_t ret = CM_SUCCESS;
365     struct CMUri certUri;
366     (void)memset_s(&certUri, sizeof(certUri), 0, sizeof(certUri));
367 
368     ret = CertManagerUriDecode(&certUri, uri);
369     if (ret != CM_SUCCESS) {
370         CM_LOG_E("uri decode failed, ret = %d", ret);
371         return ret;
372     }
373     if (certUri.object == NULL) {
374         CM_LOG_E("uri's object is invalid after decode");
375         (void)CertManagerFreeUri(&certUri);
376         return CMR_ERROR_INVALID_ARGUMENT;
377     }
378 
379     struct CertProperty certProperty;
380     (void)memset_s(&certProperty, sizeof(struct CertProperty), 0, sizeof(struct CertProperty));
381     ret = QueryCertProperty(uri, &certProperty);
382     if (ret != CM_SUCCESS) {
383         CM_LOG_E("Failed to QueryCertProperty, ret: %d", ret);
384         (void)CertManagerFreeUri(&certUri);
385         return ret;
386     }
387 
388     uint32_t size = strlen(certProperty.alias) + 1;
389     if (size <= 1) {
390         size = strlen(certUri.object) + 1;
391         if (memcpy_s(alias->data, size, certUri.object, size) != EOK) {
392             (void)CertManagerFreeUri(&certUri);
393             return CM_FAILURE;
394         }
395     } else {
396         if (memcpy_s(alias->data, size, (uint8_t *)certProperty.alias, size) != EOK) {
397             (void)CertManagerFreeUri(&certUri);
398             return CM_FAILURE;
399         }
400     }
401     alias->size = size;
402     (void)CertManagerFreeUri(&certUri);
403     return ret;
404 }
405 
GetSysCertAlias(const struct CmBlob * certData,struct CmBlob * alias)406 static int32_t GetSysCertAlias(const struct CmBlob *certData, struct CmBlob *alias)
407 {
408     X509 *cert = InitCertContext(certData->data, certData->size);
409     if (cert == NULL) {
410         CM_LOG_E("cert data can't convert x509 format");
411         return CM_FAILURE;
412     }
413 
414     int32_t aliasLen = GetX509SubjectName(cert, CM_ORGANIZATION_NAME, (char *)alias->data, alias->size);
415     if (aliasLen <= 0) {
416         aliasLen = GetX509SubjectName(cert, CM_COMMON_NAME, (char *)alias->data, alias->size);
417         if (aliasLen <= 0) {
418             CM_LOG_E("Failed to get certificates CN name");
419             FreeCertContext(cert);
420             return CM_FAILURE;
421         }
422     }
423     alias->size = (uint32_t)aliasLen + 1;
424 
425     FreeCertContext(cert);
426     return CM_SUCCESS;
427 }
428 
CmGetCertAlias(const uint32_t store,const char * uri,const struct CmBlob * certData,struct CmBlob * alias)429 int32_t CmGetCertAlias(const uint32_t store, const char *uri, const struct CmBlob *certData, struct CmBlob *alias)
430 {
431     int32_t ret;
432 
433     if (store == CM_USER_TRUSTED_STORE) {
434         ret = GetUserCertAlias(uri, alias);
435     } else if (store == CM_SYSTEM_TRUSTED_STORE) {
436         ret = GetSysCertAlias(certData, alias);
437     } else {
438         CM_LOG_E("Invalid store");
439         return CM_FAILURE;
440     }
441 
442     if (ret != CM_SUCCESS) {
443         CM_LOG_E("Failed to get cert certAlias");
444         return ret;
445     }
446 
447     return CM_SUCCESS;
448 }
449 
CmGetCertSubjectName(const struct CmBlob * certData,struct CmBlob * subjectName)450 static int32_t CmGetCertSubjectName(const struct CmBlob *certData, struct CmBlob *subjectName)
451 {
452     X509 *cert = InitCertContext(certData->data, certData->size);
453     if (cert == NULL) {
454         CM_LOG_E("cert data can't convert x509 format");
455         return CM_FAILURE;
456     }
457 
458     int32_t subjectLen = GetX509SubjectNameLongFormat(cert, (char *)subjectName->data, MAX_LEN_SUBJECT_NAME);
459     if (subjectLen <= 0) {
460         CM_LOG_E("get cert subjectName failed");
461         FreeCertContext(cert);
462         return CM_FAILURE;
463     }
464     subjectName->size = (uint32_t)subjectLen + 1;
465 
466     FreeCertContext(cert);
467     return CM_SUCCESS;
468 }
469 
CmGetCertListInfo(const struct CmContext * context,uint32_t store,const struct CmMutableBlob * certFileList,struct CertBlob * certBlob,uint32_t * status)470 int32_t CmGetCertListInfo(const struct CmContext *context, uint32_t store,
471     const struct CmMutableBlob *certFileList, struct CertBlob *certBlob, uint32_t *status)
472 {
473     int32_t ret = CM_SUCCESS;
474     struct CertFileInfo *cFileList = (struct CertFileInfo *)certFileList->data;
475 
476     ret = CmMallocCertBlob(certBlob, certFileList->size);
477     if (ret != CM_SUCCESS) {
478         CM_LOG_E("malloc certBlob failed");
479         return ret;
480     }
481 
482     for (uint32_t i = 0; i < certFileList->size; i++) {
483         ret = CmGetCertStatus(context, &cFileList[i], store, &status[i]); /* status */
484         if (ret != CM_SUCCESS) {
485             CM_LOG_E("Failed to get cert status");
486             return CM_FAILURE;
487         }
488 
489         if (memcpy_s(certBlob->uri[i].data, MAX_LEN_URI, cFileList[i].fileName.data,
490             cFileList[i].fileName.size) != EOK) {
491             CM_LOG_E("Failed to get cert uri");
492             return CM_FAILURE;
493         }
494         certBlob->uri[i].size = cFileList[i].fileName.size; /* uri */
495 
496         struct CmBlob certData = { 0, NULL };
497         ret = CmStorageGetBuf((char *)cFileList[i].path.data, (char *)cFileList[i].fileName.data, &certData);
498         if (ret != CM_SUCCESS) {
499             CM_LOG_E("get cert data failed");
500             return CM_FAILURE;
501         }
502 
503         ret = CmGetCertAlias(store, (char *)cFileList[i].fileName.data, &certData,
504             &(certBlob->certAlias[i])); /* alias */
505         if (ret != CM_SUCCESS) {
506             CM_LOG_E("Failed to get cert certAlias");
507             CM_FREE_BLOB(certData);
508             return CM_FAILURE;
509         }
510 
511         ret = CmGetCertSubjectName(&certData, &(certBlob->subjectName[i])); /* subjectName */
512         if (ret != CM_SUCCESS) {
513             CM_LOG_E("Failed to get cert subjectName");
514             CM_FREE_BLOB(certData);
515             return CM_FAILURE;
516         }
517         CM_FREE_BLOB(certData);
518     }
519     return ret;
520 }
521 
CmFreeCertBlob(struct CertBlob * certBlob)522 void CmFreeCertBlob(struct CertBlob *certBlob)
523 {
524     if (certBlob == NULL) {
525         CM_LOG_E("certBlob is null");
526         return;
527     }
528 
529     for (uint32_t i = 0; i < MAX_COUNT_CERTIFICATE; i++) {
530         CM_FREE_BLOB(certBlob->uri[i]);
531         CM_FREE_BLOB(certBlob->subjectName[i]);
532         CM_FREE_BLOB(certBlob->certAlias[i]);
533     }
534 }
535 
CmGetMatchedCertIndex(const struct CmMutableBlob * certFileList,const struct CmBlob * certUri)536 uint32_t CmGetMatchedCertIndex(const struct CmMutableBlob *certFileList, const struct CmBlob *certUri)
537 {
538     if (certFileList->size == 0) {
539         CM_LOG_D("no cert file  exist");
540         return MAX_COUNT_CERTIFICATE;
541     }
542 
543     struct CertFileInfo *cFileList = (struct CertFileInfo *)certFileList->data;
544     uint32_t matchIndex = certFileList->size;
545 
546     for (uint32_t i = 0; i < certFileList->size; i++) {
547         if (cFileList[i].fileName.data == NULL) {
548             CM_LOG_E("Corrupted file name at index: %u.\n", i);
549             continue;
550         }
551 
552         if ((certUri->size <= cFileList[i].fileName.size) &&
553             (memcmp(certUri->data, cFileList[i].fileName.data, certUri->size) == 0)) {
554             matchIndex = i;
555             break;
556         }
557     }
558     return matchIndex;
559 }
560