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 "cm_x509.h"
17 
18 #include <openssl/asn1.h>
19 #include <openssl/bio.h>
20 #include <openssl/err.h>
21 #include <openssl/evp.h>
22 #include <openssl/pem.h>
23 
24 #include <string.h>
25 #include <time.h>
26 
27 #include "securec.h"
28 
29 #include "cm_log.h"
30 
31 typedef X509_NAME *(FUNC)(const X509 *);
32 typedef ASN1_TIME *(TIME_FUNC)(const X509 *);
33 #define CONVERT(p) (((p)[0] - '0') * 10 + (p)[1] - '0')
34 #define BASE_YEAR 1900
35 
InitCertContext(const uint8_t * certBuf,uint32_t size)36 X509 *InitCertContext(const uint8_t *certBuf, uint32_t size)
37 {
38     X509 *x509 = NULL;
39     if (certBuf == NULL || size > MAX_LEN_CERTIFICATE) {
40         return NULL;
41     }
42     BIO *bio = BIO_new_mem_buf(certBuf, (int)size);
43     if (!bio) {
44         return NULL;
45     }
46     if (certBuf[0] == '-') {
47         // PEM format
48         x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
49     } else if (certBuf[0] == ASN1_TAG_TYPE_SEQ) {
50         // Der format
51         x509 = d2i_X509_bio(bio, NULL);
52     } else {
53         CM_LOG_E("invalid certificate format.");
54     }
55     BIO_free(bio);
56     return x509;
57 }
58 
GetX509SerialNumber(X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)59 int32_t GetX509SerialNumber(X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
60 {
61     if (outBuf == NULL || x509cert == NULL) {
62         return CMR_ERROR_INVALID_ARGUMENT;
63     }
64     ASN1_INTEGER *serial = X509_get_serialNumber(x509cert);
65     if (serial == NULL) {
66         return CMR_ERROR_INVALID_CERT_FORMAT;
67     }
68     BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL);
69     if (bn == NULL) {
70         return CMR_ERROR_INVALID_CERT_FORMAT;
71     }
72 
73     char *hex = BN_bn2hex(bn);
74     if (hex == NULL) {
75         BN_free(bn);
76         return CMR_ERROR_INVALID_CERT_FORMAT;
77     }
78 
79     uint32_t len = (uint32_t)strlen(hex);
80     if (len >= outBufMaxSize) {
81         OPENSSL_free(hex);
82         BN_free(bn);
83         return CMR_ERROR_BUFFER_TOO_SMALL;
84     }
85     if (strncpy_s(outBuf, outBufMaxSize, hex, len) != EOK) {
86         OPENSSL_free(hex);
87         BN_free(bn);
88         return CMR_ERROR_INVALID_OPERATION;
89     }
90 
91     OPENSSL_free(hex);
92     BN_free(bn);
93     return (int32_t)len;
94 }
ToStringName(FUNC func,const X509 * x509cert,const char * objname,char * outBuf,uint32_t outBufMaxSize)95 static int32_t ToStringName(FUNC func, const X509 *x509cert, const char *objname, char *outBuf, uint32_t outBufMaxSize)
96 {
97     int32_t length = 0;
98     if (func == NULL || x509cert == NULL || outBuf == NULL || outBufMaxSize == 0) {
99         return CMR_ERROR_INVALID_ARGUMENT;
100     }
101 
102     X509_NAME *name = func(x509cert);
103     if (name == NULL) {
104         return CMR_ERROR_INVALID_CERT_FORMAT;
105     }
106 
107     for (int i = 0; i < X509_NAME_entry_count(name); ++i) {
108         X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, i);
109         const char *strname = OBJ_nid2sn(OBJ_obj2nid(X509_NAME_ENTRY_get_object(entry)));
110 
111         if (strname == NULL) {
112             continue;
113         }
114 
115         if (strcmp(objname, strname) == 0) {
116             char *data = NULL;
117             length = ASN1_STRING_to_UTF8((unsigned char **)&data, X509_NAME_ENTRY_get_data(entry));
118             if (length < 0) {
119                 return CMR_ERROR_INVALID_CERT_FORMAT;
120             } else if ((uint32_t)length >= outBufMaxSize) {
121                 OPENSSL_free(data);
122                 return CMR_ERROR_BUFFER_TOO_SMALL;
123             }
124             if (strncpy_s(outBuf, outBufMaxSize, data, length) != EOK) {
125                 OPENSSL_free(data);
126                 return CMR_ERROR_INVALID_OPERATION;
127             }
128             OPENSSL_free(data);
129             break;
130         }
131     }
132     return length;
133 }
134 
GetX509IssueName(const X509 * x509cert,const char * issuerObjName,char * outBuf,uint32_t outBufMaxSize)135 static int32_t GetX509IssueName(const X509 *x509cert, const char *issuerObjName, char *outBuf, uint32_t outBufMaxSize)
136 {
137     return ToStringName(X509_get_issuer_name, x509cert, issuerObjName, outBuf, outBufMaxSize);
138 }
139 
GetX509FirstSubjectName(const X509 * x509cert,struct CmBlob * displaytName)140 static int32_t GetX509FirstSubjectName(const X509 *x509cert, struct CmBlob *displaytName)
141 {
142     char *outBuf = (char *)displaytName->data;
143     const char *subjectNameList[] = {CM_COMMON_NAME, CM_ORGANIZATION_UNIT_NAME, CM_ORGANIZATION_NAME};
144     uint32_t sizeList = sizeof(subjectNameList) / sizeof(subjectNameList[0]);
145     for (uint32_t j = 0; j < sizeList; ++j) {
146         int32_t length = 0;
147         char subjectName[NAME_MAX_SIZE] = { 0 };
148         length = GetX509SubjectName(x509cert, subjectNameList[j], subjectName, NAME_MAX_SIZE);
149         if (length < 0) {
150             return CMR_ERROR_INVALID_CERT_FORMAT;
151         } else if ((uint32_t)length >= displaytName->size) {
152             return CMR_ERROR_BUFFER_TOO_SMALL;
153         }
154         if (strlen(subjectName) > 0) {
155             if (strncpy_s(outBuf, displaytName->size, subjectName, strlen(subjectName)) != EOK) {
156                 return CMR_ERROR_INVALID_OPERATION;
157             }
158             outBuf[length] = '\0';
159             displaytName->size = (uint32_t)(length + 1);
160             break;
161         }
162     }
163     return CM_SUCCESS;
164 }
165 
GetX509FirstSubjectProp(const X509 * x509cert,struct CmBlob * displaytName)166 static int32_t GetX509FirstSubjectProp(const X509 *x509cert, struct CmBlob *displaytName)
167 {
168     int32_t length = 0;
169     char *outBuf = (char *)displaytName->data;
170     X509_NAME *name = X509_get_subject_name(x509cert);
171     if (name == NULL) {
172         CM_LOG_E("X509_get_subject_name get name faild");
173         return CMR_ERROR_INVALID_CERT_FORMAT;
174     }
175     X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, 0);
176     char *data = NULL;
177     length = ASN1_STRING_to_UTF8((unsigned char **)&data, X509_NAME_ENTRY_get_data(entry));
178     if (length < 0) {
179         return CMR_ERROR_INVALID_CERT_FORMAT;
180     } else if ((uint32_t)length >= displaytName->size) {
181         OPENSSL_free(data);
182         return CMR_ERROR_BUFFER_TOO_SMALL;
183     }
184     if (strncpy_s(outBuf, displaytName->size, data, length) != EOK) {
185         OPENSSL_free(data);
186         return CMR_ERROR_INVALID_OPERATION;
187     }
188     outBuf[length] = '\0';
189     displaytName->size = (uint32_t)(length + 1);
190     OPENSSL_free(data);
191     return CM_SUCCESS;
192 }
193 
GetDisplayName(X509 * x509cert,const struct CmBlob * certAlias,const char * subjectName,struct CmBlob * displaytName)194 static int32_t GetDisplayName(X509 *x509cert, const struct CmBlob *certAlias,
195     const char *subjectName, struct CmBlob *displaytName)
196 {
197     int32_t ret = CM_SUCCESS;
198     if (strcmp("", (char *)certAlias->data) == 0) {
199         if (strcmp(CM_SUBJECT_NAME_NULL, subjectName) == 0) {
200             ret = GetX509FirstSubjectProp(x509cert, displaytName);
201             if (ret != CM_SUCCESS) {
202                 CM_LOG_E("GetX509FirstSubjectProp failed");
203                 return ret;
204             }
205         } else {
206             ret = GetX509FirstSubjectName(x509cert, displaytName);
207             if (ret != CM_SUCCESS) {
208                 CM_LOG_E("GetX509FirstSubjectName failed");
209                 return ret;
210             }
211         }
212     } else {
213         if (memcpy_s(displaytName->data, displaytName->size, certAlias->data, certAlias->size) != EOK) {
214             CM_LOG_E("copy displayname failed");
215             return CMR_ERROR_INVALID_OPERATION;
216         }
217         displaytName->size = certAlias->size;
218     }
219     return ret;
220 }
221 
GetSubjectNameAndAlias(X509 * x509cert,const struct CmBlob * certAlias,struct CmBlob * subjectName,struct CmBlob * displaytName)222 int32_t GetSubjectNameAndAlias(X509 *x509cert, const struct CmBlob *certAlias,
223     struct CmBlob *subjectName, struct CmBlob *displaytName)
224 {
225     if ((x509cert == NULL) || (CmCheckBlob(certAlias) != CM_SUCCESS) ||
226         (subjectName == NULL) || (displaytName == NULL)) {
227         CM_LOG_E("input param is invalid");
228         return CMR_ERROR_INVALID_ARGUMENT;
229     }
230 
231     int32_t subjectLen = GetX509SubjectNameLongFormat(x509cert, (char *)subjectName->data, MAX_LEN_SUBJECT_NAME);
232     if (subjectLen <= 0) {
233         CM_LOG_E("get cert subjectName failed");
234         return CMR_ERROR_INVALID_CERT_FORMAT;
235     }
236     subjectName->size = (uint32_t)subjectLen + 1;
237 
238     int32_t ret = GetDisplayName(x509cert, certAlias, (char *)subjectName->data, displaytName);
239     if (ret != CM_SUCCESS) {
240         CM_LOG_E("GetDisplayName failed");
241         return ret;
242     }
243     return CM_SUCCESS;
244 }
245 
GetX509SubjectName(const X509 * x509cert,const char * subjectObjName,char * outBuf,uint32_t outBufMaxSize)246 int32_t GetX509SubjectName(const X509 *x509cert, const char *subjectObjName, char *outBuf, uint32_t outBufMaxSize)
247 {
248     return ToStringName(X509_get_subject_name, x509cert, subjectObjName, outBuf, outBufMaxSize);
249 }
250 
GetX509SubjectNameLongFormat(const X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)251 int32_t GetX509SubjectNameLongFormat(const X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
252 {
253     if (outBuf == NULL || outBufMaxSize == 0) {
254         return CMR_ERROR_INVALID_ARGUMENT;
255     }
256     uint32_t offset = 0;
257     const char *subjectNameList[] = {CM_COMMON_NAME, CM_ORGANIZATION_UNIT_NAME, CM_ORGANIZATION_NAME};
258     uint32_t sizeList = sizeof(subjectNameList) / sizeof(subjectNameList[0]);
259     for (uint32_t j = 0; j < sizeList; ++j) {
260         char subjectName[NAME_MAX_SIZE] = {0};
261         int32_t length = GetX509SubjectName(x509cert, subjectNameList[j], subjectName, NAME_MAX_SIZE);
262         if (length < 0) {
263             return length;
264         }
265         if (snprintf_s(outBuf + offset, outBufMaxSize - offset, outBufMaxSize - offset - 1, "%s=%s%c",
266             subjectNameList[j], subjectName, (char)(((j + 1) == sizeList) ? '\0' : ',')) < 0) {
267             return CMR_ERROR_INVALID_OPERATION;
268         }
269         offset += strlen(subjectNameList[j]) + strlen(subjectName) + NAME_DELIMITER_SIZE;
270     }
271     return (int32_t)strlen(outBuf);
272 }
273 
GetX509IssueNameLongFormat(const X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)274 int32_t GetX509IssueNameLongFormat(const X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
275 {
276     if (outBuf == NULL || outBufMaxSize == 0) {
277         return CMR_ERROR_INVALID_ARGUMENT;
278     }
279     uint32_t offset = 0;
280 
281     const char *issueNameList[] = {CM_COMMON_NAME, CM_ORGANIZATION_UNIT_NAME, CM_ORGANIZATION_NAME};
282     uint32_t sizeList = sizeof(issueNameList) / sizeof(issueNameList[0]);
283     for (uint32_t j = 0; j < sizeList; ++j) {
284         char issueName[NAME_MAX_SIZE] = {0};
285         int32_t length = GetX509IssueName(x509cert, issueNameList[j], issueName, NAME_MAX_SIZE);
286         if (length < 0) {
287             return length;
288         }
289         if (snprintf_s(outBuf + offset, outBufMaxSize - offset, outBufMaxSize - offset - 1, "%s=%s%c",
290             issueNameList[j], issueName, (char)(((j + 1) == sizeList) ? '\0' : ',')) < 0) {
291             return CMR_ERROR_INVALID_OPERATION;
292         }
293         offset += strlen(issueNameList[j]) + strlen(issueName) + NAME_DELIMITER_SIZE;
294     }
295     return (int32_t)strlen(outBuf);
296 }
297 
GetLocalTime(ASN1_TIME * asn1Time)298 static struct tm *GetLocalTime(ASN1_TIME *asn1Time)
299 {
300     time_t curLocalTimeSec = time(NULL);
301     if (curLocalTimeSec < 0) {
302         CM_LOG_E("Failed to get current local time");
303         return NULL;
304     }
305 
306     struct tm *gmTime = gmtime(&curLocalTimeSec);
307     if (gmTime == NULL) {
308         CM_LOG_E("Failed to convert current local time to utc time");
309         return NULL;
310     }
311 
312     time_t curUtcTimeSec = mktime(gmTime);
313     if (curUtcTimeSec < 0) {
314         CM_LOG_E("Failed to get current utc time");
315         return NULL;
316     }
317 
318     struct tm utcTime;
319     int ret = ASN1_TIME_to_tm(asn1Time, &utcTime);
320     if (ret == 0) {
321         CM_LOG_E("invalid asn1 time format");
322         return NULL;
323     }
324 
325     time_t utcTimeSec = mktime(&utcTime);
326     if (utcTimeSec < 0) {
327         CM_LOG_E("Failed to get utc time");
328         return NULL;
329     }
330     time_t localTimeSec = utcTimeSec + curLocalTimeSec - curUtcTimeSec;
331     return localtime(&localTimeSec);
332 }
333 
GetX509Time(TIME_FUNC fuc,const X509 * x509cert,struct DataTime * pDataTime)334 static int32_t GetX509Time(TIME_FUNC fuc, const X509 *x509cert, struct DataTime *pDataTime)
335 {
336     if (x509cert == NULL || fuc == NULL || pDataTime == NULL) {
337         return CMR_ERROR_INVALID_ARGUMENT;
338     }
339     ASN1_TIME *asn1Time = fuc(x509cert);
340     if (asn1Time == NULL) {
341         CM_LOG_E("Failed to get asn1 time from x509Cert");
342         return CMR_ERROR_INVALID_CERT_FORMAT;
343     }
344 
345     if (asn1Time->length < NAME_ANS1TIME_LEN) {
346         return CMR_ERROR_INVALID_CERT_FORMAT;
347     }
348 
349     struct tm *localTime = GetLocalTime(asn1Time);
350     if (localTime == NULL) {
351         CM_LOG_E("Failed to get local time by utc time");
352         return CMR_ERROR_INVALID_OPERATION;
353     }
354 
355     pDataTime->year = (uint32_t)(localTime->tm_year + BASE_YEAR);
356     pDataTime->month = (uint32_t)(localTime->tm_mon + 1);
357     pDataTime->day = (uint32_t)localTime->tm_mday;
358     pDataTime->hour = (uint32_t)localTime->tm_hour;
359     pDataTime->min = (uint32_t)localTime->tm_min;
360     pDataTime->second = (uint32_t)localTime->tm_sec;
361     return CM_SUCCESS;
362 }
363 
GetX509TimeFormat(TIME_FUNC fuc,const X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)364 static int32_t GetX509TimeFormat(TIME_FUNC fuc, const X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
365 {
366     if (x509cert == NULL || outBuf == NULL || outBufMaxSize == 0) {
367         return CMR_ERROR_INVALID_ARGUMENT;
368     }
369 
370     struct DataTime dataTime;
371     int32_t ret = GetX509Time(fuc, x509cert, &dataTime);
372     if (ret != CM_SUCCESS) {
373         return ret;
374     }
375 
376     char buf[TIME_FORMAT_MAX_SIZE] = {0};
377     if (snprintf_s(buf, TIME_FORMAT_MAX_SIZE, TIME_FORMAT_MAX_SIZE - 1,
378         "%d-%d-%d", (int)dataTime.year, (int)dataTime.month, (int)dataTime.day) < 0) {
379         return  CMR_ERROR_INVALID_OPERATION;
380     }
381 
382     uint32_t length = (uint32_t)strlen(buf);
383     if (length >= outBufMaxSize) {
384         CM_LOG_E("GetX509TimeFormat buffer too small");
385         return CMR_ERROR_BUFFER_TOO_SMALL;
386     }
387     if (strncpy_s(outBuf, outBufMaxSize, buf, length) != EOK) {
388         return  CMR_ERROR_INVALID_OPERATION;
389     }
390     return (int32_t)length;
391 }
GetX509NotBefore(const X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)392 int32_t GetX509NotBefore(const X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
393 {
394     return GetX509TimeFormat(X509_getm_notBefore, x509cert, outBuf, outBufMaxSize);
395 }
396 
GetX509NotAfter(const X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)397 int32_t GetX509NotAfter(const X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
398 {
399     return GetX509TimeFormat(X509_getm_notAfter, x509cert, outBuf, outBufMaxSize);
400 }
401 
GetX509Fingerprint(const X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)402 int32_t GetX509Fingerprint(const X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
403 {
404     uint32_t size = 0;
405     uint8_t md[EVP_MAX_MD_SIZE] = {0};
406     if (x509cert == NULL) {
407         return CMR_ERROR_INVALID_ARGUMENT;
408     }
409 
410     int32_t res = X509_digest(x509cert, EVP_sha256(), md, &size);
411     if (res < 0) {
412         return CMR_ERROR_INVALID_CERT_FORMAT;
413     }
414     char buf[FINGERPRINT_MAX_SIZE] = {0};
415     for (uint32_t i = 0; i < size; ++i) {
416         if (snprintf_s(buf + 3 * i, FINGERPRINT_MAX_SIZE - 3 * i, /* 3 is  array index */
417             FINGERPRINT_MAX_SIZE - 3 * i - 1,  /* 3 is  array index */
418             "%02X%c", md[i], (char)(((i + 1) == size) ? '\0' : ':')) < 0) {
419             return  CMR_ERROR_INVALID_OPERATION;
420         }
421     }
422     uint32_t length = (uint32_t)strlen(buf);
423     if (length >= outBufMaxSize) {
424         CM_LOG_E("GetX509Fingerprint buffer too small");
425         return CMR_ERROR_BUFFER_TOO_SMALL;
426     }
427 
428     if (strncpy_s(outBuf, outBufMaxSize, buf, length) != EOK) {
429         return  CMR_ERROR_INVALID_OPERATION;
430     }
431     return (int32_t)length;
432 }
433 
FreeCertContext(X509 * x509cert)434 void FreeCertContext(X509 *x509cert)
435 {
436     if (!x509cert) {
437         return;
438     }
439     X509_free(x509cert);
440 }
441