Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 2021-2025 DMTF. All rights reserved.
4 : * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md
5 : **/
6 :
7 : /** @file
8 : * X.509 Certificate Handler Wrapper Implementation.
9 : **/
10 :
11 : #include <stdarg.h>
12 : #include "internal_crypt_lib.h"
13 : #include <mbedtls/x509.h>
14 : #include <mbedtls/x509_crt.h>
15 : #include <mbedtls/rsa.h>
16 : #include <mbedtls/ecp.h>
17 : #include <mbedtls/ecdh.h>
18 : #include <mbedtls/ecdsa.h>
19 : #include <mbedtls/x509_csr.h>
20 : #include <mbedtls/entropy.h>
21 : #include <mbedtls/ctr_drbg.h>
22 : #include <mbedtls/oid.h>
23 : #include <mbedtls/bignum.h>
24 : #include <string.h>
25 :
26 : #if LIBSPDM_CERT_PARSE_SUPPORT
27 :
28 : /* OID*/
29 :
30 : #define OID_COMMON_NAME { 0x55, 0x04, 0x03 }
31 : #define OID_ORGANIZATION_NAME { 0x55, 0x04, 0x0A }
32 : #define OID_EXT_KEY_USAGE { 0x55, 0x1D, 0x25 }
33 : #define OID_BASIC_CONSTRAINTS { 0x55, 0x1D, 0x13 }
34 :
35 : static const uint8_t m_libspdm_oid_common_name[] = OID_COMMON_NAME;
36 : static const uint8_t m_libspdm_oid_organization_name[] = OID_ORGANIZATION_NAME;
37 : static const uint8_t m_libspdm_oid_ext_key_usage[] = OID_EXT_KEY_USAGE;
38 : static const uint8_t m_libspdm_oid_basic_constraints[] = OID_BASIC_CONSTRAINTS;
39 :
40 : typedef struct {
41 : const char *name; /* String representation of AttributeType, e.g.
42 : * "CN" or "emailAddress". */
43 : size_t name_len; /* Length of 'name', without trailing 0 byte. */
44 : const char *oid; /* String representation of OID of AttributeType,
45 : * as per RFC 5280, Appendix A.1. */
46 : size_t oid_len;
47 : int default_tag; /* The default character encoding used for the
48 : * given attribute type, e.g.
49 : * MBEDTLS_ASN1_UTF8_STRING for UTF-8. */
50 : } libspdm_x509_subject_descriptor_t;
51 :
52 : #define LIBSPDM_ADD_STRLEN( s ) s, sizeof( s ) - 1
53 :
54 : /*
55 : * EC public keys:
56 : * SubjectPublicKeyInfo ::= SEQUENCE { 1 + 2
57 : * algorithm AlgorithmIdentifier, 1 + 1 (sequence)
58 : * + 1 + 1 + 7 (ec oid)
59 : * + 1 + 1 + 9 (namedCurve oid)
60 : * subjectPublicKey BIT STRING 1 + 2 + 1 [1]
61 : * + 1 (point format) [1]
62 : * + 2 * ECP_MAX (coords) [1]
63 : * }
64 : */
65 : #define LIBSPDM_ECP_PUB_DER_MAX_BYTES (30 + 2 * MBEDTLS_ECP_MAX_BYTES)
66 :
67 : /*
68 : * RSA public keys:
69 : * SubjectPublicKeyInfo ::= SEQUENCE { 1 + 3
70 : * algorithm AlgorithmIdentifier, 1 + 1 (sequence)
71 : * + 1 + 1 + 9 (rsa oid)
72 : * + 1 + 1 (params null)
73 : * subjectPublicKey BIT STRING } 1 + 3 + (1 + below)
74 : * RSAPublicKey ::= SEQUENCE { 1 + 3
75 : * modulus INTEGER, -- n 1 + 3 + MPI_MAX + 1
76 : * publicExponent INTEGER -- e 1 + 3 + MPI_MAX + 1
77 : * }
78 : */
79 : #define LIBSPDM_RSA_PUB_DER_MAX_BYTES (38 + 2 * MBEDTLS_MPI_MAX_SIZE)
80 :
81 : #define LIBSPDM_MAX_PUBKEY_DER_BUFFER_SIZE (LIBSPDM_RSA_PUB_DER_MAX_BYTES > \
82 : LIBSPDM_ECP_PUB_DER_MAX_BYTES ? \
83 : LIBSPDM_RSA_PUB_DER_MAX_BYTES : \
84 : LIBSPDM_ECP_PUB_DER_MAX_BYTES )
85 :
86 : #define LIBSPDM_MAX_SUBJECT_BUFFER_SIZE MBEDTLS_X509_MAX_DN_NAME_SIZE
87 :
88 : #ifdef LIBSPDM_MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
89 : int wrapper_mbedtls_x509_crt_ext_cb(void *p_ctx,
90 : mbedtls_x509_crt const *crt,
91 : mbedtls_x509_buf const *oid,
92 : int critical,
93 : const unsigned char *p,
94 : const unsigned char *end)
95 : {
96 : return 0;
97 : }
98 : #endif
99 :
100 13820 : int wrapper_mbedtls_x509_crt_parse_der(mbedtls_x509_crt *chain,
101 : const unsigned char *buf,
102 : size_t buflen)
103 : {
104 : #ifdef LIBSPDM_MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
105 : return mbedtls_x509_crt_parse_der_with_ext_cb(chain, buf, buflen, 1, wrapper_mbedtls_x509_crt_ext_cb, NULL);
106 : #else
107 13820 : return mbedtls_x509_crt_parse_der(chain, buf, buflen);
108 : #endif
109 : }
110 :
111 : /**
112 : * Construct a X509 object from DER-encoded certificate data.
113 : *
114 : * If cert is NULL, then return false.
115 : * If single_x509_cert is NULL, then return false.
116 : *
117 : * @param[in] cert Pointer to the DER-encoded certificate data.
118 : * @param[in] cert_size The size of certificate data in bytes.
119 : * @param[out] single_x509_cert The generated X509 object.
120 : *
121 : * @retval true The X509 object generation succeeded.
122 : * @retval false The operation failed.
123 : *
124 : **/
125 6 : bool libspdm_x509_construct_certificate(const uint8_t *cert, size_t cert_size,
126 : uint8_t **single_x509_cert)
127 : {
128 : mbedtls_x509_crt *mbedtls_cert;
129 : int ret;
130 :
131 6 : if (cert == NULL || single_x509_cert == NULL || cert_size == 0) {
132 0 : return false;
133 : }
134 :
135 6 : mbedtls_cert = allocate_pool(sizeof(mbedtls_x509_crt));
136 6 : if (mbedtls_cert == NULL) {
137 0 : return false;
138 : }
139 :
140 6 : mbedtls_x509_crt_init(mbedtls_cert);
141 :
142 6 : *single_x509_cert = (uint8_t *)(void *)mbedtls_cert;
143 6 : ret = wrapper_mbedtls_x509_crt_parse_der(mbedtls_cert, cert, cert_size);
144 :
145 6 : return ret == 0;
146 : }
147 :
148 0 : static bool libspdm_x509_construct_certificate_stack_v(uint8_t **x509_stack,
149 : va_list args)
150 : {
151 : uint8_t *cert;
152 : size_t cert_size;
153 : int ret;
154 :
155 0 : if (x509_stack == NULL) {
156 0 : return false;
157 : }
158 :
159 0 : ret = 0;
160 0 : mbedtls_x509_crt *crt = (mbedtls_x509_crt *)*x509_stack;
161 0 : if (crt == NULL) {
162 0 : crt = allocate_pool(sizeof(mbedtls_x509_crt));
163 0 : if (crt == NULL) {
164 0 : return false;
165 : }
166 0 : mbedtls_x509_crt_init(crt);
167 0 : *x509_stack = (uint8_t *)crt;
168 : }
169 :
170 : for (;;) {
171 :
172 : /* If cert is NULL, then it is the end of the list.*/
173 :
174 0 : cert = va_arg(args, uint8_t *);
175 0 : if (cert == NULL) {
176 0 : break;
177 : }
178 :
179 0 : cert_size = va_arg(args, size_t);
180 0 : if (cert_size == 0) {
181 0 : break;
182 : }
183 :
184 0 : ret = wrapper_mbedtls_x509_crt_parse_der(crt, cert, cert_size);
185 :
186 0 : if (ret != 0) {
187 0 : break;
188 : }
189 : }
190 0 : return ret == 0;
191 : }
192 :
193 : /**
194 : * Construct a X509 stack object from a list of DER-encoded certificate data.
195 : *
196 : * If x509_stack is NULL, then return false.
197 : *
198 : * @param[in, out] x509_stack On input, pointer to an existing or NULL X509 stack object.
199 : * On output, pointer to the X509 stack object with new
200 : * inserted X509 certificate.
201 : * @param ... A list of DER-encoded single certificate data followed
202 : * by certificate size. A NULL terminates the list. The
203 : * pairs are the arguments to libspdm_x509_construct_certificate().
204 : *
205 : * @retval true The X509 stack construction succeeded.
206 : * @retval false The construction operation failed.
207 : *
208 : **/
209 0 : bool libspdm_x509_construct_certificate_stack(uint8_t **x509_stack, ...)
210 : {
211 : va_list args;
212 : bool result;
213 :
214 0 : va_start(args, x509_stack);
215 0 : result = libspdm_x509_construct_certificate_stack_v(x509_stack, args);
216 0 : va_end(args);
217 0 : return result;
218 : }
219 :
220 : /**
221 : * Release the specified X509 object.
222 : *
223 : * If x509_cert is NULL, then return early.
224 : *
225 : * @param[in] x509_cert Pointer to the X509 object to be released.
226 : *
227 : **/
228 0 : void libspdm_x509_free(void *x509_cert)
229 : {
230 0 : if (x509_cert == NULL) {
231 0 : return;
232 : }
233 :
234 0 : mbedtls_x509_crt_free(x509_cert);
235 0 : free_pool(x509_cert);
236 : }
237 :
238 : /**
239 : * Release the specified X509 stack object.
240 : *
241 : * If x509_stack is NULL, then return early.
242 : *
243 : * @param[in] x509_stack Pointer to the X509 stack object to be released.
244 : *
245 : **/
246 0 : void libspdm_x509_stack_free(void *x509_stack)
247 : {
248 0 : if (x509_stack == NULL) {
249 0 : return;
250 : }
251 :
252 0 : mbedtls_x509_crt_free(x509_stack);
253 : }
254 :
255 : /**
256 : * Retrieve the tag and length of the tag.
257 : *
258 : * @param ptr The position in the ASN.1 data
259 : * @param end end of data
260 : * @param length The variable that will receive the length
261 : * @param tag The expected tag
262 : *
263 : * @retval true Get tag successful
264 : * @retval false Failed to get tag or tag not match
265 : **/
266 15026 : bool libspdm_asn1_get_tag(uint8_t **ptr, const uint8_t *end, size_t *length,
267 : uint32_t tag)
268 : {
269 15026 : if (mbedtls_asn1_get_tag(ptr, end, length, (int32_t)tag) == 0) {
270 14997 : return true;
271 : } else {
272 29 : return false;
273 : }
274 : }
275 :
276 : /**
277 : * Retrieve the subject bytes from one X.509 certificate.
278 : *
279 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
280 : * @param[in] cert_size size of the X509 certificate in bytes.
281 : * @param[out] cert_subject Pointer to the retrieved certificate subject bytes.
282 : * @param[in, out] subject_size The size in bytes of the cert_subject buffer on input,
283 : * and the size of buffer returned cert_subject on output.
284 : *
285 : * If cert is NULL, then return false.
286 : * If subject_size is NULL, then return false.
287 : *
288 : * @retval true If the subject_size is not equal 0. The certificate subject retrieved successfully.
289 : * @retval true If the subject_size is equal 0. The certificate parse successful. But the cert doesn't have subject.
290 : * @retval false If the subject_size is not equal 0. The certificate subject retrieved successfully.But the subject_size is too small for the result.
291 : * @retval false If the subject_size is equal 0. Invalid certificate.
292 : **/
293 841 : bool libspdm_x509_get_subject_name(const uint8_t *cert, size_t cert_size,
294 : uint8_t *cert_subject,
295 : size_t *subject_size)
296 : {
297 : mbedtls_x509_crt crt;
298 : int ret;
299 : bool status;
300 :
301 : /* Check input parameters.*/
302 841 : if (cert == NULL || cert == 0 || subject_size == NULL) {
303 0 : if (subject_size != NULL) {
304 0 : *subject_size = 0;
305 : }
306 0 : return false;
307 : }
308 :
309 841 : status = false;
310 :
311 841 : mbedtls_x509_crt_init(&crt);
312 :
313 841 : ret = wrapper_mbedtls_x509_crt_parse_der(&crt, cert, cert_size);
314 :
315 841 : if (ret == 0) {
316 841 : if (*subject_size < crt.subject_raw.len) {
317 782 : *subject_size = crt.subject_raw.len;
318 782 : status = false;
319 782 : goto cleanup;
320 : }
321 59 : if (cert_subject != NULL) {
322 59 : libspdm_copy_mem(cert_subject, *subject_size,
323 59 : crt.subject_raw.p, crt.subject_raw.len);
324 : }
325 59 : *subject_size = crt.subject_raw.len;
326 59 : status = true;
327 : } else {
328 0 : *subject_size = 0;
329 : }
330 :
331 841 : cleanup:
332 841 : mbedtls_x509_crt_free(&crt);
333 :
334 841 : return status;
335 : }
336 :
337 : bool
338 0 : libspdm_internal_x509_get_nid_name(mbedtls_x509_name *name, const uint8_t *oid,
339 : size_t oid_size, char *common_name,
340 : size_t *common_name_size)
341 : {
342 : const mbedtls_asn1_named_data *data;
343 :
344 0 : data = mbedtls_asn1_find_named_data(name, (const char *)oid, oid_size);
345 0 : if (data != NULL) {
346 0 : if (*common_name_size <= data->val.len) {
347 0 : *common_name_size = data->val.len + 1;
348 0 : return false;
349 : }
350 0 : if (common_name != NULL) {
351 0 : libspdm_copy_mem(common_name, *common_name_size, data->val.p, data->val.len);
352 0 : common_name[data->val.len] = '\0';
353 : }
354 0 : *common_name_size = data->val.len + 1;
355 0 : return true;
356 : } else {
357 0 : *common_name_size = 0;
358 0 : return false;
359 : }
360 : }
361 :
362 : bool
363 0 : libspdm_internal_x509_get_subject_nid_name(const uint8_t *cert, size_t cert_size,
364 : const uint8_t *oid, size_t oid_size,
365 : char *common_name,
366 : size_t *common_name_size)
367 : {
368 : mbedtls_x509_crt crt;
369 : int ret;
370 : mbedtls_x509_name *name;
371 : bool status;
372 :
373 0 : if (cert == NULL) {
374 0 : return false;
375 : }
376 :
377 0 : status = false;
378 :
379 0 : mbedtls_x509_crt_init(&crt);
380 :
381 0 : ret = wrapper_mbedtls_x509_crt_parse_der(&crt, cert, cert_size);
382 :
383 0 : if (ret == 0) {
384 0 : name = &(crt.subject);
385 0 : status = libspdm_internal_x509_get_nid_name(
386 : name, oid, oid_size, common_name, common_name_size);
387 : }
388 :
389 0 : mbedtls_x509_crt_free(&crt);
390 :
391 0 : return status;
392 : }
393 :
394 : bool
395 0 : libspdm_internal_x509_get_issuer_nid_name(const uint8_t *cert, size_t cert_size,
396 : const uint8_t *oid, size_t oid_size,
397 : char *common_name,
398 : size_t *common_name_size)
399 : {
400 : mbedtls_x509_crt crt;
401 : int ret;
402 : mbedtls_x509_name *name;
403 : bool status;
404 :
405 0 : if (cert == NULL) {
406 0 : return false;
407 : }
408 :
409 0 : status = false;
410 :
411 0 : mbedtls_x509_crt_init(&crt);
412 :
413 0 : ret = wrapper_mbedtls_x509_crt_parse_der(&crt, cert, cert_size);
414 :
415 0 : if (ret == 0) {
416 0 : name = &(crt.issuer);
417 0 : status = libspdm_internal_x509_get_nid_name(
418 : name, oid, oid_size, common_name, common_name_size);
419 : }
420 :
421 0 : mbedtls_x509_crt_free(&crt);
422 :
423 0 : return status;
424 : }
425 :
426 : /**
427 : * Retrieve the common name (CN) string from one X.509 certificate.
428 : *
429 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
430 : * @param[in] cert_size size of the X509 certificate in bytes.
431 : * @param[out] common_name buffer to contain the retrieved certificate common
432 : * name string. At most common_name_size bytes will be
433 : * written and the string will be null terminated. May be
434 : * NULL in order to determine the size buffer needed.
435 : * @param[in,out] common_name_size The size in bytes of the common_name buffer on input,
436 : * and the size of buffer returned common_name on output.
437 : * If common_name is NULL then the amount of space needed
438 : * in buffer (including the final null) is returned.
439 : *
440 : * @retval RETURN_SUCCESS The certificate common_name retrieved successfully.
441 : * @retval RETURN_INVALID_PARAMETER If cert is NULL.
442 : * If common_name_size is NULL.
443 : * If common_name is not NULL and *common_name_size is 0.
444 : * If Certificate is invalid.
445 : * @retval RETURN_NOT_FOUND If no common_name entry exists.
446 : * @retval RETURN_BUFFER_TOO_SMALL If the common_name is NULL. The required buffer size
447 : * (including the final null) is returned in the
448 : * common_name_size parameter.
449 : * @retval RETURN_UNSUPPORTED The operation is not supported.
450 : *
451 : **/
452 0 : bool libspdm_x509_get_common_name(const uint8_t *cert, size_t cert_size,
453 : char *common_name,
454 : size_t *common_name_size)
455 : {
456 0 : return libspdm_internal_x509_get_subject_nid_name(
457 : cert, cert_size, (const uint8_t *)m_libspdm_oid_common_name,
458 : sizeof(m_libspdm_oid_common_name), common_name, common_name_size);
459 : }
460 :
461 : /**
462 : * Retrieve the organization name (O) string from one X.509 certificate.
463 : *
464 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
465 : * @param[in] cert_size size of the X509 certificate in bytes.
466 : * @param[out] name_buffer buffer to contain the retrieved certificate organization
467 : * name string. At most name_buffer_size bytes will be
468 : * written and the string will be null terminated. May be
469 : * NULL in order to determine the size buffer needed.
470 : * @param[in,out] name_buffer_size The size in bytes of the name buffer on input,
471 : * and the size of buffer returned name on output.
472 : * If name_buffer is NULL then the amount of space needed
473 : * in buffer (including the final null) is returned.
474 : *
475 : * @retval RETURN_SUCCESS The certificate Organization name retrieved successfully.
476 : * @retval RETURN_INVALID_PARAMETER If cert is NULL.
477 : * If name_buffer_size is NULL.
478 : * If name_buffer is not NULL and *common_name_size is 0.
479 : * If Certificate is invalid.
480 : * @retval RETURN_NOT_FOUND If no Organization name entry exists.
481 : * @retval RETURN_BUFFER_TOO_SMALL If the name_buffer is NULL. The required buffer size
482 : * (including the final null) is returned in the
483 : * common_name_size parameter.
484 : * @retval RETURN_UNSUPPORTED The operation is not supported.
485 : *
486 : **/
487 : bool
488 0 : libspdm_x509_get_organization_name(const uint8_t *cert, size_t cert_size,
489 : char *name_buffer,
490 : size_t *name_buffer_size)
491 : {
492 0 : return libspdm_internal_x509_get_subject_nid_name(
493 : cert, cert_size, m_libspdm_oid_organization_name,
494 : sizeof(m_libspdm_oid_organization_name), name_buffer, name_buffer_size);
495 : }
496 :
497 : #if (LIBSPDM_RSA_SSA_SUPPORT) || (LIBSPDM_RSA_PSS_SUPPORT)
498 : /**
499 : * Retrieve the RSA public key from one DER-encoded X509 certificate.
500 : *
501 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
502 : * @param[in] cert_size size of the X509 certificate in bytes.
503 : * @param[out] rsa_context Pointer to newly generated RSA context which contain the retrieved
504 : * RSA public key component. Use libspdm_rsa_free() function to free the
505 : * resource.
506 : *
507 : * If cert is NULL, then return false.
508 : * If rsa_context is NULL, then return false.
509 : *
510 : * @retval true RSA public key was retrieved successfully.
511 : * @retval false Fail to retrieve RSA public key from X509 certificate.
512 : *
513 : **/
514 103 : bool libspdm_rsa_get_public_key_from_x509(const uint8_t *cert, size_t cert_size,
515 : void **rsa_context)
516 : {
517 : mbedtls_x509_crt crt;
518 : mbedtls_rsa_context *rsa;
519 : int ret;
520 :
521 103 : mbedtls_x509_crt_init(&crt);
522 :
523 103 : if (wrapper_mbedtls_x509_crt_parse_der(&crt, cert, cert_size) != 0) {
524 0 : return false;
525 : }
526 :
527 103 : if (mbedtls_pk_get_type(&crt.pk) != MBEDTLS_PK_RSA) {
528 6 : mbedtls_x509_crt_free(&crt);
529 6 : return false;
530 : }
531 :
532 97 : rsa = libspdm_rsa_new();
533 97 : if (rsa == NULL) {
534 0 : mbedtls_x509_crt_free(&crt);
535 0 : return false;
536 : }
537 97 : ret = mbedtls_rsa_copy(rsa, mbedtls_pk_rsa(crt.pk));
538 97 : if (ret != 0) {
539 0 : libspdm_rsa_free(rsa);
540 0 : mbedtls_x509_crt_free(&crt);
541 0 : return false;
542 : }
543 97 : mbedtls_x509_crt_free(&crt);
544 :
545 97 : *rsa_context = rsa;
546 97 : return true;
547 : }
548 : #endif /* (LIBSPDM_RSA_SSA_SUPPORT) || (LIBSPDM_RSA_PSS_SUPPORT) */
549 :
550 : /**
551 : * Retrieve the EC public key from one DER-encoded X509 certificate.
552 : *
553 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
554 : * @param[in] cert_size size of the X509 certificate in bytes.
555 : * @param[out] ec_context Pointer to newly generated EC DSA context which contain the retrieved
556 : * EC public key component. Use libspdm_ec_free() function to free the
557 : * resource.
558 : *
559 : * If cert is NULL, then return false.
560 : * If ec_context is NULL, then return false.
561 : *
562 : * @retval true EC public key was retrieved successfully.
563 : * @retval false Fail to retrieve EC public key from X509 certificate.
564 : *
565 : **/
566 941 : bool libspdm_ec_get_public_key_from_x509(const uint8_t *cert, size_t cert_size,
567 : void **ec_context)
568 : {
569 : mbedtls_x509_crt crt;
570 : mbedtls_ecdh_context *ecdh;
571 : int ret;
572 :
573 941 : mbedtls_x509_crt_init(&crt);
574 :
575 941 : if (wrapper_mbedtls_x509_crt_parse_der(&crt, cert, cert_size) != 0) {
576 0 : return false;
577 : }
578 :
579 941 : if (mbedtls_pk_get_type(&crt.pk) != MBEDTLS_PK_ECKEY) {
580 1 : mbedtls_x509_crt_free(&crt);
581 1 : return false;
582 : }
583 :
584 940 : ecdh = allocate_zero_pool(sizeof(mbedtls_ecdh_context));
585 940 : if (ecdh == NULL) {
586 0 : mbedtls_x509_crt_free(&crt);
587 0 : return false;
588 : }
589 940 : mbedtls_ecdh_init(ecdh);
590 :
591 940 : ret = mbedtls_ecdh_get_params(ecdh, mbedtls_pk_ec(crt.pk),
592 : MBEDTLS_ECDH_OURS);
593 940 : if (ret != 0) {
594 0 : mbedtls_ecdh_free(ecdh);
595 0 : free_pool(ecdh);
596 0 : mbedtls_x509_crt_free(&crt);
597 0 : return false;
598 : }
599 940 : mbedtls_x509_crt_free(&crt);
600 :
601 940 : *ec_context = ecdh;
602 940 : return true;
603 : }
604 :
605 : /**
606 : * Retrieve the Ed public key from one DER-encoded X509 certificate.
607 : *
608 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
609 : * @param[in] cert_size size of the X509 certificate in bytes.
610 : * @param[out] ecd_context Pointer to newly generated Ed DSA context which contain the retrieved
611 : * Ed public key component. Use libspdm_ecd_free() function to free the
612 : * resource.
613 : *
614 : * If cert is NULL, then return false.
615 : * If ecd_context is NULL, then return false.
616 : *
617 : * @retval true Ed public key was retrieved successfully.
618 : * @retval false Fail to retrieve Ed public key from X509 certificate.
619 : *
620 : **/
621 0 : bool libspdm_ecd_get_public_key_from_x509(const uint8_t *cert, size_t cert_size,
622 : void **ecd_context)
623 : {
624 0 : return false;
625 : }
626 :
627 : /**
628 : * Retrieve the sm2 public key from one DER-encoded X509 certificate.
629 : *
630 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
631 : * @param[in] cert_size size of the X509 certificate in bytes.
632 : * @param[out] sm2_context Pointer to newly generated sm2 context which contain the retrieved
633 : * sm2 public key component. Use sm2_free() function to free the
634 : * resource.
635 : *
636 : * If cert is NULL, then return false.
637 : * If ecd_context is NULL, then return false.
638 : *
639 : * @retval true sm2 public key was retrieved successfully.
640 : * @retval false Fail to retrieve sm2 public key from X509 certificate.
641 : *
642 : **/
643 0 : bool libspdm_sm2_get_public_key_from_x509(const uint8_t *cert, size_t cert_size,
644 : void **sm2_context)
645 : {
646 0 : return false;
647 : }
648 :
649 : /**
650 : * Verify one X509 certificate was issued by the trusted CA.
651 : *
652 : * @param[in] cert Pointer to the DER-encoded X509 certificate to be verified.
653 : * @param[in] cert_size size of the X509 certificate in bytes.
654 : * @param[in] ca_cert Pointer to the DER-encoded trusted CA certificate.
655 : * @param[in] ca_cert_size size of the CA Certificate in bytes.
656 : *
657 : * If cert is NULL, then return false.
658 : * If ca_cert is NULL, then return false.
659 : *
660 : * @retval true The certificate was issued by the trusted CA.
661 : * @retval false Invalid certificate or the certificate was not issued by the given
662 : * trusted CA.
663 : *
664 : **/
665 2417 : bool libspdm_x509_verify_cert(const uint8_t *cert, size_t cert_size,
666 : const uint8_t *ca_cert, size_t ca_cert_size)
667 : {
668 : int ret;
669 : mbedtls_x509_crt ca, end;
670 2417 : uint32_t v_flag = 0;
671 2417 : mbedtls_x509_crt_profile profile = { 0 };
672 :
673 2417 : if (cert == NULL || ca_cert == NULL) {
674 0 : return false;
675 : }
676 :
677 2417 : libspdm_copy_mem(&profile, sizeof(profile),
678 : &mbedtls_x509_crt_profile_default,
679 : sizeof(mbedtls_x509_crt_profile));
680 :
681 2417 : mbedtls_x509_crt_init(&ca);
682 2417 : mbedtls_x509_crt_init(&end);
683 :
684 2417 : ret = wrapper_mbedtls_x509_crt_parse_der(&ca, ca_cert, ca_cert_size);
685 :
686 2417 : if (ret == 0) {
687 2417 : ret = wrapper_mbedtls_x509_crt_parse_der(&end, cert, cert_size);
688 : }
689 :
690 2417 : if (ret == 0) {
691 2417 : ret = mbedtls_x509_crt_verify_with_profile(
692 : &end, &ca, NULL, &profile, NULL, &v_flag, NULL, NULL);
693 : }
694 :
695 2417 : mbedtls_x509_crt_free(&ca);
696 2417 : mbedtls_x509_crt_free(&end);
697 :
698 2417 : return ret == 0;
699 : }
700 :
701 : /**
702 : * Verify one X509 certificate was issued by the trusted CA.
703 : *
704 : * @param[in] cert_chain One or more ASN.1 DER-encoded X.509 certificates
705 : * where the first certificate is signed by the Root
706 : * Certificate or is the Root Certificate itself. and
707 : * subsequent certificate is signed by the preceding
708 : * certificate.
709 : * @param[in] cert_chain_length Total length of the certificate chain, in bytes.
710 : *
711 : * @param[in] root_cert Trusted Root Certificate buffer
712 : *
713 : * @param[in] root_cert_length Trusted Root Certificate buffer length
714 : *
715 : * @retval true All certificates were issued by the first certificate in X509Certchain.
716 : * @retval false Invalid certificate or the certificate was not issued by the given
717 : * trusted CA.
718 : **/
719 759 : bool libspdm_x509_verify_cert_chain(const uint8_t *root_cert, size_t root_cert_length,
720 : const uint8_t *cert_chain, size_t cert_chain_length)
721 : {
722 : size_t asn1_len;
723 : size_t preceding_cert_len;
724 : const uint8_t *preceding_cert;
725 : size_t current_cert_len;
726 : const unsigned char *current_cert;
727 : const unsigned char *tmp_ptr;
728 : int ret;
729 : bool verify_flag;
730 :
731 759 : verify_flag = false;
732 759 : preceding_cert = root_cert;
733 759 : preceding_cert_len = root_cert_length;
734 :
735 759 : current_cert = (const unsigned char *)cert_chain;
736 :
737 :
738 : /* Get Current certificate from certificates buffer and Verify with preceding cert*/
739 :
740 : do {
741 3172 : tmp_ptr = current_cert;
742 3172 : ret = mbedtls_asn1_get_tag(
743 3172 : &tmp_ptr, cert_chain + cert_chain_length, &asn1_len,
744 : MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
745 3172 : if (ret != 0) {
746 756 : if (current_cert < cert_chain + cert_chain_length) {
747 2 : verify_flag = false;
748 : }
749 756 : break;
750 : }
751 :
752 2416 : current_cert_len = asn1_len + (tmp_ptr - current_cert);
753 :
754 2416 : if (current_cert + current_cert_len > cert_chain + cert_chain_length) {
755 0 : verify_flag = false;
756 0 : break;
757 : }
758 :
759 2416 : if (libspdm_x509_verify_cert(current_cert, current_cert_len,
760 : preceding_cert,
761 2416 : preceding_cert_len) == false) {
762 3 : verify_flag = false;
763 3 : break;
764 : } else {
765 2413 : verify_flag = true;
766 : }
767 :
768 :
769 : /* Save preceding certificate*/
770 :
771 2413 : preceding_cert = current_cert;
772 2413 : preceding_cert_len = current_cert_len;
773 :
774 :
775 : /* Move current certificate to next;*/
776 :
777 2413 : current_cert = current_cert + current_cert_len;
778 : } while (true);
779 :
780 759 : return verify_flag;
781 : }
782 :
783 : /**
784 : * Get one X509 certificate from cert_chain.
785 : *
786 : * @param[in] cert_chain One or more ASN.1 DER-encoded X.509 certificates
787 : * where the first certificate is signed by the Root
788 : * Certificate or is the Root Certificate itself. and
789 : * subsequent certificate is signed by the preceding
790 : * certificate.
791 : * @param[in] cert_chain_length Total length of the certificate chain, in bytes.
792 : *
793 : * @param[in] cert_index index of certificate.
794 : *
795 : * @param[out] cert The certificate at the index of cert_chain.
796 : * @param[out] cert_length The length certificate at the index of cert_chain.
797 : *
798 : * @retval true Success.
799 : * @retval false Failed to get certificate from certificate chain.
800 : **/
801 2548 : bool libspdm_x509_get_cert_from_cert_chain(const uint8_t *cert_chain,
802 : size_t cert_chain_length,
803 : const int32_t cert_index, const uint8_t **cert,
804 : size_t *cert_length)
805 : {
806 : size_t asn1_len;
807 : int32_t current_index;
808 : size_t current_cert_len;
809 : const unsigned char *current_cert;
810 : const unsigned char *tmp_ptr;
811 : int ret;
812 :
813 2548 : current_cert_len = 0;
814 :
815 : /* Check input parameters.*/
816 :
817 2548 : if ((cert_chain == NULL) || (cert == NULL) || (cert_index < -1) ||
818 : (cert_length == NULL)) {
819 0 : return false;
820 : }
821 :
822 2548 : current_cert = (const unsigned char *)cert_chain;
823 2548 : current_index = -1;
824 :
825 :
826 : /* Traverse the certificate chain*/
827 :
828 : while (true) {
829 :
830 : /* Get asn1 tag len*/
831 :
832 5772 : tmp_ptr = current_cert;
833 5772 : ret = mbedtls_asn1_get_tag(
834 5772 : &tmp_ptr, cert_chain + cert_chain_length, &asn1_len,
835 : MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
836 5772 : if (ret != 0) {
837 1016 : break;
838 : }
839 :
840 4756 : current_cert_len = asn1_len + (tmp_ptr - current_cert);
841 4756 : if (current_cert + current_cert_len > cert_chain + cert_chain_length) {
842 0 : return false;
843 : }
844 :
845 4756 : current_index++;
846 :
847 4756 : if (current_index == cert_index) {
848 1532 : *cert = current_cert;
849 1532 : *cert_length = current_cert_len;
850 1532 : return true;
851 : }
852 :
853 :
854 : /* Move to next*/
855 :
856 3224 : current_cert = current_cert + current_cert_len;
857 : }
858 :
859 :
860 : /* If cert_index is -1, Return the last certificate*/
861 :
862 1016 : if (cert_index == -1 && current_index >= 0) {
863 1016 : *cert = current_cert - current_cert_len;
864 1016 : *cert_length = current_cert_len;
865 1016 : return true;
866 : }
867 :
868 0 : return false;
869 : }
870 :
871 : /**
872 : * Retrieve the TBSCertificate from one given X.509 certificate.
873 : *
874 : * @param[in] cert Pointer to the given DER-encoded X509 certificate.
875 : * @param[in] cert_size size of the X509 certificate in bytes.
876 : * @param[out] tbs_cert DER-Encoded to-Be-Signed certificate.
877 : * @param[out] tbs_cert_size size of the TBS certificate in bytes.
878 : *
879 : * If cert is NULL, then return false.
880 : * If tbs_cert is NULL, then return false.
881 : * If tbs_cert_size is NULL, then return false.
882 : *
883 : * @retval true The TBSCertificate was retrieved successfully.
884 : * @retval false Invalid X.509 certificate.
885 : *
886 : **/
887 0 : bool libspdm_x509_get_tbs_cert(const uint8_t *cert, size_t cert_size,
888 : uint8_t **tbs_cert, size_t *tbs_cert_size)
889 : {
890 0 : return false;
891 : }
892 :
893 : /**
894 : * Retrieve the version from one X.509 certificate.
895 : *
896 : * If cert is NULL, then return false.
897 : * If cert_size is 0, then return false.
898 : * If this interface is not supported, then return false.
899 : *
900 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
901 : * @param[in] cert_size size of the X509 certificate in bytes.
902 : * @param[out] version Pointer to the retrieved version integer.
903 : *
904 : * @retval RETURN_SUCCESS The certificate version retrieved successfully.
905 : * @retval RETURN_INVALID_PARAMETER If cert is NULL or cert_size is Zero.
906 : * @retval RETURN_UNSUPPORTED The operation is not supported.
907 : *
908 : **/
909 784 : bool libspdm_x509_get_version(const uint8_t *cert, size_t cert_size,
910 : size_t *version)
911 : {
912 : mbedtls_x509_crt crt;
913 : int ret;
914 : bool status;
915 :
916 784 : if (cert == NULL) {
917 0 : return false;
918 : }
919 :
920 784 : status = false;
921 :
922 784 : mbedtls_x509_crt_init(&crt);
923 :
924 784 : ret = wrapper_mbedtls_x509_crt_parse_der(&crt, cert, cert_size);
925 :
926 784 : if (ret == 0) {
927 784 : *version = crt.version - 1;
928 784 : status = true;
929 : }
930 :
931 784 : mbedtls_x509_crt_free(&crt);
932 :
933 784 : return status;
934 : }
935 :
936 : /**
937 : * Retrieve the serialNumber from one X.509 certificate.
938 : *
939 : * If cert is NULL, then return false.
940 : * If cert_size is 0, then return false.
941 : * If this interface is not supported, then return false.
942 : *
943 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
944 : * @param[in] cert_size size of the X509 certificate in bytes.
945 : * @param[out] serial_number Pointer to the retrieved certificate serial_number bytes.
946 : * @param[in, out] serial_number_size The size in bytes of the serial_number buffer on input,
947 : * and the size of buffer returned serial_number on output.
948 : *
949 : * @retval RETURN_SUCCESS The certificate serialNumber retrieved successfully.
950 : * @retval RETURN_INVALID_PARAMETER If cert is NULL or cert_size is Zero.
951 : * If serial_number_size is NULL.
952 : * If Certificate is invalid.
953 : * @retval RETURN_NOT_FOUND If no serial_number exists.
954 : * @retval RETURN_BUFFER_TOO_SMALL If the serial_number is NULL. The required buffer size
955 : * (including the final null) is returned in the
956 : * serial_number_size parameter.
957 : * @retval RETURN_UNSUPPORTED The operation is not supported.
958 : **/
959 784 : bool libspdm_x509_get_serial_number(const uint8_t *cert, size_t cert_size,
960 : uint8_t *serial_number,
961 : size_t *serial_number_size)
962 : {
963 : mbedtls_x509_crt crt;
964 : int ret;
965 : bool status;
966 :
967 784 : if (cert == NULL) {
968 0 : return false;
969 : }
970 :
971 784 : status = false;
972 :
973 784 : mbedtls_x509_crt_init(&crt);
974 :
975 784 : ret = wrapper_mbedtls_x509_crt_parse_der(&crt, cert, cert_size);
976 :
977 784 : if (ret == 0) {
978 784 : if (*serial_number_size <= crt.serial.len) {
979 784 : *serial_number_size = crt.serial.len + 1;
980 784 : status = false;
981 784 : goto cleanup;
982 : }
983 0 : if (serial_number != NULL) {
984 0 : libspdm_copy_mem(serial_number, *serial_number_size, crt.serial.p, crt.serial.len);
985 0 : serial_number[crt.serial.len] = '\0';
986 : }
987 0 : *serial_number_size = crt.serial.len + 1;
988 0 : status = true;
989 : }
990 0 : cleanup:
991 784 : mbedtls_x509_crt_free(&crt);
992 :
993 784 : return status;
994 : }
995 :
996 : /**
997 : * Retrieve the issuer bytes from one X.509 certificate.
998 : *
999 : * If cert is NULL, then return false.
1000 : * If issuer_size is NULL, then return false.
1001 : * If this interface is not supported, then return false.
1002 : *
1003 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
1004 : * @param[in] cert_size size of the X509 certificate in bytes.
1005 : * @param[out] cert_issuer Pointer to the retrieved certificate subject bytes.
1006 : * @param[in, out] issuer_size The size in bytes of the cert_issuer buffer on input,
1007 : * and the size of buffer returned cert_issuer on output.
1008 : *
1009 : * @retval true If the issuer_size is not equal 0. The certificate issuer retrieved successfully.
1010 : * @retval true If the issuer_size is equal 0. The certificate parse successful. But the cert doesn't have issuer.
1011 : * @retval false If the issuer_size is not equal 0. The certificate issuer retrieved successfully. But the issuer_size is too small for the result.
1012 : * @retval false If the issuer_size is equal 0. Invalid certificate.
1013 : *
1014 : **/
1015 841 : bool libspdm_x509_get_issuer_name(const uint8_t *cert, size_t cert_size,
1016 : uint8_t *cert_issuer,
1017 : size_t *issuer_size)
1018 : {
1019 : mbedtls_x509_crt crt;
1020 : int ret;
1021 : bool status;
1022 :
1023 : /* Check input parameters.*/
1024 841 : if (cert == NULL || cert_size == 0 || issuer_size == NULL) {
1025 0 : if (issuer_size != NULL) {
1026 0 : *issuer_size = 0;
1027 : }
1028 0 : return false;
1029 : }
1030 :
1031 841 : status = false;
1032 :
1033 841 : mbedtls_x509_crt_init(&crt);
1034 :
1035 841 : ret = wrapper_mbedtls_x509_crt_parse_der(&crt, cert, cert_size);
1036 :
1037 841 : if (ret == 0) {
1038 841 : if (*issuer_size < crt.issuer_raw.len) {
1039 782 : *issuer_size = crt.issuer_raw.len;
1040 782 : status = false;
1041 782 : goto cleanup;
1042 : }
1043 59 : if (cert_issuer != NULL) {
1044 59 : libspdm_copy_mem(cert_issuer, *issuer_size, crt.issuer_raw.p, crt.issuer_raw.len);
1045 : }
1046 59 : *issuer_size = crt.issuer_raw.len;
1047 59 : status = true;
1048 : } else {
1049 0 : *issuer_size = 0;
1050 : }
1051 :
1052 841 : cleanup:
1053 841 : mbedtls_x509_crt_free(&crt);
1054 :
1055 841 : return status;
1056 : }
1057 :
1058 : /**
1059 : * Retrieve the issuer common name (CN) string from one X.509 certificate.
1060 : *
1061 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
1062 : * @param[in] cert_size size of the X509 certificate in bytes.
1063 : * @param[out] common_name buffer to contain the retrieved certificate issuer common
1064 : * name string. At most common_name_size bytes will be
1065 : * written and the string will be null terminated. May be
1066 : * NULL in order to determine the size buffer needed.
1067 : * @param[in,out] common_name_size The size in bytes of the common_name buffer on input,
1068 : * and the size of buffer returned common_name on output.
1069 : * If common_name is NULL then the amount of space needed
1070 : * in buffer (including the final null) is returned.
1071 : *
1072 : * @retval RETURN_SUCCESS The certificate Issuer common_name retrieved successfully.
1073 : * @retval RETURN_INVALID_PARAMETER If cert is NULL.
1074 : * If common_name_size is NULL.
1075 : * If common_name is not NULL and *common_name_size is 0.
1076 : * If Certificate is invalid.
1077 : * @retval RETURN_NOT_FOUND If no common_name entry exists.
1078 : * @retval RETURN_BUFFER_TOO_SMALL If the common_name is NULL. The required buffer size
1079 : * (including the final null) is returned in the
1080 : * common_name_size parameter.
1081 : * @retval RETURN_UNSUPPORTED The operation is not supported.
1082 : *
1083 : **/
1084 : bool
1085 0 : libspdm_x509_get_issuer_common_name(const uint8_t *cert, size_t cert_size,
1086 : char *common_name,
1087 : size_t *common_name_size)
1088 : {
1089 0 : return libspdm_internal_x509_get_issuer_nid_name(cert, cert_size,
1090 : m_libspdm_oid_common_name,
1091 : sizeof(m_libspdm_oid_common_name),
1092 : common_name, common_name_size);
1093 : }
1094 :
1095 : /**
1096 : * Retrieve the issuer organization name (O) string from one X.509 certificate.
1097 : *
1098 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
1099 : * @param[in] cert_size size of the X509 certificate in bytes.
1100 : * @param[out] name_buffer buffer to contain the retrieved certificate issuer organization
1101 : * name string. At most name_buffer_size bytes will be
1102 : * written and the string will be null terminated. May be
1103 : * NULL in order to determine the size buffer needed.
1104 : * @param[in,out] name_buffer_size The size in bytes of the name buffer on input,
1105 : * and the size of buffer returned name on output.
1106 : * If name_buffer is NULL then the amount of space needed
1107 : * in buffer (including the final null) is returned.
1108 : *
1109 : * @retval RETURN_SUCCESS The certificate issuer Organization name retrieved successfully.
1110 : * @retval RETURN_INVALID_PARAMETER If cert is NULL.
1111 : * If name_buffer_size is NULL.
1112 : * If name_buffer is not NULL and *common_name_size is 0.
1113 : * If Certificate is invalid.
1114 : * @retval RETURN_NOT_FOUND If no Organization name entry exists.
1115 : * @retval RETURN_BUFFER_TOO_SMALL If the name_buffer is NULL. The required buffer size
1116 : * (including the final null) is returned in the
1117 : * common_name_size parameter.
1118 : * @retval RETURN_UNSUPPORTED The operation is not supported.
1119 : *
1120 : **/
1121 : bool
1122 0 : libspdm_x509_get_issuer_orgnization_name(const uint8_t *cert, size_t cert_size,
1123 : char *name_buffer,
1124 : size_t *name_buffer_size)
1125 : {
1126 0 : return libspdm_internal_x509_get_issuer_nid_name(
1127 : cert, cert_size, m_libspdm_oid_organization_name,
1128 : sizeof(m_libspdm_oid_organization_name), name_buffer, name_buffer_size);
1129 : }
1130 :
1131 : /**
1132 : * Retrieve the signature algorithm from one X.509 certificate.
1133 : *
1134 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
1135 : * @param[in] cert_size size of the X509 certificate in bytes.
1136 : * @param[out] oid signature algorithm Object identifier buffer.
1137 : * @param[in,out] oid_size signature algorithm Object identifier buffer size
1138 : *
1139 : * @retval true if the oid_size is equal 0, the cert parse successfully, but cert doesn't have signature algo.
1140 : * @retval true if the oid_size is not equal 0, the cert parse and get signature algo successfully.
1141 : * @retval false if the oid_size is equal 0, the cert parse failed.
1142 : * @retval false if the oid_size is not equal 0, the cert parse and get signature algo successfully, but the input buffer size is small.
1143 : **/
1144 784 : bool libspdm_x509_get_signature_algorithm(const uint8_t *cert,
1145 : size_t cert_size, uint8_t *oid,
1146 : size_t *oid_size)
1147 : {
1148 : mbedtls_x509_crt crt;
1149 : int ret;
1150 : bool status;
1151 :
1152 : /* Check input parameters.*/
1153 784 : if (cert == NULL || cert_size == 0 || oid_size == NULL) {
1154 0 : if (oid_size != NULL) {
1155 0 : *oid_size = 0;
1156 : }
1157 0 : return false;
1158 : }
1159 :
1160 784 : status = false;
1161 :
1162 784 : mbedtls_x509_crt_init(&crt);
1163 :
1164 784 : ret = wrapper_mbedtls_x509_crt_parse_der(&crt, cert, cert_size);
1165 :
1166 784 : if (ret == 0) {
1167 784 : if (*oid_size < crt.sig_oid.len) {
1168 784 : *oid_size = crt.serial.len;
1169 784 : status = false;
1170 784 : goto cleanup;
1171 : }
1172 0 : if (oid != NULL) {
1173 0 : libspdm_copy_mem(oid, *oid_size, crt.sig_oid.p, crt.sig_oid.len);
1174 : }
1175 0 : *oid_size = crt.sig_oid.len;
1176 0 : status = true;
1177 : } else {
1178 0 : *oid_size = 0;
1179 : }
1180 :
1181 784 : cleanup:
1182 784 : mbedtls_x509_crt_free(&crt);
1183 :
1184 784 : return status;
1185 : }
1186 :
1187 : /**
1188 : * Find first Extension data match with given OID
1189 : *
1190 : * @param[in] start Pointer to the DER-encoded extensions data
1191 : * @param[in] end extensions data size in bytes
1192 : * @param[in ] oid OID for match
1193 : * @param[in ] oid_size OID size in bytes
1194 : * @param[out] find_extension_data output matched extension data.
1195 : * @param[out] find_extension_data_len matched extension data size.
1196 : *
1197 : **/
1198 : static bool
1199 2344 : libspdm_internal_x509_find_extension_data(uint8_t *start, uint8_t *end, const uint8_t *oid,
1200 : size_t oid_size, uint8_t **find_extension_data,
1201 : size_t *find_extension_data_len)
1202 : {
1203 : uint8_t *ptr;
1204 : uint8_t *extension_ptr;
1205 : size_t obj_len;
1206 : int ret;
1207 : bool status;
1208 : size_t find_extension_len;
1209 : size_t header_len;
1210 :
1211 : /*If no Extension entry match oid*/
1212 2344 : status = false;
1213 2344 : ptr = start;
1214 :
1215 2344 : ret = 0;
1216 :
1217 : while (true) {
1218 : /*
1219 : * Extension ::= SEQUENCE {
1220 : * extnID OBJECT IDENTIFIER,
1221 : * critical bool DEFAULT false,
1222 : * extnValue OCTET STRING }
1223 : */
1224 9407 : extension_ptr = ptr;
1225 9407 : ret = mbedtls_asn1_get_tag(&ptr, end, &obj_len,
1226 : MBEDTLS_ASN1_CONSTRUCTED |
1227 : MBEDTLS_ASN1_SEQUENCE);
1228 9407 : if (ret == 0) {
1229 9392 : header_len = (size_t)(ptr - extension_ptr);
1230 9392 : find_extension_len = obj_len;
1231 : /* Get Object Identifier*/
1232 9392 : ret = mbedtls_asn1_get_tag(&ptr, end, &obj_len,
1233 : MBEDTLS_ASN1_OID);
1234 : } else {
1235 15 : break;
1236 : }
1237 :
1238 9392 : if (ret == 0 && libspdm_consttime_is_mem_equal(ptr, oid, oid_size)) {
1239 2329 : ptr += obj_len;
1240 :
1241 2329 : ret = mbedtls_asn1_get_tag(&ptr, end, &obj_len,
1242 : MBEDTLS_ASN1_BOOLEAN);
1243 2329 : if (ret == 0) {
1244 1551 : ptr += obj_len;
1245 : }
1246 :
1247 2329 : ret = mbedtls_asn1_get_tag(&ptr, end, &obj_len,
1248 : MBEDTLS_ASN1_OCTET_STRING);
1249 : } else {
1250 7063 : ret = 1;
1251 : }
1252 :
1253 9392 : if (ret == 0) {
1254 2329 : *find_extension_data = ptr;
1255 2329 : *find_extension_data_len = obj_len;
1256 2329 : status = true;
1257 2329 : break;
1258 : }
1259 :
1260 : /* move to next*/
1261 7063 : ptr = extension_ptr + header_len + find_extension_len;
1262 7063 : ret = 0;
1263 : }
1264 :
1265 2344 : return status;
1266 : }
1267 :
1268 : /**
1269 : * Retrieve Extension data from one X.509 certificate.
1270 : *
1271 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
1272 : * @param[in] cert_size size of the X509 certificate in bytes.
1273 : * @param[in] oid Object identifier buffer
1274 : * @param[in] oid_size Object identifier buffer size
1275 : * @param[out] extension_data Extension bytes.
1276 : * @param[in, out] extension_data_size Extension bytes size.
1277 : *
1278 : * @retval true If the returned extension_data_size == 0, it means that cert and oid are valid, but the oid extension is not found;
1279 : * If the returned extension_data_size != 0, it means that cert and oid are valid, and the oid extension is found;
1280 : * @retval false If the returned extension_data_size == 0, it means that cert or oid are invalid;
1281 : * If the returned extension_data_size != 0, it means that cert and oid are valid, and the oid extension is found,
1282 : * but the store buffer is too small.
1283 : **/
1284 2344 : bool libspdm_x509_get_extension_data(const uint8_t *cert, size_t cert_size,
1285 : const uint8_t *oid, size_t oid_size,
1286 : uint8_t *extension_data,
1287 : size_t *extension_data_size)
1288 : {
1289 : mbedtls_x509_crt crt;
1290 : int ret;
1291 : bool status;
1292 : uint8_t *ptr;
1293 : uint8_t *end;
1294 : size_t obj_len;
1295 :
1296 2344 : ptr = NULL;
1297 2344 : end = NULL;
1298 2344 : obj_len = 0;
1299 :
1300 2344 : if (cert == NULL || cert_size == 0 || oid == NULL || oid_size == 0 ||
1301 : extension_data_size == NULL) {
1302 0 : if (extension_data_size != NULL) {
1303 0 : *extension_data_size = 0;
1304 : }
1305 0 : return false;
1306 : }
1307 :
1308 2344 : status = false;
1309 :
1310 2344 : mbedtls_x509_crt_init(&crt);
1311 :
1312 2344 : ret = wrapper_mbedtls_x509_crt_parse_der(&crt, cert, cert_size);
1313 :
1314 2344 : if (ret == 0) {
1315 2344 : ptr = crt.v3_ext.p;
1316 2344 : end = crt.v3_ext.p + crt.v3_ext.len;
1317 2344 : ret = mbedtls_asn1_get_tag(&ptr, end, &obj_len,
1318 : MBEDTLS_ASN1_CONSTRUCTED |
1319 : MBEDTLS_ASN1_SEQUENCE);
1320 : }
1321 :
1322 2344 : if (ret == 0) {
1323 2344 : status = libspdm_internal_x509_find_extension_data(
1324 : ptr, end, oid, oid_size, &ptr, &obj_len);
1325 2344 : if (!status) {
1326 15 : status = true;
1327 15 : *extension_data_size = 0;
1328 15 : goto cleanup;
1329 : }
1330 : }
1331 :
1332 2329 : if (status) {
1333 2329 : if (*extension_data_size < obj_len) {
1334 6 : *extension_data_size = obj_len;
1335 6 : status = false;
1336 6 : goto cleanup;
1337 : }
1338 2323 : if (oid != NULL) {
1339 2323 : libspdm_copy_mem(extension_data, *extension_data_size, ptr, obj_len);
1340 : }
1341 2323 : *extension_data_size = obj_len;
1342 : } else {
1343 0 : *extension_data_size = 0;
1344 : }
1345 :
1346 2344 : cleanup:
1347 2344 : mbedtls_x509_crt_free(&crt);
1348 :
1349 2344 : return status;
1350 : }
1351 :
1352 : /**
1353 : * Retrieve the Validity from one X.509 certificate
1354 : *
1355 : * If cert is NULL, then return false.
1356 : * If CertIssuerSize is NULL, then return false.
1357 : * If this interface is not supported, then return false.
1358 : *
1359 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
1360 : * @param[in] cert_size size of the X509 certificate in bytes.
1361 : * @param[out] from notBefore Pointer to date_time object.
1362 : * @param[in,out] from_size notBefore date_time object size.
1363 : * @param[out] to notAfter Pointer to date_time object.
1364 : * @param[in,out] to_size notAfter date_time object size.
1365 : *
1366 : * Note: libspdm_x509_compare_date_time to compare date_time object
1367 : * x509SetDateTime to get a date_time object from a date_time_str
1368 : *
1369 : * @retval true The certificate Validity retrieved successfully.
1370 : * @retval false Invalid certificate, or Validity retrieve failed.
1371 : * @retval false This interface is not supported.
1372 : **/
1373 782 : bool libspdm_x509_get_validity(const uint8_t *cert, size_t cert_size,
1374 : uint8_t *from, size_t *from_size, uint8_t *to,
1375 : size_t *to_size)
1376 : {
1377 : mbedtls_x509_crt crt;
1378 : int ret;
1379 : bool status;
1380 : size_t t_size;
1381 : size_t f_size;
1382 : mbedtls_x509_time zero_time;
1383 :
1384 : /* Check input parameters.*/
1385 782 : if (cert == NULL || from_size == NULL || to_size == NULL ||
1386 : cert_size == 0) {
1387 0 : if (from_size != NULL) {
1388 0 : *from_size = 0;
1389 : }
1390 0 : if (to_size != NULL) {
1391 0 : *to_size = 0;
1392 : }
1393 0 : return false;
1394 : }
1395 :
1396 782 : status = false;
1397 :
1398 782 : mbedtls_x509_crt_init(&crt);
1399 782 : libspdm_zero_mem(&zero_time, sizeof(mbedtls_x509_time));
1400 :
1401 782 : ret = wrapper_mbedtls_x509_crt_parse_der(&crt, cert, cert_size);
1402 :
1403 782 : if (ret == 0) {
1404 782 : f_size = sizeof(mbedtls_x509_time);
1405 782 : if ((libspdm_consttime_is_mem_equal(&zero_time, &(crt.valid_from), f_size)) &&
1406 0 : (libspdm_consttime_is_mem_equal(&zero_time, &(crt.valid_to), f_size))) {
1407 0 : *from_size = 0;
1408 0 : *to_size = 0;
1409 0 : status = true;
1410 0 : goto done;
1411 : }
1412 :
1413 782 : if (*from_size < f_size) {
1414 0 : *from_size = f_size;
1415 0 : goto done;
1416 : }
1417 782 : if (from != NULL) {
1418 782 : libspdm_copy_mem(from, *from_size, &(crt.valid_from), f_size);
1419 : }
1420 782 : *from_size = f_size;
1421 :
1422 782 : t_size = sizeof(mbedtls_x509_time);
1423 782 : if (*to_size < t_size) {
1424 0 : *to_size = t_size;
1425 0 : goto done;
1426 : }
1427 782 : if (to != NULL) {
1428 782 : libspdm_copy_mem(to, *to_size, &(crt.valid_to),
1429 : sizeof(mbedtls_x509_time));
1430 : }
1431 782 : *to_size = t_size;
1432 782 : status = true;
1433 : } else {
1434 0 : *from_size = 0;
1435 0 : *to_size = 0;
1436 : }
1437 :
1438 782 : done:
1439 782 : mbedtls_x509_crt_free(&crt);
1440 :
1441 782 : return status;
1442 : }
1443 :
1444 : /**
1445 : * Retrieve the key usage from one X.509 certificate.
1446 : *
1447 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
1448 : * @param[in] cert_size size of the X509 certificate in bytes.
1449 : * @param[out] usage key usage (LIBSPDM_CRYPTO_X509_KU_*)
1450 : *
1451 : * @retval true if the usage is no equal 0. The certificate key usage retrieved successfully.
1452 : * @retval true if the usage is equal 0. The certificate parse successfully, but the cert doesn't have key usage.
1453 : * @retval false Invalid certificate, or usage is NULL.
1454 : **/
1455 776 : bool libspdm_x509_get_key_usage(const uint8_t *cert, size_t cert_size,
1456 : size_t *usage)
1457 : {
1458 : mbedtls_x509_crt crt;
1459 : int ret;
1460 : bool status;
1461 :
1462 : /* Check input parameters.*/
1463 776 : if (cert == NULL || cert_size == 0 || usage == NULL) {
1464 0 : if (usage != NULL) {
1465 0 : *usage = 0;
1466 : }
1467 0 : return false;
1468 : }
1469 :
1470 776 : status = false;
1471 :
1472 776 : mbedtls_x509_crt_init(&crt);
1473 :
1474 776 : ret = wrapper_mbedtls_x509_crt_parse_der(&crt, cert, cert_size);
1475 :
1476 776 : if (ret == 0) {
1477 776 : *usage = crt.MBEDTLS_PRIVATE(key_usage);
1478 776 : status = true;
1479 : } else {
1480 0 : *usage = 0;
1481 : }
1482 776 : mbedtls_x509_crt_free(&crt);
1483 :
1484 776 : return status;
1485 : }
1486 :
1487 : /**
1488 : * Retrieve the Extended key usage from one X.509 certificate.
1489 : *
1490 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
1491 : * @param[in] cert_size size of the X509 certificate in bytes.
1492 : * @param[out] usage key usage bytes.
1493 : * @param[in, out] usage_size key usage buffer sizs in bytes.
1494 : *
1495 : * @retval true If the returned usage_size == 0, it means that cert and oid are valid, but the Extended key usage is not found;
1496 : * If the returned usage_size != 0, it means that cert and oid are valid, and the Extended key usage is found;
1497 : * @retval false If the returned usage_size == 0, it means that cert or oid are invalid;
1498 : * If the returned usage_size != 0, it means that cert and oid are valid, and the Extended key usage is found,
1499 : * but the store buffer is too small.
1500 : **/
1501 782 : bool libspdm_x509_get_extended_key_usage(const uint8_t *cert,
1502 : size_t cert_size, uint8_t *usage,
1503 : size_t *usage_size)
1504 : {
1505 : bool status;
1506 :
1507 782 : if (cert == NULL || cert_size == 0 || usage_size == NULL) {
1508 0 : return false;
1509 : }
1510 :
1511 782 : status = libspdm_x509_get_extension_data(cert, cert_size,
1512 : m_libspdm_oid_ext_key_usage,
1513 : sizeof(m_libspdm_oid_ext_key_usage), usage,
1514 : usage_size);
1515 :
1516 782 : return status;
1517 : }
1518 :
1519 : /**
1520 : * Retrieve the basic constraints from one X.509 certificate.
1521 : *
1522 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
1523 : * @param[in] cert_size size of the X509 certificate in bytes.
1524 : * @param[out] basic_constraints basic constraints bytes.
1525 : * @param[in, out] basic_constraints_size basic constraints buffer sizs in bytes.
1526 : *
1527 : * @retval true If the returned basic_constraints_size == 0, it means that cert and oid are valid, but the basic_constraints is not found;
1528 : * If the returned basic_constraints_size != 0, it means that cert and oid are valid, and the basic_constraints is found;
1529 : * @retval false If the returned basic_constraints_size == 0, it means that cert or oid are invalid;
1530 : * If the returned basic_constraints_size != 0, it means that cert and oid are valid, and the basic_constraints is found,
1531 : * but the store buffer is too small.
1532 : **/
1533 776 : bool libspdm_x509_get_extended_basic_constraints(const uint8_t *cert,
1534 : size_t cert_size,
1535 : uint8_t *basic_constraints,
1536 : size_t *basic_constraints_size)
1537 : {
1538 : bool status;
1539 :
1540 776 : if (cert == NULL || cert_size == 0 || basic_constraints_size == NULL) {
1541 0 : return false;
1542 : }
1543 :
1544 776 : status = libspdm_x509_get_extension_data(cert, cert_size,
1545 : m_libspdm_oid_basic_constraints,
1546 : sizeof(m_libspdm_oid_basic_constraints),
1547 : basic_constraints,
1548 : basic_constraints_size);
1549 776 : return status;
1550 : }
1551 :
1552 : /**
1553 : * Return 0 if before <= after, 1 otherwise
1554 : **/
1555 1564 : static int32_t libspdm_internal_x509_check_time(const mbedtls_x509_time *before,
1556 : const mbedtls_x509_time *after)
1557 : {
1558 1564 : if (before->year > after->year) {
1559 1564 : return (1);
1560 : }
1561 :
1562 0 : if (before->year == after->year && before->mon > after->mon) {
1563 0 : return (1);
1564 : }
1565 :
1566 0 : if (before->year == after->year && before->mon == after->mon &&
1567 0 : before->day > after->day) {
1568 0 : return (1);
1569 : }
1570 :
1571 0 : if (before->year == after->year && before->mon == after->mon &&
1572 0 : before->day == after->day && before->hour > after->hour) {
1573 0 : return (1);
1574 : }
1575 :
1576 0 : if (before->year == after->year && before->mon == after->mon &&
1577 0 : before->day == after->day && before->hour == after->hour &&
1578 0 : before->min > after->min) {
1579 0 : return (1);
1580 : }
1581 :
1582 0 : if (before->year == after->year && before->mon == after->mon &&
1583 0 : before->day == after->day && before->hour == after->hour &&
1584 0 : before->min == after->min && before->sec > after->sec) {
1585 0 : return (1);
1586 : }
1587 :
1588 0 : return (0);
1589 : }
1590 :
1591 9384 : static int32_t libspdm_internal_atoi(const char *p_start, char const *p_end)
1592 : {
1593 9384 : const char *p = p_start;
1594 9384 : int32_t k = 0;
1595 31280 : while (p < p_end) {
1596 :
1597 : /* k = k * 2³ + k * 2¹ = k * 8 + k * 2 = k * 10*/
1598 :
1599 21896 : k = (k << 3) + (k << 1) + (*p) - '0';
1600 21896 : p++;
1601 : }
1602 9384 : return k;
1603 : }
1604 :
1605 : /**
1606 : * format a date_time object into DataTime buffer
1607 : *
1608 : * If date_time_str is NULL, then return false.
1609 : * If date_time_size is NULL, then return false.
1610 : * If this interface is not supported, then return false.
1611 : *
1612 : * @param[in] date_time_str date_time string like YYYYMMDDhhmmssZ
1613 : * Ref: https://www.w3.org/TR/NOTE-datetime
1614 : * Z stand for UTC time
1615 : * @param[out] date_time Pointer to a date_time object.
1616 : * @param[in,out] date_time_size date_time object buffer size.
1617 : *
1618 : * @retval RETURN_SUCCESS The date_time object create successfully.
1619 : * @retval RETURN_INVALID_PARAMETER If date_time_str is NULL.
1620 : * If date_time_size is NULL.
1621 : * If date_time is not NULL and *date_time_size is 0.
1622 : * If year month day hour minute second combination is invalid datetime.
1623 : * @retval RETURN_BUFFER_TOO_SMALL If the date_time is NULL. The required buffer size
1624 : * (including the final null) is returned in the
1625 : * date_time_size parameter.
1626 : * @retval RETURN_UNSUPPORTED The operation is not supported.
1627 : **/
1628 1564 : bool libspdm_x509_set_date_time(const char *date_time_str, void *date_time, size_t *date_time_size)
1629 : {
1630 : mbedtls_x509_time dt;
1631 :
1632 : int32_t year;
1633 : int32_t month;
1634 : int32_t day;
1635 : int32_t hour;
1636 : int32_t minute;
1637 : int32_t second;
1638 : bool status;
1639 : const char *p;
1640 :
1641 1564 : p = date_time_str;
1642 :
1643 1564 : year = libspdm_internal_atoi(p, p + 4);
1644 1564 : p += 4;
1645 1564 : month = libspdm_internal_atoi(p, p + 2);
1646 1564 : p += 2;
1647 1564 : day = libspdm_internal_atoi(p, p + 2);
1648 1564 : p += 2;
1649 1564 : hour = libspdm_internal_atoi(p, p + 2);
1650 1564 : p += 2;
1651 1564 : minute = libspdm_internal_atoi(p, p + 2);
1652 1564 : p += 2;
1653 1564 : second = libspdm_internal_atoi(p, p + 2);
1654 1564 : p += 2;
1655 1564 : dt.year = (int)year;
1656 1564 : dt.mon = (int)month;
1657 1564 : dt.day = (int)day;
1658 1564 : dt.hour = (int)hour;
1659 1564 : dt.min = (int)minute;
1660 1564 : dt.sec = (int)second;
1661 :
1662 1564 : if (*date_time_size < sizeof(mbedtls_x509_time)) {
1663 0 : *date_time_size = sizeof(mbedtls_x509_time);
1664 0 : status = false;
1665 0 : goto cleanup;
1666 : }
1667 1564 : if (date_time != NULL) {
1668 1564 : libspdm_copy_mem(date_time, *date_time_size, &dt, sizeof(mbedtls_x509_time));
1669 : }
1670 1564 : *date_time_size = sizeof(mbedtls_x509_time);
1671 1564 : status = true;
1672 1564 : cleanup:
1673 1564 : return status;
1674 : }
1675 :
1676 : /**
1677 : * Compare date_time1 object and date_time2 object.
1678 : *
1679 : * If date_time1 is NULL, then return -2.
1680 : * If date_time2 is NULL, then return -2.
1681 : * If date_time1 == date_time2, then return 0
1682 : * If date_time1 > date_time2, then return 1
1683 : * If date_time1 < date_time2, then return -1
1684 : *
1685 : * @param[in] date_time1 Pointer to a date_time Object
1686 : * @param[in] date_time2 Pointer to a date_time Object
1687 : *
1688 : * @retval 0 If date_time1 == date_time2
1689 : * @retval 1 If date_time1 > date_time2
1690 : * @retval -1 If date_time1 < date_time2
1691 : **/
1692 1564 : int32_t libspdm_x509_compare_date_time(const void *date_time1, const void *date_time2)
1693 : {
1694 1564 : if (date_time1 == NULL || date_time2 == NULL) {
1695 0 : return -2;
1696 : }
1697 1564 : if (libspdm_consttime_is_mem_equal(date_time2, date_time1, sizeof(mbedtls_x509_time))) {
1698 0 : return 0;
1699 : }
1700 1564 : if (libspdm_internal_x509_check_time((const mbedtls_x509_time *)date_time1,
1701 : (const mbedtls_x509_time *)date_time2) == 0) {
1702 0 : return -1;
1703 : } else {
1704 1564 : return 1;
1705 : }
1706 : }
1707 :
1708 2 : static bool libspdm_convert_subject_to_string(uint8_t *ptr, size_t obj_len,
1709 : uint8_t *buffer, int32_t buff_len)
1710 : {
1711 : bool ret;
1712 : uint8_t *end;
1713 : uint8_t *internal_p;
1714 :
1715 : libspdm_x509_subject_descriptor_t *cur;
1716 : /* X.509 DN attributes from RFC 5280, Appendix A.1. */
1717 2 : libspdm_x509_subject_descriptor_t x509_attrs[] =
1718 : {
1719 : { LIBSPDM_ADD_STRLEN( "CN" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_CN ),
1720 : MBEDTLS_ASN1_UTF8_STRING },
1721 : { LIBSPDM_ADD_STRLEN( "C" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_COUNTRY ),
1722 : MBEDTLS_ASN1_PRINTABLE_STRING },
1723 : { LIBSPDM_ADD_STRLEN( "O" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_ORGANIZATION ),
1724 : MBEDTLS_ASN1_UTF8_STRING },
1725 : { LIBSPDM_ADD_STRLEN( "L" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_LOCALITY ),
1726 : MBEDTLS_ASN1_UTF8_STRING },
1727 : { LIBSPDM_ADD_STRLEN( "R" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_PKCS9_EMAIL ),
1728 : MBEDTLS_ASN1_IA5_STRING },
1729 : { LIBSPDM_ADD_STRLEN( "OU" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_ORG_UNIT ),
1730 : MBEDTLS_ASN1_UTF8_STRING },
1731 : { LIBSPDM_ADD_STRLEN( "ST" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_STATE ),
1732 : MBEDTLS_ASN1_UTF8_STRING },
1733 : { LIBSPDM_ADD_STRLEN( "emailAddress" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_PKCS9_EMAIL ),
1734 : MBEDTLS_ASN1_IA5_STRING },
1735 : { LIBSPDM_ADD_STRLEN( "serialNumber" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_SERIAL_NUMBER ),
1736 : MBEDTLS_ASN1_PRINTABLE_STRING },
1737 : { LIBSPDM_ADD_STRLEN( "postalAddress" ),
1738 : LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_POSTAL_ADDRESS ), MBEDTLS_ASN1_PRINTABLE_STRING },
1739 : { LIBSPDM_ADD_STRLEN( "postalCode" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_POSTAL_CODE ),
1740 : MBEDTLS_ASN1_PRINTABLE_STRING },
1741 : { LIBSPDM_ADD_STRLEN( "dnQualifier" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_DN_QUALIFIER ),
1742 : MBEDTLS_ASN1_PRINTABLE_STRING },
1743 : { LIBSPDM_ADD_STRLEN( "title" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_TITLE ),
1744 : MBEDTLS_ASN1_UTF8_STRING },
1745 : { LIBSPDM_ADD_STRLEN( "SN" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_SUR_NAME ),
1746 : MBEDTLS_ASN1_UTF8_STRING },
1747 : { LIBSPDM_ADD_STRLEN( "GN" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_GIVEN_NAME ),
1748 : MBEDTLS_ASN1_UTF8_STRING },
1749 : { LIBSPDM_ADD_STRLEN( "initials" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_INITIALS ),
1750 : MBEDTLS_ASN1_UTF8_STRING },
1751 : { LIBSPDM_ADD_STRLEN( "pseudonym" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_PSEUDONYM ),
1752 : MBEDTLS_ASN1_UTF8_STRING },
1753 : { LIBSPDM_ADD_STRLEN( "generationQualifier" ),
1754 : LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_GENERATION_QUALIFIER ),
1755 : MBEDTLS_ASN1_UTF8_STRING },
1756 : { LIBSPDM_ADD_STRLEN( "DC" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_DOMAIN_COMPONENT ),
1757 : MBEDTLS_ASN1_IA5_STRING },
1758 : { NULL, 0, NULL, 0, MBEDTLS_ASN1_NULL }
1759 : };
1760 :
1761 2 : end = ptr + obj_len;
1762 :
1763 8 : while(ptr != end) {
1764 : /*SET*/
1765 6 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
1766 : LIBSPDM_CRYPTO_ASN1_SET | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1767 6 : if (!ret) {
1768 0 : return false;
1769 : }
1770 6 : internal_p = ptr;
1771 : /*move to next SET*/
1772 6 : ptr += obj_len;
1773 :
1774 : /*sequence*/
1775 6 : ret = libspdm_asn1_get_tag(&internal_p, end, &obj_len,
1776 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1777 6 : if (!ret) {
1778 0 : return false;
1779 : }
1780 :
1781 : /*OID*/
1782 6 : ret = libspdm_asn1_get_tag(&internal_p, end, &obj_len, LIBSPDM_CRYPTO_ASN1_OID);
1783 6 : if (!ret) {
1784 0 : return false;
1785 : }
1786 :
1787 24 : for (cur = x509_attrs; cur->name != NULL; cur++) {
1788 46 : if ((cur->oid_len == obj_len) &&
1789 22 : (libspdm_consttime_is_mem_equal(cur->oid, internal_p, obj_len))) {
1790 : /*Concat subject string*/
1791 :
1792 : /*for example: CN=*/
1793 6 : libspdm_copy_mem(buffer, buff_len, cur->name, cur->name_len);
1794 6 : buff_len = (int32_t)(buff_len - cur->name_len);
1795 6 : buffer += cur->name_len;
1796 6 : *buffer = '=';
1797 6 : buff_len--;
1798 6 : buffer++;
1799 :
1800 : /*move to string*/
1801 6 : internal_p += obj_len;
1802 6 : ret = libspdm_asn1_get_tag(&internal_p, end, &obj_len, cur->default_tag);
1803 6 : if (!ret) {
1804 0 : return false;
1805 : }
1806 :
1807 : /*for example: AU,*/
1808 6 : libspdm_copy_mem(buffer, buff_len, internal_p, obj_len);
1809 6 : buff_len = (int32_t)(buff_len - obj_len);
1810 6 : buffer += obj_len;
1811 6 : *buffer = ',';
1812 6 : buff_len--;
1813 6 : buffer++;
1814 :
1815 6 : if (buff_len < 0) {
1816 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"the buffer is too small"));
1817 0 : return false;
1818 : }
1819 6 : break;
1820 : }
1821 : }
1822 :
1823 : /*can not find the same oid, the subject is wrong*/
1824 6 : if (cur->name == NULL) {
1825 0 : return false;
1826 : }
1827 : }
1828 :
1829 2 : *buffer = '\0';
1830 2 : return true;
1831 : }
1832 :
1833 : /**
1834 : * Set all attributes object form req_info to CSR
1835 : *
1836 : * @param[in] req CSR to set attributes
1837 : * @param[in] req_info requester info to gen CSR
1838 : * @param[in] req_info_len The len of requester info
1839 : *
1840 : * @retval true Success Set.
1841 : * @retval false Set failed.
1842 : **/
1843 2 : bool libspdm_set_attribute_for_req(mbedtls_x509write_csr *req,
1844 : uint8_t *req_info, size_t req_info_len,
1845 : uint8_t *pub_key_der, size_t pub_key_der_len)
1846 : {
1847 : uint8_t *ptr;
1848 : int32_t length;
1849 : size_t obj_len;
1850 : bool ret;
1851 : uint8_t *end;
1852 : uint8_t *ptr_old;
1853 :
1854 : uint8_t *oid;
1855 : size_t oid_len;
1856 : uint8_t *val;
1857 : size_t val_len;
1858 :
1859 : uint8_t *pkinfo;
1860 : size_t pkinfo_len;
1861 : uint8_t buffer[LIBSPDM_MAX_SUBJECT_BUFFER_SIZE];
1862 :
1863 2 : length = (int32_t)req_info_len;
1864 2 : ptr = req_info;
1865 2 : obj_len = 0;
1866 2 : end = ptr + length;
1867 2 : ret = false;
1868 :
1869 2 : if (req_info == NULL) {
1870 0 : return false;
1871 : }
1872 :
1873 : /*req_info sequence, all req_info format is ok because the req_info has been verified before*/
1874 2 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
1875 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1876 :
1877 : /*integer:version*/
1878 2 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len, LIBSPDM_CRYPTO_ASN1_INTEGER);
1879 : /*check req_info version. spec PKCS#10: It shall be 0 for this version of the standard.*/
1880 2 : if ((obj_len != 1) || (*ptr != 0)) {
1881 0 : return false;
1882 : }
1883 2 : ptr += obj_len;
1884 :
1885 : /*sequence:subject name*/
1886 2 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
1887 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1888 :
1889 : /**/
1890 2 : libspdm_zero_mem(buffer, sizeof(buffer));
1891 2 : ret = libspdm_convert_subject_to_string(ptr, obj_len, buffer, LIBSPDM_MAX_SUBJECT_BUFFER_SIZE);
1892 2 : if (!ret) {
1893 0 : return false;
1894 : }
1895 :
1896 : /*set subject name*/
1897 2 : ret = mbedtls_x509write_csr_set_subject_name(req, (const char *)buffer);
1898 2 : if (ret != 0) {
1899 0 : return false;
1900 : }
1901 :
1902 2 : ptr += obj_len;
1903 :
1904 2 : pkinfo = ptr;
1905 : /*sequence:subject pkinfo*/
1906 2 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
1907 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1908 :
1909 2 : pkinfo_len = obj_len + ptr - pkinfo;
1910 : /*check the public key info*/
1911 4 : if (!((pkinfo_len == pub_key_der_len) &&
1912 2 : (libspdm_consttime_is_mem_equal(pub_key_der, pkinfo, pkinfo_len)))) {
1913 0 : return false;
1914 : }
1915 :
1916 2 : ptr += obj_len;
1917 :
1918 : /*[0]: attributes*/
1919 2 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
1920 : LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC |
1921 : LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1922 : /*there is no attributes*/
1923 2 : if (ptr == end) {
1924 0 : return true;
1925 : }
1926 :
1927 : /*there is some attributes object: 1,2 ...*/
1928 4 : while (ret)
1929 : {
1930 2 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
1931 : LIBSPDM_CRYPTO_ASN1_SEQUENCE |
1932 : LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1933 2 : if (ret) {
1934 : /*save old position*/
1935 2 : ptr_old = ptr;
1936 :
1937 : /*move to the next sequence*/
1938 2 : ptr += obj_len;
1939 :
1940 : /*get attributes oid*/
1941 2 : ret = libspdm_asn1_get_tag(&ptr_old, end, &obj_len, LIBSPDM_CRYPTO_ASN1_OID);
1942 2 : if (!ret) {
1943 0 : return false;
1944 : }
1945 2 : oid = ptr_old;
1946 2 : oid_len = obj_len;
1947 :
1948 2 : ptr_old += obj_len;
1949 : /*get attributes val*/
1950 2 : ret = libspdm_asn1_get_tag(&ptr_old, end, &obj_len,
1951 : LIBSPDM_CRYPTO_ASN1_SET |
1952 : LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1953 2 : if (!ret) {
1954 0 : return false;
1955 : }
1956 2 : ret = libspdm_asn1_get_tag(&ptr_old, end, &obj_len, LIBSPDM_CRYPTO_ASN1_UTF8_STRING);
1957 2 : if (!ret) {
1958 0 : return false;
1959 : }
1960 2 : val = ptr_old;
1961 2 : val_len = obj_len;
1962 :
1963 : /*set attributes*/
1964 2 : ret = mbedtls_x509write_csr_set_extension(req, (const char *)oid, oid_len, 0, val,
1965 : val_len);
1966 :
1967 2 : if (ret) {
1968 0 : return false;
1969 : }
1970 :
1971 : } else {
1972 0 : break;
1973 : }
1974 : }
1975 :
1976 2 : if (ptr == end) {
1977 2 : return true;
1978 : } else {
1979 0 : return false;
1980 : }
1981 : }
1982 :
1983 : /**
1984 : * Gen CSR
1985 : *
1986 : * @param[in] hash_nid hash algo for sign
1987 : * @param[in] asym_nid asym algo for sign
1988 : *
1989 : * @param[in] requester_info requester info to gen CSR
1990 : * @param[in] requester_info_length The len of requester info
1991 : *
1992 : * @param[in] is_ca if true, set basic_constraints: CA:true; Otherwise, set to false.
1993 : *
1994 : * @param[in] context Pointer to asymmetric context
1995 : * @param[in] subject_name Subject name: should be break with ',' in the middle
1996 : * example: "C=AA,CN=BB"
1997 : * Subject names should contain a comma-separated list of OID types and values:
1998 : * The valid OID type name is in:
1999 : * {"CN", "commonName", "C", "countryName", "O", "organizationName","L",
2000 : * "OU", "organizationalUnitName", "ST", "stateOrProvinceName", "emailAddress",
2001 : * "serialNumber", "postalAddress", "postalCode", "dnQualifier", "title",
2002 : * "SN","givenName","GN", "initials", "pseudonym", "generationQualifier", "domainComponent", "DC"}.
2003 : * Note: The object of C and countryName should be CSR Supported Country Codes
2004 : *
2005 : * @param[in, out] csr_len For input, csr_len is the size of store CSR buffer.
2006 : * For output, csr_len is CSR len for DER format
2007 : * @param[in, out] csr_pointer For input, csr_pointer is buffer address to store CSR.
2008 : * For output, csr_pointer is address for stored CSR.
2009 : * The csr_pointer address will be changed.
2010 : * @param[in] base_cert An optional leaf certificate whose
2011 : * extensions should be copied to the CSR
2012 : *
2013 : * @retval true Success.
2014 : * @retval false Failed to gen CSR.
2015 : **/
2016 6 : bool libspdm_gen_x509_csr(size_t hash_nid, size_t asym_nid,
2017 : uint8_t *requester_info, size_t requester_info_length,
2018 : bool is_ca,
2019 : void *context, char *subject_name,
2020 : size_t *csr_len, uint8_t *csr_pointer,
2021 : void *base_cert)
2022 : {
2023 : int ret;
2024 : bool result;
2025 : size_t csr_buffer_size;
2026 :
2027 : mbedtls_x509write_csr req;
2028 : mbedtls_md_type_t md_alg;
2029 : mbedtls_asn1_sequence extns;
2030 : mbedtls_asn1_sequence *next_oid;
2031 : mbedtls_x509_buf buf;
2032 : mbedtls_x509_crt *cert;
2033 : mbedtls_pk_context key;
2034 :
2035 : uint8_t pubkey_buffer[LIBSPDM_MAX_PUBKEY_DER_BUFFER_SIZE];
2036 : uint8_t *pubkey_der_data;
2037 : size_t pubkey_der_len;
2038 : size_t oid_tag_len;
2039 :
2040 : /*basic_constraints: CA: false */
2041 : #define BASIC_CONSTRAINTS_STRING_FALSE {0x30, 0x00}
2042 6 : uint8_t basic_constraints_false[] = BASIC_CONSTRAINTS_STRING_FALSE;
2043 :
2044 : /*basic_constraints: CA: true */
2045 : #define BASIC_CONSTRAINTS_STRING_TRUE {0x30, 0x03, 0x01, 0x01, 0xFF}
2046 6 : uint8_t basic_constraints_true[] = BASIC_CONSTRAINTS_STRING_TRUE;
2047 :
2048 : /* Init */
2049 6 : mbedtls_x509write_csr_init(&req);
2050 6 : mbedtls_pk_init(&key);
2051 6 : csr_buffer_size = *csr_len;
2052 6 : next_oid = NULL;
2053 :
2054 6 : ret = 1;
2055 6 : switch (asym_nid)
2056 : {
2057 0 : case LIBSPDM_CRYPTO_NID_RSASSA2048:
2058 : case LIBSPDM_CRYPTO_NID_RSAPSS2048:
2059 : case LIBSPDM_CRYPTO_NID_RSASSA3072:
2060 : case LIBSPDM_CRYPTO_NID_RSAPSS3072:
2061 : case LIBSPDM_CRYPTO_NID_RSASSA4096:
2062 : case LIBSPDM_CRYPTO_NID_RSAPSS4096:
2063 0 : ret = mbedtls_pk_setup(&key, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA));
2064 0 : if (ret != 0) {
2065 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"failed\n ! mbedtls_pk_setup %d", ret));
2066 0 : goto free_all;
2067 : }
2068 0 : ret = mbedtls_rsa_copy(mbedtls_pk_rsa(key), (mbedtls_rsa_context *)context);
2069 0 : if (ret != 0) {
2070 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"failed\n ! mbedtls_rsa_copy %d", ret));
2071 0 : goto free_all;
2072 : }
2073 0 : ret = mbedtls_rsa_complete(mbedtls_pk_rsa(key));
2074 0 : if (ret != 0) {
2075 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"failed\n ! mbedtls_rsa_complete %d", ret));
2076 0 : goto free_all;
2077 : }
2078 0 : break;
2079 6 : case LIBSPDM_CRYPTO_NID_ECDSA_NIST_P256:
2080 : case LIBSPDM_CRYPTO_NID_ECDSA_NIST_P384:
2081 : case LIBSPDM_CRYPTO_NID_ECDSA_NIST_P521:
2082 6 : ret = mbedtls_pk_setup(&key, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
2083 6 : if (ret != 0) {
2084 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"failed\n ! mbedtls_pk_setup %d", ret));
2085 0 : goto free_all;
2086 : }
2087 : /*mbedtls_ecdh_context include mbedtls_ecdsa_context,can be treated as mbedtls_ecdsa_context*/
2088 6 : ret = mbedtls_ecdsa_from_keypair(mbedtls_pk_ec(key), (mbedtls_ecdsa_context *)context);
2089 6 : if (ret != 0) {
2090 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"failed\n ! mbedtls_ecdsa_from_keypair %d", ret));
2091 0 : goto free_all;
2092 : }
2093 6 : break;
2094 0 : default:
2095 0 : return false;
2096 : }
2097 :
2098 6 : switch (hash_nid)
2099 : {
2100 6 : case LIBSPDM_CRYPTO_NID_SHA256:
2101 6 : md_alg = MBEDTLS_MD_SHA256;
2102 6 : break;
2103 0 : case LIBSPDM_CRYPTO_NID_SHA384:
2104 0 : md_alg = MBEDTLS_MD_SHA384;
2105 0 : break;
2106 0 : case LIBSPDM_CRYPTO_NID_SHA512:
2107 0 : md_alg = MBEDTLS_MD_SHA512;
2108 0 : break;
2109 0 : case LIBSPDM_CRYPTO_NID_SHA3_256:
2110 0 : md_alg = MBEDTLS_MD_SHA3_256;
2111 0 : break;
2112 0 : case LIBSPDM_CRYPTO_NID_SHA3_384:
2113 0 : md_alg = MBEDTLS_MD_SHA3_384;
2114 0 : break;
2115 0 : case LIBSPDM_CRYPTO_NID_SHA3_512:
2116 0 : md_alg = MBEDTLS_MD_SHA3_512;
2117 0 : break;
2118 0 : default:
2119 0 : ret = 1;
2120 0 : goto free_all;
2121 : }
2122 :
2123 : /* Set the md alg */
2124 6 : mbedtls_x509write_csr_set_md_alg(&req, md_alg);
2125 :
2126 : /* Set the subject name */
2127 6 : if (subject_name != NULL) {
2128 6 : ret = mbedtls_x509write_csr_set_subject_name(&req, subject_name);
2129 6 : if (ret != 0) {
2130 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
2131 : "failed\n ! mbedtls_x509write_csr_set_subject_name returned %d", ret));
2132 0 : goto free_all;
2133 : }
2134 : }
2135 :
2136 6 : libspdm_zero_mem(pubkey_buffer, sizeof(pubkey_buffer));
2137 6 : pubkey_der_len = mbedtls_pk_write_pubkey_der(&key, pubkey_buffer, sizeof(pubkey_buffer));
2138 6 : if (pubkey_der_len > 0) {
2139 : /*Note: data is written at the end of the buffer!*/
2140 6 : pubkey_der_data = pubkey_buffer + sizeof(pubkey_buffer) - pubkey_der_len;
2141 : } else {
2142 0 : goto free_all;
2143 : }
2144 :
2145 : /* requester info parse
2146 : * check the req_info version and subjectPKInfo;
2147 : * get attribute and subject from req_info and set them to CSR;
2148 : **/
2149 6 : if (requester_info_length != 0) {
2150 2 : result = libspdm_set_attribute_for_req(&req, requester_info, requester_info_length,
2151 : pubkey_der_data, pubkey_der_len);
2152 2 : if (!result) {
2153 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"set_attribute failed !\n"));
2154 0 : goto free_all;
2155 : }
2156 : }
2157 :
2158 : /* Set key */
2159 6 : mbedtls_x509write_csr_set_key(&req, &key);
2160 :
2161 : /*set basicConstraints*/
2162 6 : if (mbedtls_x509write_csr_set_extension(&req, MBEDTLS_OID_BASIC_CONSTRAINTS,
2163 : MBEDTLS_OID_SIZE(MBEDTLS_OID_BASIC_CONSTRAINTS),
2164 : 0,
2165 : is_ca ? basic_constraints_true : basic_constraints_false,
2166 : is_ca ?
2167 : sizeof(basic_constraints_true) :
2168 : sizeof(basic_constraints_false)
2169 : ) != 0) {
2170 0 : ret = 1;
2171 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
2172 : "mbedtls_x509write_csr_set_extension set basicConstraints failed \n"));
2173 0 : goto free_all;
2174 : }
2175 :
2176 6 : if (base_cert != NULL) {
2177 6 : cert = base_cert;
2178 6 : buf = cert->v3_ext;
2179 6 : if (mbedtls_asn1_get_sequence_of(&buf.p, buf.p + buf.len, &extns,
2180 : MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
2181 0 : ret = 1;
2182 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
2183 : "mbedtls_x509write_csr_set_extension unable to get sequence\n"));
2184 0 : goto free_all;
2185 : }
2186 :
2187 6 : next_oid = &extns;
2188 : }
2189 :
2190 42 : while (next_oid) {
2191 36 : if (mbedtls_asn1_get_tag(&(next_oid->buf.p), next_oid->buf.p + next_oid->buf.len,
2192 : &oid_tag_len, MBEDTLS_ASN1_OID)) {
2193 0 : ret = 1;
2194 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
2195 : "mbedtls_x509write_csr_set_extension unable to get OID tag\n"));
2196 0 : goto free_all;
2197 : }
2198 :
2199 36 : if (MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_BASIC_CONSTRAINTS, next_oid->buf.p, oid_tag_len) == 0) {
2200 6 : next_oid = next_oid->next;
2201 6 : continue;
2202 : }
2203 :
2204 30 : if (MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER, next_oid->buf.p,
2205 : oid_tag_len) == 0) {
2206 0 : next_oid = next_oid->next;
2207 0 : continue;
2208 : }
2209 :
2210 30 : if (mbedtls_x509write_csr_set_extension(&req, (const char *)next_oid->buf.p,
2211 : oid_tag_len, 0,
2212 30 : next_oid->buf.p + oid_tag_len,
2213 30 : next_oid->buf.len - oid_tag_len
2214 : ) != 0) {
2215 0 : ret = 1;
2216 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
2217 : "mbedtls_x509write_csr_set_extension set custom OID failed \n"));
2218 0 : goto free_all;
2219 : }
2220 :
2221 30 : next_oid = next_oid->next;
2222 : }
2223 :
2224 : /*csr data is written at the end of the buffer*/
2225 6 : ret = mbedtls_x509write_csr_der(&req, csr_pointer, csr_buffer_size, libspdm_myrand, NULL);
2226 6 : if (ret <= 0) {
2227 0 : ret = 1;
2228 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"mbedtls_x509write_csr_der failed \n"));
2229 0 : goto free_all;
2230 : }
2231 :
2232 6 : *csr_len = (size_t)ret;
2233 : /*make csr_pointer store csr data*/
2234 6 : memmove(csr_pointer, csr_pointer + csr_buffer_size - *csr_len, *csr_len);
2235 :
2236 6 : ret = 0;
2237 6 : free_all:
2238 6 : mbedtls_x509write_csr_free(&req);
2239 6 : mbedtls_pk_free(&key);
2240 :
2241 6 : return(ret == 0);
2242 : }
2243 :
2244 0 : bool libspdm_gen_x509_csr_with_pqc(
2245 : size_t hash_nid, size_t asym_nid, size_t pqc_asym_nid,
2246 : uint8_t *requester_info, size_t requester_info_length,
2247 : bool is_ca,
2248 : void *context, char *subject_name,
2249 : size_t *csr_len, uint8_t *csr_pointer,
2250 : void *base_cert)
2251 : {
2252 0 : if (pqc_asym_nid != 0) {
2253 0 : return false;
2254 : }
2255 0 : return libspdm_gen_x509_csr(hash_nid, asym_nid, requester_info,
2256 : requester_info_length, is_ca, context,
2257 : subject_name, csr_len, csr_pointer, base_cert);
2258 : }
2259 :
2260 : #endif
|