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