• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
26 #include "securec.h"
27 
28 #include "cm_log.h"
29 
30 typedef X509_NAME *(FUNC)(const X509 *);
31 typedef ASN1_TIME *(TIME_FUNC)(const X509 *);
32 #define CONVERT(p) (((p)[0] - '0') * 10 + (p)[1] - '0')
33 
InitCertContext(const uint8_t * certBuf,uint32_t size)34 X509 *InitCertContext(const uint8_t *certBuf, uint32_t size)
35 {
36     X509 *x509 = NULL;
37     if (certBuf == NULL || size > MAX_LEN_CERTIFICATE) {
38         return NULL;
39     }
40     BIO *bio = BIO_new_mem_buf(certBuf, (int)size);
41     if (!bio) {
42         return NULL;
43     }
44     if (certBuf[0] == '-') {
45         // PEM format
46         x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
47     } else if (certBuf[0] == ASN1_TAG_TYPE_SEQ) {
48         // Der format
49         x509 = d2i_X509_bio(bio, NULL);
50     } else {
51         CM_LOG_E("invalid certificate format.");
52     }
53     BIO_free(bio);
54     return x509;
55 }
56 
GetX509SerialNumber(X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)57 int32_t GetX509SerialNumber(X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
58 {
59     if (outBuf == NULL || x509cert == NULL) {
60         return CMR_ERROR_INVALID_ARGUMENT;
61     }
62     ASN1_INTEGER *serial = X509_get_serialNumber(x509cert);
63     if (serial == NULL) {
64         return CMR_ERROR_INVALID_CERT_FORMAT;
65     }
66     BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL);
67     if (bn == NULL) {
68         return CMR_ERROR_INVALID_CERT_FORMAT;
69     }
70 
71     char *hex = BN_bn2hex(bn);
72     if (hex == NULL) {
73         BN_free(bn);
74         return CMR_ERROR_INVALID_CERT_FORMAT;
75     }
76 
77     uint32_t len = (uint32_t)strlen(hex);
78     if (len >= outBufMaxSize) {
79         OPENSSL_free(hex);
80         BN_free(bn);
81         return CMR_ERROR_BUFFER_TOO_SMALL;
82     }
83     if (strncpy_s(outBuf, outBufMaxSize, hex, len) != EOK) {
84         OPENSSL_free(hex);
85         BN_free(bn);
86         return CMR_ERROR_INVALID_OPERATION;
87     }
88 
89     OPENSSL_free(hex);
90     BN_free(bn);
91     return (int32_t)len;
92 }
ToStringName(FUNC func,const X509 * x509cert,const char * objname,char * outBuf,uint32_t outBufMaxSize)93 static int32_t ToStringName(FUNC func, const X509 *x509cert, const char *objname, char *outBuf, uint32_t outBufMaxSize)
94 {
95     int32_t length = 0;
96     if (func == NULL || x509cert == NULL || outBuf == NULL || outBufMaxSize == 0) {
97         return CMR_ERROR_INVALID_ARGUMENT;
98     }
99 
100     X509_NAME *name = func(x509cert);
101     if (name == NULL) {
102         return CMR_ERROR_INVALID_CERT_FORMAT;
103     }
104 
105     for (int i = 0; i < X509_NAME_entry_count(name); ++i) {
106         X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, i);
107         const char *strname = OBJ_nid2sn(OBJ_obj2nid(X509_NAME_ENTRY_get_object(entry)));
108 
109         if (strcmp(objname, strname) == 0) {
110             char *data = NULL;
111             length = ASN1_STRING_to_UTF8((unsigned char **)&data, X509_NAME_ENTRY_get_data(entry));
112             if (length < 0) {
113                 return CMR_ERROR_INVALID_CERT_FORMAT;
114             } else if ((uint32_t)length >= outBufMaxSize) {
115                 OPENSSL_free(data);
116                 return CMR_ERROR_BUFFER_TOO_SMALL;
117             }
118             if (strncpy_s(outBuf, outBufMaxSize, data, length) != EOK) {
119                 OPENSSL_free(data);
120                 return CMR_ERROR_INVALID_OPERATION;
121             }
122             OPENSSL_free(data);
123             break;
124         }
125     }
126     return length;
127 }
128 
GetX509IssueName(const X509 * x509cert,const char * issuerObjName,char * outBuf,uint32_t outBufMaxSize)129 static int32_t GetX509IssueName(const X509 *x509cert, const char *issuerObjName, char *outBuf, uint32_t outBufMaxSize)
130 {
131     return ToStringName(X509_get_issuer_name, x509cert, issuerObjName, outBuf, outBufMaxSize);
132 }
133 
GetX509SubjectName(const X509 * x509cert,const char * subjectObjName,char * outBuf,uint32_t outBufMaxSize)134 int32_t GetX509SubjectName(const X509 *x509cert, const char *subjectObjName, char *outBuf, uint32_t outBufMaxSize)
135 {
136     return ToStringName(X509_get_subject_name, x509cert, subjectObjName, outBuf, outBufMaxSize);
137 }
138 
GetX509SubjectNameLongFormat(const X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)139 int32_t GetX509SubjectNameLongFormat(const X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
140 {
141     if (outBuf == NULL || outBufMaxSize == 0) {
142         return CMR_ERROR_INVALID_ARGUMENT;
143     }
144     uint32_t offset = 0;
145     const char *subjectNameList[] = {CM_COMMON_NAME, CM_ORGANIZATION_UNIT_NAME, CM_ORGANIZATION_NAME};
146     uint32_t sizeList = sizeof(subjectNameList) / sizeof(subjectNameList[0]);
147     for (uint32_t j = 0; j < sizeList; ++j) {
148         char subjectName[NAME_MAX_SIZE] = {0};
149         int32_t length = GetX509SubjectName(x509cert, subjectNameList[j], subjectName, NAME_MAX_SIZE);
150         if (length < 0) {
151             return length;
152         }
153         if (snprintf_s(outBuf + offset, outBufMaxSize - offset, outBufMaxSize - offset - 1, "%s=%s%c",
154             subjectNameList[j], subjectName, (char)(((j + 1) == sizeList) ? '\0' : ',')) < 0) {
155             return CMR_ERROR_INVALID_OPERATION;
156         }
157         offset += strlen(subjectNameList[j]) + strlen(subjectName) + NAME_DELIMITER_SIZE;
158     }
159     return (int32_t)strlen(outBuf);
160 }
161 
GetX509IssueNameLongFormat(const X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)162 int32_t GetX509IssueNameLongFormat(const X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
163 {
164     if (outBuf == NULL || outBufMaxSize == 0) {
165         return CMR_ERROR_INVALID_ARGUMENT;
166     }
167     uint32_t offset = 0;
168 
169     const char *issueNameList[] = {CM_COMMON_NAME, CM_ORGANIZATION_UNIT_NAME, CM_ORGANIZATION_NAME};
170     uint32_t sizeList = sizeof(issueNameList) / sizeof(issueNameList[0]);
171     for (uint32_t j = 0; j < sizeList; ++j) {
172         char issueName[NAME_MAX_SIZE] = {0};
173         int32_t length = GetX509IssueName(x509cert, issueNameList[j], issueName, NAME_MAX_SIZE);
174         if (length < 0) {
175             return length;
176         }
177         if (snprintf_s(outBuf + offset, outBufMaxSize - offset, outBufMaxSize - offset - 1, "%s=%s%c",
178             issueNameList[j], issueName, (char)(((j + 1) == sizeList) ? '\0' : ',')) < 0) {
179             return CMR_ERROR_INVALID_OPERATION;
180         }
181         offset += strlen(issueNameList[j]) + strlen(issueName) + NAME_DELIMITER_SIZE;
182     }
183     return (int32_t)strlen(outBuf);
184 }
185 
GetX509Time(TIME_FUNC fuc,const X509 * x509cert,struct DataTime * pDataTime)186 static int32_t GetX509Time(TIME_FUNC fuc, const X509 *x509cert, struct DataTime *pDataTime)
187 {
188     if (x509cert == NULL || fuc == NULL || pDataTime == NULL) {
189         return CMR_ERROR_INVALID_ARGUMENT;
190     }
191     ASN1_TIME *bufTime = fuc(x509cert);
192     if (!bufTime) {
193         return CMR_ERROR_INVALID_CERT_FORMAT;
194     }
195 
196     if (bufTime->length < NAME_ANS1TIME_LEN) {
197         return CMR_ERROR_INVALID_CERT_FORMAT;
198     }
199 
200     /* Convent the asn1 time to the readable time */
201     pDataTime->year = CONVERT(bufTime->data);
202     if (pDataTime->year < 50) { /* 50 is used for the readable time */
203         pDataTime->year += 100; /* 100 is used for the readable time */
204     }
205     pDataTime->year += 1900;    /* 1900 is used for the readable time */
206     pDataTime->month = CONVERT(bufTime->data + 2);
207     pDataTime->day = CONVERT(bufTime->data + 4);
208     pDataTime->hour = CONVERT(bufTime->data + 6);
209     pDataTime->min = CONVERT(bufTime->data + 8);
210     pDataTime->second = CONVERT(bufTime->data + 10);
211     return 0;
212 }
213 
GetX509TimeFormat(TIME_FUNC fuc,const X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)214 static int32_t GetX509TimeFormat(TIME_FUNC fuc, const X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
215 {
216     if (x509cert == NULL || outBuf == NULL || outBufMaxSize == 0) {
217         return CMR_ERROR_INVALID_ARGUMENT;
218     }
219 
220     struct DataTime dataTime;
221     int32_t ret = GetX509Time(fuc, x509cert, &dataTime);
222     if (ret != CM_SUCCESS) {
223         return ret;
224     }
225 
226     char buf[TIME_FORMAT_MAX_SIZE] = {0};
227     if (snprintf_s(buf, TIME_FORMAT_MAX_SIZE, TIME_FORMAT_MAX_SIZE - 1,
228         "%d-%d-%d", (int)dataTime.year, (int)dataTime.month, (int)dataTime.day) < 0) {
229         return  CMR_ERROR_INVALID_OPERATION;
230     }
231 
232     uint32_t length = (uint32_t)strlen(buf);
233     if (length >= outBufMaxSize) {
234         CM_LOG_E("GetX509TimeFormat buffer too small");
235         return CMR_ERROR_BUFFER_TOO_SMALL;
236     }
237     if (strncpy_s(outBuf, outBufMaxSize, buf, length) != EOK) {
238         return  CMR_ERROR_INVALID_OPERATION;
239     }
240     return (int32_t)length;
241 }
GetX509NotBefore(const X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)242 int32_t GetX509NotBefore(const X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
243 {
244     return GetX509TimeFormat(X509_getm_notBefore, x509cert, outBuf, outBufMaxSize);
245 }
246 
GetX509NotAfter(const X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)247 int32_t GetX509NotAfter(const X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
248 {
249     return GetX509TimeFormat(X509_getm_notAfter, x509cert, outBuf, outBufMaxSize);
250 }
251 
GetX509Fingerprint(const X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)252 int32_t GetX509Fingerprint(const X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
253 {
254     uint32_t size = 0;
255     uint8_t md[EVP_MAX_MD_SIZE] = {0};
256     if (x509cert == NULL) {
257         return CMR_ERROR_INVALID_ARGUMENT;
258     }
259 
260     int32_t res = X509_digest(x509cert, EVP_sha256(), md, &size);
261     if (res < 0) {
262         return CMR_ERROR_INVALID_CERT_FORMAT;
263     }
264     char buf[FINGERPRINT_MAX_SIZE] = {0};
265     for (uint32_t i = 0; i < size; ++i) {
266         if (snprintf_s(buf + 3 * i, FINGERPRINT_MAX_SIZE - 3 * i, /* 3 is  array index */
267             FINGERPRINT_MAX_SIZE - 3 * i - 1,  /* 3 is  array index */
268             "%02X%c", md[i], (char)(((i + 1) == size) ? '\0' : ':')) < 0) {
269             return  CMR_ERROR_INVALID_OPERATION;
270         }
271     }
272     uint32_t length = (uint32_t)strlen(buf);
273     if (length >= outBufMaxSize) {
274         CM_LOG_E("GetX509Fingerprint buffer too small");
275         return CMR_ERROR_BUFFER_TOO_SMALL;
276     }
277 
278     if (strncpy_s(outBuf, outBufMaxSize, buf, length) != EOK) {
279         return  CMR_ERROR_INVALID_OPERATION;
280     }
281     return (int32_t)length;
282 }
283 
FreeCertContext(X509 * x509cert)284 void FreeCertContext(X509 *x509cert)
285 {
286     if (!x509cert) {
287         return;
288     }
289     X509_free(x509cert);
290 }
291