1 /*
2 * Copyright (c) 2022-2025 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 #include <openssl/pkcs7.h>
24
25 #include <string.h>
26 #include <time.h>
27
28 #include "securec.h"
29
30 #include "cm_log.h"
31
32 typedef X509_NAME *(FUNC)(const X509 *);
33 typedef ASN1_TIME *(TIME_FUNC)(const X509 *);
34 #define CONVERT(p) (((p)[0] - '0') * 10 + (p)[1] - '0')
35 #define BASE_YEAR 1900
36
37 // LCOV_EXCL_START
InitCertContext(const uint8_t * certBuf,uint32_t size)38 X509 *InitCertContext(const uint8_t *certBuf, uint32_t size)
39 {
40 X509 *x509 = NULL;
41 if (certBuf == NULL || size > MAX_LEN_CERTIFICATE || size == 0) {
42 return NULL;
43 }
44 BIO *bio = BIO_new_mem_buf(certBuf, (int)size);
45 if (!bio) {
46 return NULL;
47 }
48 if (certBuf[0] == '-') {
49 // PEM format
50 x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
51 } else if (certBuf[0] == ASN1_TAG_TYPE_SEQ) {
52 // Der format
53 x509 = d2i_X509_bio(bio, NULL);
54 } else {
55 CM_LOG_E("invalid certificate format.");
56 }
57 BIO_free(bio);
58 return x509;
59 }
60
FindStringInStack(STACK_OF (char)* sk,const char * target)61 static int32_t FindStringInStack(STACK_OF(char) *sk, const char *target)
62 {
63 if (sk == NULL || target == NULL) {
64 CM_LOG_E("null pointer");
65 return CMR_ERROR;
66 }
67 int num = sk_char_num(sk);
68 for (int i = 0; i < num; i++) {
69 char *str = sk_char_value(sk, i);
70 if (str && strcmp(str, target) == 0) {
71 CM_LOG_I("found fingerprint");
72 return i;
73 }
74 }
75 return CMR_ERROR;
76 }
77
DumplicateCerts(STACK_OF (X509)* certStack,STACK_OF (X509)* deduplicateStack)78 static int32_t DumplicateCerts(STACK_OF(X509) *certStack, STACK_OF(X509) *deduplicateStack)
79 {
80 if (certStack == NULL || deduplicateStack == NULL) {
81 CM_LOG_E("certStack or deduplicateStack is null");
82 return CMR_ERROR_NULL_POINTER;
83 }
84 STACK_OF(char) *fingerprintStack = sk_char_new_null();
85 if (fingerprintStack == NULL) {
86 CM_LOG_E("fingerprintStack is null");
87 return CMR_ERROR_MALLOC_FAIL;
88 }
89 int32_t ret = CM_SUCCESS;
90 int certNum = sk_X509_num(certStack);
91 for (int i = 0; i < certNum; ++i) {
92 X509 *cert = sk_X509_value(certStack, i);
93 char fingerprint[FINGERPRINT_MAX_SIZE] = {0};
94 int32_t fingerprintLength = GetX509Fingerprint(cert, fingerprint, sizeof(fingerprint));
95 if (fingerprintLength < 0) {
96 continue;
97 }
98 // check is fingerprint exist or not.
99 int32_t fpIdx = FindStringInStack(fingerprintStack, fingerprint);
100 if (fpIdx != CMR_ERROR) {
101 continue;
102 }
103 X509 *dupCert = X509_dup(cert);
104 if (dupCert == NULL) {
105 CM_LOG_E("dupCert is null");
106 ret = CMR_ERROR_NULL_POINTER;
107 break;
108 }
109 char *dupFingerprint = strdup(fingerprint);
110 if (dupFingerprint == NULL) {
111 X509_free(dupCert);
112 CM_LOG_E("dupFingerprint is null");
113 ret = CMR_ERROR_NULL_POINTER;
114 break;
115 }
116 sk_X509_push(deduplicateStack, dupCert);
117 sk_char_push(fingerprintStack, dupFingerprint);
118 }
119 sk_char_pop_free(fingerprintStack, (void (*)(char *))free);
120 return ret;
121 }
122
STACK_OF(X509)123 STACK_OF(X509) *InitCertStackContext(const uint8_t *certBuf, uint32_t size)
124 {
125 if (certBuf == NULL || size > MAX_LEN_CERTIFICATE_P7B || size == 0) {
126 CM_LOG_E("invalid params");
127 return NULL;
128 }
129 BIO *bio = BIO_new_mem_buf(certBuf, (int)size);
130 if (bio == NULL) {
131 CM_LOG_E("bio is null");
132 return NULL;
133 }
134 PKCS7 *p7 = d2i_PKCS7_bio(bio, NULL);
135 BIO_free(bio);
136 if (p7 == NULL) {
137 CM_LOG_E("p7 is null");
138 return NULL;
139 }
140 if (p7->d.sign == NULL) {
141 CM_LOG_E("p7->d.sign is null");
142 PKCS7_free(p7);
143 return NULL;
144 }
145 STACK_OF(X509) *certStack = p7->d.sign->cert;
146 if (certStack == NULL) {
147 CM_LOG_E("certStack is null");
148 PKCS7_free(p7);
149 return NULL;
150 }
151 STACK_OF(X509) *deduplicateStack = sk_X509_new_null();
152 if (deduplicateStack == NULL) {
153 CM_LOG_E("deduplicateStack is null");
154 PKCS7_free(p7);
155 return NULL;
156 }
157 int32_t ret = DumplicateCerts(certStack, deduplicateStack);
158 PKCS7_free(p7);
159 if (ret != CM_SUCCESS) {
160 CM_LOG_E("deduplicate certs failed, ret = %d", ret);
161 sk_X509_pop_free(deduplicateStack, X509_free);
162 return NULL;
163 }
164 return deduplicateStack;
165 }
166
GetX509SerialNumber(X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)167 int32_t GetX509SerialNumber(X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
168 {
169 if (outBuf == NULL || x509cert == NULL) {
170 return CMR_ERROR_INVALID_ARGUMENT;
171 }
172 ASN1_INTEGER *serial = X509_get_serialNumber(x509cert);
173 if (serial == NULL) {
174 return CMR_ERROR_INVALID_CERT_FORMAT;
175 }
176 BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL);
177 if (bn == NULL) {
178 return CMR_ERROR_INVALID_CERT_FORMAT;
179 }
180
181 char *hex = BN_bn2hex(bn);
182 if (hex == NULL) {
183 BN_free(bn);
184 return CMR_ERROR_INVALID_CERT_FORMAT;
185 }
186
187 uint32_t len = (uint32_t)strlen(hex);
188 if (len >= outBufMaxSize) {
189 OPENSSL_free(hex);
190 BN_free(bn);
191 return CMR_ERROR_BUFFER_TOO_SMALL;
192 }
193 if (strncpy_s(outBuf, outBufMaxSize, hex, len) != EOK) {
194 OPENSSL_free(hex);
195 BN_free(bn);
196 return CMR_ERROR_MEM_OPERATION_COPY;
197 }
198
199 OPENSSL_free(hex);
200 BN_free(bn);
201 return (int32_t)len;
202 }
ToStringName(FUNC func,const X509 * x509cert,const char * objname,char * outBuf,uint32_t outBufMaxSize)203 static int32_t ToStringName(FUNC func, const X509 *x509cert, const char *objname, char *outBuf, uint32_t outBufMaxSize)
204 {
205 int32_t length = 0;
206 if (func == NULL || x509cert == NULL || outBuf == NULL || outBufMaxSize == 0) {
207 return CMR_ERROR_INVALID_ARGUMENT;
208 }
209
210 X509_NAME *name = func(x509cert);
211 if (name == NULL) {
212 return CMR_ERROR_INVALID_CERT_FORMAT;
213 }
214
215 for (int i = 0; i < X509_NAME_entry_count(name); ++i) {
216 X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, i);
217 const char *strname = OBJ_nid2sn(OBJ_obj2nid(X509_NAME_ENTRY_get_object(entry)));
218
219 if (strname == NULL) {
220 continue;
221 }
222
223 if (strcmp(objname, strname) == 0) {
224 char *data = NULL;
225 length = ASN1_STRING_to_UTF8((unsigned char **)&data, X509_NAME_ENTRY_get_data(entry));
226 if (length < 0) {
227 return CMR_ERROR_INVALID_CERT_FORMAT;
228 } else if ((uint32_t)length >= outBufMaxSize) {
229 OPENSSL_free(data);
230 return CMR_ERROR_BUFFER_TOO_SMALL;
231 }
232 if (strncpy_s(outBuf, outBufMaxSize, data, length) != EOK) {
233 OPENSSL_free(data);
234 return CMR_ERROR_MEM_OPERATION_COPY;
235 }
236 OPENSSL_free(data);
237 break;
238 }
239 }
240 return length;
241 }
242
GetX509IssueName(const X509 * x509cert,const char * issuerObjName,char * outBuf,uint32_t outBufMaxSize)243 static int32_t GetX509IssueName(const X509 *x509cert, const char *issuerObjName, char *outBuf, uint32_t outBufMaxSize)
244 {
245 return ToStringName(X509_get_issuer_name, x509cert, issuerObjName, outBuf, outBufMaxSize);
246 }
247
GetX509FirstSubjectName(const X509 * x509cert,struct CmBlob * displayName)248 static int32_t GetX509FirstSubjectName(const X509 *x509cert, struct CmBlob *displayName)
249 {
250 char *outBuf = (char *)displayName->data;
251 const char *subjectNameList[] = {CM_COMMON_NAME, CM_ORGANIZATION_UNIT_NAME, CM_ORGANIZATION_NAME};
252 uint32_t sizeList = sizeof(subjectNameList) / sizeof(subjectNameList[0]);
253 for (uint32_t j = 0; j < sizeList; ++j) {
254 int32_t length = 0;
255 char subjectName[NAME_MAX_SIZE] = { 0 };
256 length = GetX509SubjectName(x509cert, subjectNameList[j], subjectName, NAME_MAX_SIZE);
257 if (length < 0) {
258 return CMR_ERROR_INVALID_CERT_FORMAT;
259 } else if ((uint32_t)length >= displayName->size) {
260 return CMR_ERROR_BUFFER_TOO_SMALL;
261 }
262 if (strlen(subjectName) > 0) {
263 if (strncpy_s(outBuf, displayName->size, subjectName, strlen(subjectName)) != EOK) {
264 return CMR_ERROR_MEM_OPERATION_COPY;
265 }
266 outBuf[length] = '\0';
267 displayName->size = (uint32_t)(length + 1);
268 break;
269 }
270 }
271 return CM_SUCCESS;
272 }
273
GetX509FirstSubjectProp(const X509 * x509cert,struct CmBlob * displayName)274 static int32_t GetX509FirstSubjectProp(const X509 *x509cert, struct CmBlob *displayName)
275 {
276 int32_t length = 0;
277 char *outBuf = (char *)displayName->data;
278 X509_NAME *name = X509_get_subject_name(x509cert);
279 if (name == NULL) {
280 CM_LOG_E("X509_get_subject_name get name faild");
281 return CMR_ERROR_INVALID_CERT_FORMAT;
282 }
283 X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, 0);
284 char *data = NULL;
285 length = ASN1_STRING_to_UTF8((unsigned char **)&data, X509_NAME_ENTRY_get_data(entry));
286 if (length < 0) {
287 return CMR_ERROR_INVALID_CERT_FORMAT;
288 } else if ((uint32_t)length >= displayName->size) {
289 OPENSSL_free(data);
290 return CMR_ERROR_BUFFER_TOO_SMALL;
291 }
292 if (strncpy_s(outBuf, displayName->size, data, length) != EOK) {
293 OPENSSL_free(data);
294 return CMR_ERROR_MEM_OPERATION_COPY;
295 }
296 outBuf[length] = '\0';
297 displayName->size = (uint32_t)(length + 1);
298 OPENSSL_free(data);
299 return CM_SUCCESS;
300 }
301
GetDisplayName(X509 * x509cert,const struct CmBlob * certAlias,const char * subjectName,struct CmBlob * displayName)302 static int32_t GetDisplayName(X509 *x509cert, const struct CmBlob *certAlias,
303 const char *subjectName, struct CmBlob *displayName)
304 {
305 int32_t ret = CM_SUCCESS;
306 if (strcmp("", (char *)certAlias->data) == 0) {
307 if (strcmp(CM_SUBJECT_NAME_NULL, subjectName) == 0) {
308 ret = GetX509FirstSubjectProp(x509cert, displayName);
309 if (ret != CM_SUCCESS) {
310 CM_LOG_E("GetX509FirstSubjectProp failed");
311 return ret;
312 }
313 } else {
314 ret = GetX509FirstSubjectName(x509cert, displayName);
315 if (ret != CM_SUCCESS) {
316 CM_LOG_E("GetX509FirstSubjectName failed");
317 return ret;
318 }
319 }
320 } else {
321 if (memcpy_s(displayName->data, displayName->size, certAlias->data, certAlias->size) != EOK) {
322 CM_LOG_E("copy displayname failed");
323 return CMR_ERROR_MEM_OPERATION_COPY;
324 }
325 displayName->size = certAlias->size;
326 }
327 return ret;
328 }
329
GetSubjectNameAndAlias(X509 * x509cert,const struct CmBlob * certAlias,struct CmBlob * subjectName,struct CmBlob * displayName)330 int32_t GetSubjectNameAndAlias(X509 *x509cert, const struct CmBlob *certAlias,
331 struct CmBlob *subjectName, struct CmBlob *displayName)
332 {
333 if ((x509cert == NULL) || (CmCheckBlob(certAlias) != CM_SUCCESS) ||
334 (subjectName == NULL) || (displayName == NULL)) {
335 CM_LOG_E("input param is invalid");
336 return CMR_ERROR_INVALID_ARGUMENT;
337 }
338
339 int32_t subjectLen = GetX509SubjectNameLongFormat(x509cert, (char *)subjectName->data, MAX_LEN_SUBJECT_NAME);
340 if (subjectLen <= 0) {
341 CM_LOG_E("get cert subjectName failed");
342 return CMR_ERROR_INVALID_CERT_FORMAT;
343 }
344 subjectName->size = (uint32_t)subjectLen + 1;
345
346 int32_t ret = GetDisplayName(x509cert, certAlias, (char *)subjectName->data, displayName);
347 if (ret != CM_SUCCESS) {
348 CM_LOG_E("GetDisplayName failed");
349 return ret;
350 }
351 return CM_SUCCESS;
352 }
353
GetX509SubjectName(const X509 * x509cert,const char * subjectObjName,char * outBuf,uint32_t outBufMaxSize)354 int32_t GetX509SubjectName(const X509 *x509cert, const char *subjectObjName, char *outBuf, uint32_t outBufMaxSize)
355 {
356 return ToStringName(X509_get_subject_name, x509cert, subjectObjName, outBuf, outBufMaxSize);
357 }
358
GetX509SubjectNameLongFormat(const X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)359 int32_t GetX509SubjectNameLongFormat(const X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
360 {
361 if (outBuf == NULL || outBufMaxSize == 0) {
362 return CMR_ERROR_INVALID_ARGUMENT;
363 }
364 uint32_t offset = 0;
365 const char *subjectNameList[] = {CM_COMMON_NAME, CM_ORGANIZATION_UNIT_NAME, CM_ORGANIZATION_NAME};
366 uint32_t sizeList = sizeof(subjectNameList) / sizeof(subjectNameList[0]);
367 for (uint32_t j = 0; j < sizeList; ++j) {
368 char subjectName[NAME_MAX_SIZE] = {0};
369 int32_t length = GetX509SubjectName(x509cert, subjectNameList[j], subjectName, NAME_MAX_SIZE);
370 if (length < 0) {
371 return length;
372 }
373 if (snprintf_s(outBuf + offset, outBufMaxSize - offset, outBufMaxSize - offset - 1, "%s=%s%c",
374 subjectNameList[j], subjectName, (char)(((j + 1) == sizeList) ? '\0' : ',')) < 0) {
375 return CMR_ERROR_MEM_OPERATION_PRINT;
376 }
377 offset += strlen(subjectNameList[j]) + strlen(subjectName) + NAME_DELIMITER_SIZE;
378 }
379 return (int32_t)strlen(outBuf);
380 }
381
GetX509IssueNameLongFormat(const X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)382 int32_t GetX509IssueNameLongFormat(const X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
383 {
384 if (outBuf == NULL || outBufMaxSize == 0) {
385 return CMR_ERROR_INVALID_ARGUMENT;
386 }
387 uint32_t offset = 0;
388
389 const char *issueNameList[] = {CM_COMMON_NAME, CM_ORGANIZATION_UNIT_NAME, CM_ORGANIZATION_NAME};
390 uint32_t sizeList = sizeof(issueNameList) / sizeof(issueNameList[0]);
391 for (uint32_t j = 0; j < sizeList; ++j) {
392 char issueName[NAME_MAX_SIZE] = {0};
393 int32_t length = GetX509IssueName(x509cert, issueNameList[j], issueName, NAME_MAX_SIZE);
394 if (length < 0) {
395 return length;
396 }
397 if (snprintf_s(outBuf + offset, outBufMaxSize - offset, outBufMaxSize - offset - 1, "%s=%s%c",
398 issueNameList[j], issueName, (char)(((j + 1) == sizeList) ? '\0' : ',')) < 0) {
399 return CMR_ERROR_MEM_OPERATION_PRINT;
400 }
401 offset += strlen(issueNameList[j]) + strlen(issueName) + NAME_DELIMITER_SIZE;
402 }
403 return (int32_t)strlen(outBuf);
404 }
405
GetLocalTime(ASN1_TIME * asn1Time)406 static struct tm *GetLocalTime(ASN1_TIME *asn1Time)
407 {
408 time_t curLocalTimeSec = time(NULL);
409 if (curLocalTimeSec < 0) {
410 CM_LOG_E("Failed to get current local time");
411 return NULL;
412 }
413
414 struct tm *gmTime = gmtime(&curLocalTimeSec);
415 if (gmTime == NULL) {
416 CM_LOG_E("Failed to convert current local time to utc time");
417 return NULL;
418 }
419
420 time_t curUtcTimeSec = mktime(gmTime);
421 if (curUtcTimeSec < 0) {
422 CM_LOG_E("Failed to get current utc time");
423 return NULL;
424 }
425
426 struct tm utcTime;
427 int ret = ASN1_TIME_to_tm(asn1Time, &utcTime);
428 if (ret == 0) {
429 CM_LOG_E("invalid asn1 time format");
430 return NULL;
431 }
432
433 time_t utcTimeSec = mktime(&utcTime);
434 if (utcTimeSec < 0) {
435 CM_LOG_E("Failed to get utc time");
436 return NULL;
437 }
438 time_t localTimeSec = utcTimeSec + curLocalTimeSec - curUtcTimeSec;
439 return localtime(&localTimeSec);
440 }
441
GetX509Time(TIME_FUNC fuc,const X509 * x509cert,struct DataTime * pDataTime)442 static int32_t GetX509Time(TIME_FUNC fuc, const X509 *x509cert, struct DataTime *pDataTime)
443 {
444 if (x509cert == NULL || fuc == NULL || pDataTime == NULL) {
445 return CMR_ERROR_INVALID_ARGUMENT;
446 }
447 ASN1_TIME *asn1Time = fuc(x509cert);
448 if (asn1Time == NULL) {
449 CM_LOG_E("Failed to get asn1 time from x509Cert");
450 return CMR_ERROR_INVALID_CERT_FORMAT;
451 }
452
453 if (asn1Time->length < NAME_ANS1TIME_LEN) {
454 return CMR_ERROR_INVALID_CERT_FORMAT;
455 }
456
457 struct tm *localTime = GetLocalTime(asn1Time);
458 if (localTime == NULL) {
459 CM_LOG_E("Failed to get local time by utc time");
460 return CMR_ERROR_GET_LOCAL_TIME_FAILED;
461 }
462
463 pDataTime->year = (uint32_t)(localTime->tm_year + BASE_YEAR);
464 pDataTime->month = (uint32_t)(localTime->tm_mon + 1);
465 pDataTime->day = (uint32_t)localTime->tm_mday;
466 pDataTime->hour = (uint32_t)localTime->tm_hour;
467 pDataTime->min = (uint32_t)localTime->tm_min;
468 pDataTime->second = (uint32_t)localTime->tm_sec;
469 return CM_SUCCESS;
470 }
471
GetX509TimeFormat(TIME_FUNC fuc,const X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)472 static int32_t GetX509TimeFormat(TIME_FUNC fuc, const X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
473 {
474 if (x509cert == NULL || outBuf == NULL || outBufMaxSize == 0) {
475 return CMR_ERROR_INVALID_ARGUMENT;
476 }
477
478 struct DataTime dataTime;
479 int32_t ret = GetX509Time(fuc, x509cert, &dataTime);
480 if (ret != CM_SUCCESS) {
481 return ret;
482 }
483
484 char buf[TIME_FORMAT_MAX_SIZE] = {0};
485 if (snprintf_s(buf, TIME_FORMAT_MAX_SIZE, TIME_FORMAT_MAX_SIZE - 1,
486 "%d-%d-%d", (int)dataTime.year, (int)dataTime.month, (int)dataTime.day) < 0) {
487 return CMR_ERROR_MEM_OPERATION_PRINT;
488 }
489
490 uint32_t length = (uint32_t)strlen(buf);
491 if (length >= outBufMaxSize) {
492 CM_LOG_E("GetX509TimeFormat buffer too small");
493 return CMR_ERROR_BUFFER_TOO_SMALL;
494 }
495 if (strncpy_s(outBuf, outBufMaxSize, buf, length) != EOK) {
496 return CMR_ERROR_MEM_OPERATION_COPY;
497 }
498 return (int32_t)length;
499 }
GetX509NotBefore(const X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)500 int32_t GetX509NotBefore(const X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
501 {
502 return GetX509TimeFormat(X509_getm_notBefore, x509cert, outBuf, outBufMaxSize);
503 }
504
GetX509NotAfter(const X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)505 int32_t GetX509NotAfter(const X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
506 {
507 return GetX509TimeFormat(X509_getm_notAfter, x509cert, outBuf, outBufMaxSize);
508 }
509
GetX509Fingerprint(const X509 * x509cert,char * outBuf,uint32_t outBufMaxSize)510 int32_t GetX509Fingerprint(const X509 *x509cert, char *outBuf, uint32_t outBufMaxSize)
511 {
512 uint32_t size = 0;
513 uint8_t md[EVP_MAX_MD_SIZE] = {0};
514 if (x509cert == NULL) {
515 return CMR_ERROR_INVALID_ARGUMENT;
516 }
517
518 int32_t res = X509_digest(x509cert, EVP_sha256(), md, &size);
519 if (res < 0) {
520 return CMR_ERROR_INVALID_CERT_FORMAT;
521 }
522 char buf[FINGERPRINT_MAX_SIZE] = {0};
523 for (uint32_t i = 0; i < size; ++i) {
524 if (snprintf_s(buf + 3 * i, FINGERPRINT_MAX_SIZE - 3 * i, /* 3 is array index */
525 FINGERPRINT_MAX_SIZE - 3 * i - 1, /* 3 is array index */
526 "%02X%c", md[i], (char)(((i + 1) == size) ? '\0' : ':')) < 0) {
527 return CMR_ERROR_MEM_OPERATION_PRINT;
528 }
529 }
530 uint32_t length = (uint32_t)strlen(buf);
531 if (length >= outBufMaxSize) {
532 CM_LOG_E("GetX509Fingerprint buffer too small");
533 return CMR_ERROR_BUFFER_TOO_SMALL;
534 }
535
536 if (strncpy_s(outBuf, outBufMaxSize, buf, length) != EOK) {
537 return CMR_ERROR_MEM_OPERATION_PRINT;
538 }
539 return (int32_t)length;
540 }
541
FreeCertContext(X509 * x509cert)542 void FreeCertContext(X509 *x509cert)
543 {
544 if (!x509cert) {
545 return;
546 }
547 X509_free(x509cert);
548 }
549 // LCOV_EXCL_STOP