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