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