• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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