Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 2021-2024 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 14760 : bool libspdm_asn1_get_tag(uint8_t **ptr, const uint8_t *end, size_t *length,
244 : uint32_t tag)
245 : {
246 14760 : if (mbedtls_asn1_get_tag(ptr, end, length, (int32_t)tag) == 0) {
247 14731 : 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 827 : 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 827 : 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 827 : status = false;
287 :
288 827 : mbedtls_x509_crt_init(&crt);
289 :
290 827 : ret = mbedtls_x509_crt_parse_der(&crt, cert, cert_size);
291 :
292 827 : if (ret == 0) {
293 827 : if (*subject_size < crt.subject_raw.len) {
294 768 : *subject_size = crt.subject_raw.len;
295 768 : status = false;
296 768 : 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 827 : cleanup:
309 827 : mbedtls_x509_crt_free(&crt);
310 :
311 827 : 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 925 : 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 925 : mbedtls_x509_crt_init(&crt);
551 :
552 925 : if (mbedtls_x509_crt_parse_der(&crt, cert, cert_size) != 0) {
553 0 : return false;
554 : }
555 :
556 925 : if (mbedtls_pk_get_type(&crt.pk) != MBEDTLS_PK_ECKEY) {
557 1 : mbedtls_x509_crt_free(&crt);
558 1 : return false;
559 : }
560 :
561 924 : ecdh = allocate_zero_pool(sizeof(mbedtls_ecdh_context));
562 924 : if (ecdh == NULL) {
563 0 : mbedtls_x509_crt_free(&crt);
564 0 : return false;
565 : }
566 924 : mbedtls_ecdh_init(ecdh);
567 :
568 924 : ret = mbedtls_ecdh_get_params(ecdh, mbedtls_pk_ec(crt.pk),
569 : MBEDTLS_ECDH_OURS);
570 924 : 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 924 : mbedtls_x509_crt_free(&crt);
577 :
578 924 : *ec_context = ecdh;
579 924 : 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 2375 : 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 2375 : uint32_t v_flag = 0;
648 2375 : mbedtls_x509_crt_profile profile = { 0 };
649 :
650 2375 : if (cert == NULL || ca_cert == NULL) {
651 0 : return false;
652 : }
653 :
654 2375 : libspdm_copy_mem(&profile, sizeof(profile),
655 : &mbedtls_x509_crt_profile_default,
656 : sizeof(mbedtls_x509_crt_profile));
657 :
658 2375 : mbedtls_x509_crt_init(&ca);
659 2375 : mbedtls_x509_crt_init(&end);
660 :
661 2375 : ret = mbedtls_x509_crt_parse_der(&ca, ca_cert, ca_cert_size);
662 :
663 2375 : if (ret == 0) {
664 2375 : ret = mbedtls_x509_crt_parse_der(&end, cert, cert_size);
665 : }
666 :
667 2375 : if (ret == 0) {
668 2375 : ret = mbedtls_x509_crt_verify_with_profile(
669 : &end, &ca, NULL, &profile, NULL, &v_flag, NULL, NULL);
670 : }
671 :
672 2375 : mbedtls_x509_crt_free(&ca);
673 2375 : mbedtls_x509_crt_free(&end);
674 :
675 2375 : 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 745 : 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 745 : verify_flag = false;
709 745 : preceding_cert = root_cert;
710 745 : preceding_cert_len = root_cert_length;
711 :
712 745 : 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 3116 : tmp_ptr = current_cert;
719 3116 : ret = mbedtls_asn1_get_tag(
720 3116 : &tmp_ptr, cert_chain + cert_chain_length, &asn1_len,
721 : MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
722 3116 : if (ret != 0) {
723 742 : if (current_cert < cert_chain + cert_chain_length) {
724 2 : verify_flag = false;
725 : }
726 742 : break;
727 : }
728 :
729 2374 : current_cert_len = asn1_len + (tmp_ptr - current_cert);
730 :
731 2374 : if (current_cert + current_cert_len > cert_chain + cert_chain_length) {
732 0 : verify_flag = false;
733 0 : break;
734 : }
735 :
736 2374 : if (libspdm_x509_verify_cert(current_cert, current_cert_len,
737 : preceding_cert,
738 2374 : preceding_cert_len) == false) {
739 3 : verify_flag = false;
740 3 : break;
741 : } else {
742 2371 : verify_flag = true;
743 : }
744 :
745 :
746 : /* Save preceding certificate*/
747 :
748 2371 : preceding_cert = current_cert;
749 2371 : preceding_cert_len = current_cert_len;
750 :
751 :
752 : /* Move current certificate to next;*/
753 :
754 2371 : current_cert = current_cert + current_cert_len;
755 : } while (true);
756 :
757 745 : 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 2505 : 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 2505 : current_cert_len = 0;
791 :
792 : /* Check input parameters.*/
793 :
794 2505 : if ((cert_chain == NULL) || (cert == NULL) || (cert_index < -1) ||
795 : (cert_length == NULL)) {
796 0 : return false;
797 : }
798 :
799 2505 : current_cert = (const unsigned char *)cert_chain;
800 2505 : current_index = -1;
801 :
802 :
803 : /* Traverse the certificate chain*/
804 :
805 : while (true) {
806 :
807 : /* Get asn1 tag len*/
808 :
809 5681 : tmp_ptr = current_cert;
810 5681 : ret = mbedtls_asn1_get_tag(
811 5681 : &tmp_ptr, cert_chain + cert_chain_length, &asn1_len,
812 : MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
813 5681 : if (ret != 0) {
814 1000 : break;
815 : }
816 :
817 4681 : current_cert_len = asn1_len + (tmp_ptr - current_cert);
818 4681 : if (current_cert + current_cert_len > cert_chain + cert_chain_length) {
819 0 : return false;
820 : }
821 :
822 4681 : current_index++;
823 :
824 4681 : if (current_index == cert_index) {
825 1505 : *cert = current_cert;
826 1505 : *cert_length = current_cert_len;
827 1505 : return true;
828 : }
829 :
830 :
831 : /* Move to next*/
832 :
833 3176 : current_cert = current_cert + current_cert_len;
834 : }
835 :
836 :
837 : /* If cert_index is -1, Return the last certificate*/
838 :
839 1000 : if (cert_index == -1 && current_index >= 0) {
840 1000 : *cert = current_cert - current_cert_len;
841 1000 : *cert_length = current_cert_len;
842 1000 : 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 770 : 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 770 : if (cert == NULL) {
894 0 : return false;
895 : }
896 :
897 770 : status = false;
898 :
899 770 : mbedtls_x509_crt_init(&crt);
900 :
901 770 : ret = mbedtls_x509_crt_parse_der(&crt, cert, cert_size);
902 :
903 770 : if (ret == 0) {
904 770 : *version = crt.version - 1;
905 770 : status = true;
906 : }
907 :
908 770 : mbedtls_x509_crt_free(&crt);
909 :
910 770 : 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 770 : 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 770 : if (cert == NULL) {
945 0 : return false;
946 : }
947 :
948 770 : status = false;
949 :
950 770 : mbedtls_x509_crt_init(&crt);
951 :
952 770 : ret = mbedtls_x509_crt_parse_der(&crt, cert, cert_size);
953 :
954 770 : if (ret == 0) {
955 770 : if (*serial_number_size <= crt.serial.len) {
956 770 : *serial_number_size = crt.serial.len + 1;
957 770 : status = false;
958 770 : 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 770 : mbedtls_x509_crt_free(&crt);
969 :
970 770 : 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 827 : 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 827 : 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 827 : status = false;
1009 :
1010 827 : mbedtls_x509_crt_init(&crt);
1011 :
1012 827 : ret = mbedtls_x509_crt_parse_der(&crt, cert, cert_size);
1013 :
1014 827 : if (ret == 0) {
1015 827 : if (*issuer_size < crt.issuer_raw.len) {
1016 768 : *issuer_size = crt.issuer_raw.len;
1017 768 : status = false;
1018 768 : 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 827 : cleanup:
1030 827 : mbedtls_x509_crt_free(&crt);
1031 :
1032 827 : 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 : #if LIBSPDM_ADDITIONAL_CHECK_CERT
1109 : /**
1110 : * Retrieve the signature algorithm from one X.509 certificate.
1111 : *
1112 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
1113 : * @param[in] cert_size size of the X509 certificate in bytes.
1114 : * @param[out] oid signature algorithm Object identifier buffer.
1115 : * @param[in,out] oid_size signature algorithm Object identifier buffer size
1116 : *
1117 : * @retval true if the oid_size is equal 0, the cert parse successfully, but cert doesn't have signature algo.
1118 : * @retval true if the oid_size is not equal 0, the cert parse and get signature algo successfully.
1119 : * @retval false if the oid_size is equal 0, the cert parse failed.
1120 : * @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.
1121 : **/
1122 : bool libspdm_x509_get_signature_algorithm(const uint8_t *cert,
1123 : size_t cert_size, uint8_t *oid,
1124 : size_t *oid_size)
1125 : {
1126 : mbedtls_x509_crt crt;
1127 : int ret;
1128 : bool status;
1129 :
1130 : /* Check input parameters.*/
1131 : if (cert == NULL || cert_size == 0 || oid_size == NULL) {
1132 : if (oid_size != NULL) {
1133 : *oid_size = 0;
1134 : }
1135 : return false;
1136 : }
1137 :
1138 : status = false;
1139 :
1140 : mbedtls_x509_crt_init(&crt);
1141 :
1142 : ret = mbedtls_x509_crt_parse_der(&crt, cert, cert_size);
1143 :
1144 : if (ret == 0) {
1145 : if (*oid_size < crt.sig_oid.len) {
1146 : *oid_size = crt.serial.len;
1147 : status = false;
1148 : goto cleanup;
1149 : }
1150 : if (oid != NULL) {
1151 : libspdm_copy_mem(oid, *oid_size, crt.sig_oid.p, crt.sig_oid.len);
1152 : }
1153 : *oid_size = crt.sig_oid.len;
1154 : status = true;
1155 : } else {
1156 : *oid_size = 0;
1157 : }
1158 :
1159 : cleanup:
1160 : mbedtls_x509_crt_free(&crt);
1161 :
1162 : return status;
1163 : }
1164 : #endif /* LIBSPDM_ADDITIONAL_CHECK_CERT */
1165 :
1166 : /**
1167 : * Find first Extension data match with given OID
1168 : *
1169 : * @param[in] start Pointer to the DER-encoded extensions data
1170 : * @param[in] end extensions data size in bytes
1171 : * @param[in ] oid OID for match
1172 : * @param[in ] oid_size OID size in bytes
1173 : * @param[out] find_extension_data output matched extension data.
1174 : * @param[out] find_extension_data_len matched extension data size.
1175 : *
1176 : **/
1177 : static bool
1178 2302 : libspdm_internal_x509_find_extension_data(uint8_t *start, uint8_t *end, const uint8_t *oid,
1179 : size_t oid_size, uint8_t **find_extension_data,
1180 : size_t *find_extension_data_len)
1181 : {
1182 : uint8_t *ptr;
1183 : uint8_t *extension_ptr;
1184 : size_t obj_len;
1185 : int ret;
1186 : bool status;
1187 : size_t find_extension_len;
1188 : size_t header_len;
1189 :
1190 : /*If no Extension entry match oid*/
1191 2302 : status = false;
1192 2302 : ptr = start;
1193 :
1194 2302 : ret = 0;
1195 :
1196 : while (true) {
1197 : /*
1198 : * Extension ::= SEQUENCE {
1199 : * extnID OBJECT IDENTIFIER,
1200 : * critical bool DEFAULT false,
1201 : * extnValue OCTET STRING }
1202 : */
1203 9239 : extension_ptr = ptr;
1204 9239 : ret = mbedtls_asn1_get_tag(&ptr, end, &obj_len,
1205 : MBEDTLS_ASN1_CONSTRUCTED |
1206 : MBEDTLS_ASN1_SEQUENCE);
1207 9239 : if (ret == 0) {
1208 9224 : header_len = (size_t)(ptr - extension_ptr);
1209 9224 : find_extension_len = obj_len;
1210 : /* Get Object Identifier*/
1211 9224 : ret = mbedtls_asn1_get_tag(&ptr, end, &obj_len,
1212 : MBEDTLS_ASN1_OID);
1213 : } else {
1214 15 : break;
1215 : }
1216 :
1217 9224 : if (ret == 0 && libspdm_consttime_is_mem_equal(ptr, oid, oid_size)) {
1218 2287 : ptr += obj_len;
1219 :
1220 2287 : ret = mbedtls_asn1_get_tag(&ptr, end, &obj_len,
1221 : MBEDTLS_ASN1_BOOLEAN);
1222 2287 : if (ret == 0) {
1223 1523 : ptr += obj_len;
1224 : }
1225 :
1226 2287 : ret = mbedtls_asn1_get_tag(&ptr, end, &obj_len,
1227 : MBEDTLS_ASN1_OCTET_STRING);
1228 : } else {
1229 6937 : ret = 1;
1230 : }
1231 :
1232 9224 : if (ret == 0) {
1233 2287 : *find_extension_data = ptr;
1234 2287 : *find_extension_data_len = obj_len;
1235 2287 : status = true;
1236 2287 : break;
1237 : }
1238 :
1239 : /* move to next*/
1240 6937 : ptr = extension_ptr + header_len + find_extension_len;
1241 6937 : ret = 0;
1242 : }
1243 :
1244 2302 : return status;
1245 : }
1246 :
1247 : /**
1248 : * Retrieve Extension data from one X.509 certificate.
1249 : *
1250 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
1251 : * @param[in] cert_size size of the X509 certificate in bytes.
1252 : * @param[in] oid Object identifier buffer
1253 : * @param[in] oid_size Object identifier buffer size
1254 : * @param[out] extension_data Extension bytes.
1255 : * @param[in, out] extension_data_size Extension bytes size.
1256 : *
1257 : * @retval true If the returned extension_data_size == 0, it means that cert and oid are valid, but the oid extension is not found;
1258 : * If the returned extension_data_size != 0, it means that cert and oid are valid, and the oid extension is found;
1259 : * @retval false If the returned extension_data_size == 0, it means that cert or oid are invalid;
1260 : * If the returned extension_data_size != 0, it means that cert and oid are valid, and the oid extension is found,
1261 : * but the store buffer is too small.
1262 : **/
1263 2302 : bool libspdm_x509_get_extension_data(const uint8_t *cert, size_t cert_size,
1264 : const uint8_t *oid, size_t oid_size,
1265 : uint8_t *extension_data,
1266 : size_t *extension_data_size)
1267 : {
1268 : mbedtls_x509_crt crt;
1269 : int ret;
1270 : bool status;
1271 : uint8_t *ptr;
1272 : uint8_t *end;
1273 : size_t obj_len;
1274 :
1275 2302 : ptr = NULL;
1276 2302 : end = NULL;
1277 2302 : obj_len = 0;
1278 :
1279 2302 : if (cert == NULL || cert_size == 0 || oid == NULL || oid_size == 0 ||
1280 : extension_data_size == NULL) {
1281 0 : if (extension_data_size != NULL) {
1282 0 : *extension_data_size = 0;
1283 : }
1284 0 : return false;
1285 : }
1286 :
1287 2302 : status = false;
1288 :
1289 2302 : mbedtls_x509_crt_init(&crt);
1290 :
1291 2302 : ret = mbedtls_x509_crt_parse_der(&crt, cert, cert_size);
1292 :
1293 2302 : if (ret == 0) {
1294 2302 : ptr = crt.v3_ext.p;
1295 2302 : end = crt.v3_ext.p + crt.v3_ext.len;
1296 2302 : ret = mbedtls_asn1_get_tag(&ptr, end, &obj_len,
1297 : MBEDTLS_ASN1_CONSTRUCTED |
1298 : MBEDTLS_ASN1_SEQUENCE);
1299 : }
1300 :
1301 2302 : if (ret == 0) {
1302 2302 : status = libspdm_internal_x509_find_extension_data(
1303 : ptr, end, oid, oid_size, &ptr, &obj_len);
1304 2302 : if (!status) {
1305 15 : status = true;
1306 15 : *extension_data_size = 0;
1307 15 : goto cleanup;
1308 : }
1309 : }
1310 :
1311 2287 : if (status) {
1312 2287 : if (*extension_data_size < obj_len) {
1313 6 : *extension_data_size = obj_len;
1314 6 : status = false;
1315 6 : goto cleanup;
1316 : }
1317 2281 : if (oid != NULL) {
1318 2281 : libspdm_copy_mem(extension_data, *extension_data_size, ptr, obj_len);
1319 : }
1320 2281 : *extension_data_size = obj_len;
1321 : } else {
1322 0 : *extension_data_size = 0;
1323 : }
1324 :
1325 2302 : cleanup:
1326 2302 : mbedtls_x509_crt_free(&crt);
1327 :
1328 2302 : return status;
1329 : }
1330 :
1331 : /**
1332 : * Retrieve the Validity from one X.509 certificate
1333 : *
1334 : * If cert is NULL, then return false.
1335 : * If CertIssuerSize is NULL, then return false.
1336 : * If this interface is not supported, then return false.
1337 : *
1338 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
1339 : * @param[in] cert_size size of the X509 certificate in bytes.
1340 : * @param[out] from notBefore Pointer to date_time object.
1341 : * @param[in,out] from_size notBefore date_time object size.
1342 : * @param[out] to notAfter Pointer to date_time object.
1343 : * @param[in,out] to_size notAfter date_time object size.
1344 : *
1345 : * Note: libspdm_x509_compare_date_time to compare date_time object
1346 : * x509SetDateTime to get a date_time object from a date_time_str
1347 : *
1348 : * @retval true The certificate Validity retrieved successfully.
1349 : * @retval false Invalid certificate, or Validity retrieve failed.
1350 : * @retval false This interface is not supported.
1351 : **/
1352 768 : bool libspdm_x509_get_validity(const uint8_t *cert, size_t cert_size,
1353 : uint8_t *from, size_t *from_size, uint8_t *to,
1354 : size_t *to_size)
1355 : {
1356 : mbedtls_x509_crt crt;
1357 : int ret;
1358 : bool status;
1359 : size_t t_size;
1360 : size_t f_size;
1361 : mbedtls_x509_time zero_time;
1362 :
1363 : /* Check input parameters.*/
1364 768 : if (cert == NULL || from_size == NULL || to_size == NULL ||
1365 : cert_size == 0) {
1366 0 : if (from_size != NULL) {
1367 0 : *from_size = 0;
1368 : }
1369 0 : if (to_size != NULL) {
1370 0 : *to_size = 0;
1371 : }
1372 0 : return false;
1373 : }
1374 :
1375 768 : status = false;
1376 :
1377 768 : mbedtls_x509_crt_init(&crt);
1378 768 : libspdm_zero_mem(&zero_time, sizeof(mbedtls_x509_time));
1379 :
1380 768 : ret = mbedtls_x509_crt_parse_der(&crt, cert, cert_size);
1381 :
1382 768 : if (ret == 0) {
1383 768 : f_size = sizeof(mbedtls_x509_time);
1384 768 : if ((libspdm_consttime_is_mem_equal(&zero_time, &(crt.valid_from), f_size)) &&
1385 0 : (libspdm_consttime_is_mem_equal(&zero_time, &(crt.valid_to), f_size))) {
1386 0 : *from_size = 0;
1387 0 : *to_size = 0;
1388 0 : status = true;
1389 0 : goto done;
1390 : }
1391 :
1392 768 : if (*from_size < f_size) {
1393 0 : *from_size = f_size;
1394 0 : goto done;
1395 : }
1396 768 : if (from != NULL) {
1397 768 : libspdm_copy_mem(from, *from_size, &(crt.valid_from), f_size);
1398 : }
1399 768 : *from_size = f_size;
1400 :
1401 768 : t_size = sizeof(mbedtls_x509_time);
1402 768 : if (*to_size < t_size) {
1403 0 : *to_size = t_size;
1404 0 : goto done;
1405 : }
1406 768 : if (to != NULL) {
1407 768 : libspdm_copy_mem(to, *to_size, &(crt.valid_to),
1408 : sizeof(mbedtls_x509_time));
1409 : }
1410 768 : *to_size = t_size;
1411 768 : status = true;
1412 : } else {
1413 0 : *from_size = 0;
1414 0 : *to_size = 0;
1415 : }
1416 :
1417 768 : done:
1418 768 : mbedtls_x509_crt_free(&crt);
1419 :
1420 768 : return status;
1421 : }
1422 :
1423 : /**
1424 : * Retrieve the key usage from one X.509 certificate.
1425 : *
1426 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
1427 : * @param[in] cert_size size of the X509 certificate in bytes.
1428 : * @param[out] usage key usage (LIBSPDM_CRYPTO_X509_KU_*)
1429 : *
1430 : * @retval true if the usage is no equal 0. The certificate key usage retrieved successfully.
1431 : * @retval true if the usage is equal 0. The certificate parse successfully, but the cert doesn't have key usage.
1432 : * @retval false Invalid certificate, or usage is NULL.
1433 : **/
1434 762 : bool libspdm_x509_get_key_usage(const uint8_t *cert, size_t cert_size,
1435 : size_t *usage)
1436 : {
1437 : mbedtls_x509_crt crt;
1438 : int ret;
1439 : bool status;
1440 :
1441 : /* Check input parameters.*/
1442 762 : if (cert == NULL || cert_size == 0 || usage == NULL) {
1443 0 : if (usage != NULL) {
1444 0 : *usage = 0;
1445 : }
1446 0 : return false;
1447 : }
1448 :
1449 762 : status = false;
1450 :
1451 762 : mbedtls_x509_crt_init(&crt);
1452 :
1453 762 : ret = mbedtls_x509_crt_parse_der(&crt, cert, cert_size);
1454 :
1455 762 : if (ret == 0) {
1456 762 : *usage = crt.MBEDTLS_PRIVATE(key_usage);
1457 762 : status = true;
1458 : } else {
1459 0 : *usage = 0;
1460 : }
1461 762 : mbedtls_x509_crt_free(&crt);
1462 :
1463 762 : return status;
1464 : }
1465 :
1466 : /**
1467 : * Retrieve the Extended key usage from one X.509 certificate.
1468 : *
1469 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
1470 : * @param[in] cert_size size of the X509 certificate in bytes.
1471 : * @param[out] usage key usage bytes.
1472 : * @param[in, out] usage_size key usage buffer sizs in bytes.
1473 : *
1474 : * @retval true If the returned usage_size == 0, it means that cert and oid are valid, but the Extended key usage is not found;
1475 : * If the returned usage_size != 0, it means that cert and oid are valid, and the Extended key usage is found;
1476 : * @retval false If the returned usage_size == 0, it means that cert or oid are invalid;
1477 : * If the returned usage_size != 0, it means that cert and oid are valid, and the Extended key usage is found,
1478 : * but the store buffer is too small.
1479 : **/
1480 768 : bool libspdm_x509_get_extended_key_usage(const uint8_t *cert,
1481 : size_t cert_size, uint8_t *usage,
1482 : size_t *usage_size)
1483 : {
1484 : bool status;
1485 :
1486 768 : if (cert == NULL || cert_size == 0 || usage_size == NULL) {
1487 0 : return false;
1488 : }
1489 :
1490 768 : status = libspdm_x509_get_extension_data(cert, cert_size,
1491 : m_libspdm_oid_ext_key_usage,
1492 : sizeof(m_libspdm_oid_ext_key_usage), usage,
1493 : usage_size);
1494 :
1495 768 : return status;
1496 : }
1497 :
1498 : /**
1499 : * Retrieve the basic constraints from one X.509 certificate.
1500 : *
1501 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
1502 : * @param[in] cert_size size of the X509 certificate in bytes.
1503 : * @param[out] basic_constraints basic constraints bytes.
1504 : * @param[in, out] basic_constraints_size basic constraints buffer sizs in bytes.
1505 : *
1506 : * @retval true If the returned basic_constraints_size == 0, it means that cert and oid are valid, but the basic_constraints is not found;
1507 : * If the returned basic_constraints_size != 0, it means that cert and oid are valid, and the basic_constraints is found;
1508 : * @retval false If the returned basic_constraints_size == 0, it means that cert or oid are invalid;
1509 : * If the returned basic_constraints_size != 0, it means that cert and oid are valid, and the basic_constraints is found,
1510 : * but the store buffer is too small.
1511 : **/
1512 762 : bool libspdm_x509_get_extended_basic_constraints(const uint8_t *cert,
1513 : size_t cert_size,
1514 : uint8_t *basic_constraints,
1515 : size_t *basic_constraints_size)
1516 : {
1517 : bool status;
1518 :
1519 762 : if (cert == NULL || cert_size == 0 || basic_constraints_size == NULL) {
1520 0 : return false;
1521 : }
1522 :
1523 762 : status = libspdm_x509_get_extension_data(cert, cert_size,
1524 : m_libspdm_oid_basic_constraints,
1525 : sizeof(m_libspdm_oid_basic_constraints),
1526 : basic_constraints,
1527 : basic_constraints_size);
1528 762 : return status;
1529 : }
1530 :
1531 : /**
1532 : * Return 0 if before <= after, 1 otherwise
1533 : **/
1534 1536 : static int32_t libspdm_internal_x509_check_time(const mbedtls_x509_time *before,
1535 : const mbedtls_x509_time *after)
1536 : {
1537 1536 : if (before->year > after->year) {
1538 1536 : return (1);
1539 : }
1540 :
1541 0 : if (before->year == after->year && before->mon > after->mon) {
1542 0 : return (1);
1543 : }
1544 :
1545 0 : if (before->year == after->year && before->mon == after->mon &&
1546 0 : before->day > after->day) {
1547 0 : return (1);
1548 : }
1549 :
1550 0 : if (before->year == after->year && before->mon == after->mon &&
1551 0 : before->day == after->day && before->hour > after->hour) {
1552 0 : return (1);
1553 : }
1554 :
1555 0 : if (before->year == after->year && before->mon == after->mon &&
1556 0 : before->day == after->day && before->hour == after->hour &&
1557 0 : before->min > after->min) {
1558 0 : return (1);
1559 : }
1560 :
1561 0 : if (before->year == after->year && before->mon == after->mon &&
1562 0 : before->day == after->day && before->hour == after->hour &&
1563 0 : before->min == after->min && before->sec > after->sec) {
1564 0 : return (1);
1565 : }
1566 :
1567 0 : return (0);
1568 : }
1569 :
1570 9216 : static int32_t libspdm_internal_atoi(const char *p_start, char const *p_end)
1571 : {
1572 9216 : const char *p = p_start;
1573 9216 : int32_t k = 0;
1574 30720 : while (p < p_end) {
1575 :
1576 : /* k = k * 2³ + k * 2¹ = k * 8 + k * 2 = k * 10*/
1577 :
1578 21504 : k = (k << 3) + (k << 1) + (*p) - '0';
1579 21504 : p++;
1580 : }
1581 9216 : return k;
1582 : }
1583 :
1584 : /**
1585 : * format a date_time object into DataTime buffer
1586 : *
1587 : * If date_time_str is NULL, then return false.
1588 : * If date_time_size is NULL, then return false.
1589 : * If this interface is not supported, then return false.
1590 : *
1591 : * @param[in] date_time_str date_time string like YYYYMMDDhhmmssZ
1592 : * Ref: https://www.w3.org/TR/NOTE-datetime
1593 : * Z stand for UTC time
1594 : * @param[out] date_time Pointer to a date_time object.
1595 : * @param[in,out] date_time_size date_time object buffer size.
1596 : *
1597 : * @retval RETURN_SUCCESS The date_time object create successfully.
1598 : * @retval RETURN_INVALID_PARAMETER If date_time_str is NULL.
1599 : * If date_time_size is NULL.
1600 : * If date_time is not NULL and *date_time_size is 0.
1601 : * If year month day hour minute second combination is invalid datetime.
1602 : * @retval RETURN_BUFFER_TOO_SMALL If the date_time is NULL. The required buffer size
1603 : * (including the final null) is returned in the
1604 : * date_time_size parameter.
1605 : * @retval RETURN_UNSUPPORTED The operation is not supported.
1606 : **/
1607 1536 : bool libspdm_x509_set_date_time(const char *date_time_str, void *date_time, size_t *date_time_size)
1608 : {
1609 : mbedtls_x509_time dt;
1610 :
1611 : int32_t year;
1612 : int32_t month;
1613 : int32_t day;
1614 : int32_t hour;
1615 : int32_t minute;
1616 : int32_t second;
1617 : bool status;
1618 : const char *p;
1619 :
1620 1536 : p = date_time_str;
1621 :
1622 1536 : year = libspdm_internal_atoi(p, p + 4);
1623 1536 : p += 4;
1624 1536 : month = libspdm_internal_atoi(p, p + 2);
1625 1536 : p += 2;
1626 1536 : day = libspdm_internal_atoi(p, p + 2);
1627 1536 : p += 2;
1628 1536 : hour = libspdm_internal_atoi(p, p + 2);
1629 1536 : p += 2;
1630 1536 : minute = libspdm_internal_atoi(p, p + 2);
1631 1536 : p += 2;
1632 1536 : second = libspdm_internal_atoi(p, p + 2);
1633 1536 : p += 2;
1634 1536 : dt.year = (int)year;
1635 1536 : dt.mon = (int)month;
1636 1536 : dt.day = (int)day;
1637 1536 : dt.hour = (int)hour;
1638 1536 : dt.min = (int)minute;
1639 1536 : dt.sec = (int)second;
1640 :
1641 1536 : if (*date_time_size < sizeof(mbedtls_x509_time)) {
1642 0 : *date_time_size = sizeof(mbedtls_x509_time);
1643 0 : status = false;
1644 0 : goto cleanup;
1645 : }
1646 1536 : if (date_time != NULL) {
1647 1536 : libspdm_copy_mem(date_time, *date_time_size, &dt, sizeof(mbedtls_x509_time));
1648 : }
1649 1536 : *date_time_size = sizeof(mbedtls_x509_time);
1650 1536 : status = true;
1651 1536 : cleanup:
1652 1536 : return status;
1653 : }
1654 :
1655 : /**
1656 : * Compare date_time1 object and date_time2 object.
1657 : *
1658 : * If date_time1 is NULL, then return -2.
1659 : * If date_time2 is NULL, then return -2.
1660 : * If date_time1 == date_time2, then return 0
1661 : * If date_time1 > date_time2, then return 1
1662 : * If date_time1 < date_time2, then return -1
1663 : *
1664 : * @param[in] date_time1 Pointer to a date_time Object
1665 : * @param[in] date_time2 Pointer to a date_time Object
1666 : *
1667 : * @retval 0 If date_time1 == date_time2
1668 : * @retval 1 If date_time1 > date_time2
1669 : * @retval -1 If date_time1 < date_time2
1670 : **/
1671 1536 : int32_t libspdm_x509_compare_date_time(const void *date_time1, const void *date_time2)
1672 : {
1673 1536 : if (date_time1 == NULL || date_time2 == NULL) {
1674 0 : return -2;
1675 : }
1676 1536 : if (libspdm_consttime_is_mem_equal(date_time2, date_time1, sizeof(mbedtls_x509_time))) {
1677 0 : return 0;
1678 : }
1679 1536 : if (libspdm_internal_x509_check_time((const mbedtls_x509_time *)date_time1,
1680 : (const mbedtls_x509_time *)date_time2) == 0) {
1681 0 : return -1;
1682 : } else {
1683 1536 : return 1;
1684 : }
1685 : }
1686 :
1687 2 : static bool libspdm_convert_subject_to_string(uint8_t *ptr, size_t obj_len,
1688 : uint8_t *buffer, int32_t buff_len)
1689 : {
1690 : bool ret;
1691 : uint8_t *end;
1692 : uint8_t *internal_p;
1693 :
1694 : libspdm_x509_subject_descriptor_t *cur;
1695 : /* X.509 DN attributes from RFC 5280, Appendix A.1. */
1696 2 : libspdm_x509_subject_descriptor_t x509_attrs[] =
1697 : {
1698 : { LIBSPDM_ADD_STRLEN( "CN" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_CN ),
1699 : MBEDTLS_ASN1_UTF8_STRING },
1700 : { LIBSPDM_ADD_STRLEN( "C" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_COUNTRY ),
1701 : MBEDTLS_ASN1_PRINTABLE_STRING },
1702 : { LIBSPDM_ADD_STRLEN( "O" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_ORGANIZATION ),
1703 : MBEDTLS_ASN1_UTF8_STRING },
1704 : { LIBSPDM_ADD_STRLEN( "L" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_LOCALITY ),
1705 : MBEDTLS_ASN1_UTF8_STRING },
1706 : { LIBSPDM_ADD_STRLEN( "R" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_PKCS9_EMAIL ),
1707 : MBEDTLS_ASN1_IA5_STRING },
1708 : { LIBSPDM_ADD_STRLEN( "OU" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_ORG_UNIT ),
1709 : MBEDTLS_ASN1_UTF8_STRING },
1710 : { LIBSPDM_ADD_STRLEN( "ST" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_STATE ),
1711 : MBEDTLS_ASN1_UTF8_STRING },
1712 : { LIBSPDM_ADD_STRLEN( "emailAddress" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_PKCS9_EMAIL ),
1713 : MBEDTLS_ASN1_IA5_STRING },
1714 : { LIBSPDM_ADD_STRLEN( "serialNumber" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_SERIAL_NUMBER ),
1715 : MBEDTLS_ASN1_PRINTABLE_STRING },
1716 : { LIBSPDM_ADD_STRLEN( "postalAddress" ),
1717 : LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_POSTAL_ADDRESS ), MBEDTLS_ASN1_PRINTABLE_STRING },
1718 : { LIBSPDM_ADD_STRLEN( "postalCode" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_POSTAL_CODE ),
1719 : MBEDTLS_ASN1_PRINTABLE_STRING },
1720 : { LIBSPDM_ADD_STRLEN( "dnQualifier" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_DN_QUALIFIER ),
1721 : MBEDTLS_ASN1_PRINTABLE_STRING },
1722 : { LIBSPDM_ADD_STRLEN( "title" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_TITLE ),
1723 : MBEDTLS_ASN1_UTF8_STRING },
1724 : { LIBSPDM_ADD_STRLEN( "SN" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_SUR_NAME ),
1725 : MBEDTLS_ASN1_UTF8_STRING },
1726 : { LIBSPDM_ADD_STRLEN( "GN" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_GIVEN_NAME ),
1727 : MBEDTLS_ASN1_UTF8_STRING },
1728 : { LIBSPDM_ADD_STRLEN( "initials" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_INITIALS ),
1729 : MBEDTLS_ASN1_UTF8_STRING },
1730 : { LIBSPDM_ADD_STRLEN( "pseudonym" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_PSEUDONYM ),
1731 : MBEDTLS_ASN1_UTF8_STRING },
1732 : { LIBSPDM_ADD_STRLEN( "generationQualifier" ),
1733 : LIBSPDM_ADD_STRLEN( MBEDTLS_OID_AT_GENERATION_QUALIFIER ),
1734 : MBEDTLS_ASN1_UTF8_STRING },
1735 : { LIBSPDM_ADD_STRLEN( "DC" ), LIBSPDM_ADD_STRLEN( MBEDTLS_OID_DOMAIN_COMPONENT ),
1736 : MBEDTLS_ASN1_IA5_STRING },
1737 : { NULL, 0, NULL, 0, MBEDTLS_ASN1_NULL }
1738 : };
1739 :
1740 2 : end = ptr + obj_len;
1741 :
1742 8 : while(ptr != end) {
1743 : /*SET*/
1744 6 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
1745 : LIBSPDM_CRYPTO_ASN1_SET | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1746 6 : if (!ret) {
1747 0 : return false;
1748 : }
1749 6 : internal_p = ptr;
1750 : /*move to next SET*/
1751 6 : ptr += obj_len;
1752 :
1753 : /*sequence*/
1754 6 : ret = libspdm_asn1_get_tag(&internal_p, end, &obj_len,
1755 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1756 6 : if (!ret) {
1757 0 : return false;
1758 : }
1759 :
1760 : /*OID*/
1761 6 : ret = libspdm_asn1_get_tag(&internal_p, end, &obj_len, LIBSPDM_CRYPTO_ASN1_OID);
1762 6 : if (!ret) {
1763 0 : return false;
1764 : }
1765 :
1766 24 : for (cur = x509_attrs; cur->name != NULL; cur++) {
1767 46 : if ((cur->oid_len == obj_len) &&
1768 22 : (libspdm_consttime_is_mem_equal(cur->oid, internal_p, obj_len))) {
1769 : /*Concat subject string*/
1770 :
1771 : /*for example: CN=*/
1772 6 : libspdm_copy_mem(buffer, buff_len, cur->name, cur->name_len);
1773 6 : buff_len = (int32_t)(buff_len - cur->name_len);
1774 6 : buffer += cur->name_len;
1775 6 : *buffer = '=';
1776 6 : buff_len--;
1777 6 : buffer++;
1778 :
1779 : /*move to string*/
1780 6 : internal_p += obj_len;
1781 6 : ret = libspdm_asn1_get_tag(&internal_p, end, &obj_len, cur->default_tag);
1782 6 : if (!ret) {
1783 0 : return false;
1784 : }
1785 :
1786 : /*for example: AU,*/
1787 6 : libspdm_copy_mem(buffer, buff_len, internal_p, obj_len);
1788 6 : buff_len = (int32_t)(buff_len - obj_len);
1789 6 : buffer += obj_len;
1790 6 : *buffer = ',';
1791 6 : buff_len--;
1792 6 : buffer++;
1793 :
1794 6 : if (buff_len < 0) {
1795 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"the buffer is too small"));
1796 0 : return false;
1797 : }
1798 6 : break;
1799 : }
1800 : }
1801 :
1802 : /*can not find the same oid, the subject is wrong*/
1803 6 : if (cur->name == NULL) {
1804 0 : return false;
1805 : }
1806 : }
1807 :
1808 2 : *buffer = '\0';
1809 2 : return true;
1810 : }
1811 :
1812 : /**
1813 : * Set all attributes object form req_info to CSR
1814 : *
1815 : * @param[in] req CSR to set attributes
1816 : * @param[in] req_info requester info to gen CSR
1817 : * @param[in] req_info_len The len of requester info
1818 : *
1819 : * @retval true Success Set.
1820 : * @retval false Set failed.
1821 : **/
1822 2 : bool libspdm_set_attribute_for_req(mbedtls_x509write_csr *req,
1823 : uint8_t *req_info, size_t req_info_len,
1824 : uint8_t *pub_key_der, size_t pub_key_der_len)
1825 : {
1826 : uint8_t *ptr;
1827 : int32_t length;
1828 : size_t obj_len;
1829 : bool ret;
1830 : uint8_t *end;
1831 : uint8_t *ptr_old;
1832 :
1833 : uint8_t *oid;
1834 : size_t oid_len;
1835 : uint8_t *val;
1836 : size_t val_len;
1837 :
1838 : uint8_t *pkinfo;
1839 : size_t pkinfo_len;
1840 : uint8_t buffer[LIBSPDM_MAX_SUBJECT_BUFFER_SIZE];
1841 :
1842 2 : length = (int32_t)req_info_len;
1843 2 : ptr = req_info;
1844 2 : obj_len = 0;
1845 2 : end = ptr + length;
1846 2 : ret = false;
1847 :
1848 2 : if (req_info == NULL) {
1849 0 : return false;
1850 : }
1851 :
1852 : /*req_info sequence, all req_info format is ok because the req_info has been verified before*/
1853 2 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
1854 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1855 :
1856 : /*integer:version*/
1857 2 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len, LIBSPDM_CRYPTO_ASN1_INTEGER);
1858 : /*check req_info version. spec PKCS#10: It shall be 0 for this version of the standard.*/
1859 2 : if ((obj_len != 1) || (*ptr != 0)) {
1860 0 : return false;
1861 : }
1862 2 : ptr += obj_len;
1863 :
1864 : /*sequence:subject name*/
1865 2 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
1866 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1867 :
1868 : /**/
1869 2 : libspdm_zero_mem(buffer, sizeof(buffer));
1870 2 : ret = libspdm_convert_subject_to_string(ptr, obj_len, buffer, LIBSPDM_MAX_SUBJECT_BUFFER_SIZE);
1871 2 : if (!ret) {
1872 0 : return false;
1873 : }
1874 :
1875 : /*set subject name*/
1876 2 : ret = mbedtls_x509write_csr_set_subject_name(req, (const char *)buffer);
1877 2 : if (ret != 0) {
1878 0 : return false;
1879 : }
1880 :
1881 2 : ptr += obj_len;
1882 :
1883 2 : pkinfo = ptr;
1884 : /*sequence:subject pkinfo*/
1885 2 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
1886 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1887 :
1888 2 : pkinfo_len = obj_len + ptr - pkinfo;
1889 : /*check the public key info*/
1890 4 : if (!((pkinfo_len == pub_key_der_len) &&
1891 2 : (libspdm_consttime_is_mem_equal(pub_key_der, pkinfo, pkinfo_len)))) {
1892 0 : return false;
1893 : }
1894 :
1895 2 : ptr += obj_len;
1896 :
1897 : /*[0]: attributes*/
1898 2 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
1899 : LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC |
1900 : LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1901 : /*there is no attributes*/
1902 2 : if (ptr == end) {
1903 0 : return true;
1904 : }
1905 :
1906 : /*there is some attributes object: 1,2 ...*/
1907 4 : while (ret)
1908 : {
1909 2 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
1910 : LIBSPDM_CRYPTO_ASN1_SEQUENCE |
1911 : LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1912 2 : if (ret) {
1913 : /*save old position*/
1914 2 : ptr_old = ptr;
1915 :
1916 : /*move to the next sequence*/
1917 2 : ptr += obj_len;
1918 :
1919 : /*get attributes oid*/
1920 2 : ret = libspdm_asn1_get_tag(&ptr_old, end, &obj_len, LIBSPDM_CRYPTO_ASN1_OID);
1921 2 : if (!ret) {
1922 0 : return false;
1923 : }
1924 2 : oid = ptr_old;
1925 2 : oid_len = obj_len;
1926 :
1927 2 : ptr_old += obj_len;
1928 : /*get attributes val*/
1929 2 : ret = libspdm_asn1_get_tag(&ptr_old, end, &obj_len,
1930 : LIBSPDM_CRYPTO_ASN1_SET |
1931 : LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1932 2 : if (!ret) {
1933 0 : return false;
1934 : }
1935 2 : ret = libspdm_asn1_get_tag(&ptr_old, end, &obj_len, LIBSPDM_CRYPTO_ASN1_UTF8_STRING);
1936 2 : if (!ret) {
1937 0 : return false;
1938 : }
1939 2 : val = ptr_old;
1940 2 : val_len = obj_len;
1941 :
1942 : /*set attributes*/
1943 2 : ret = mbedtls_x509write_csr_set_extension(req, (const char *)oid, oid_len, 0, val,
1944 : val_len);
1945 :
1946 2 : if (ret) {
1947 0 : return false;
1948 : }
1949 :
1950 : } else {
1951 0 : break;
1952 : }
1953 : }
1954 :
1955 2 : if (ptr == end) {
1956 2 : return true;
1957 : } else {
1958 0 : return false;
1959 : }
1960 : }
1961 :
1962 : /**
1963 : * Gen CSR
1964 : *
1965 : * @param[in] hash_nid hash algo for sign
1966 : * @param[in] asym_nid asym algo for sign
1967 : *
1968 : * @param[in] requester_info requester info to gen CSR
1969 : * @param[in] requester_info_length The len of requester info
1970 : *
1971 : * @param[in] is_ca if true, set basic_constraints: CA:true; Otherwise, set to false.
1972 : *
1973 : * @param[in] context Pointer to asymmetric context
1974 : * @param[in] subject_name Subject name: should be break with ',' in the middle
1975 : * example: "C=AA,CN=BB"
1976 : * Subject names should contain a comma-separated list of OID types and values:
1977 : * The valid OID type name is in:
1978 : * {"CN", "commonName", "C", "countryName", "O", "organizationName","L",
1979 : * "OU", "organizationalUnitName", "ST", "stateOrProvinceName", "emailAddress",
1980 : * "serialNumber", "postalAddress", "postalCode", "dnQualifier", "title",
1981 : * "SN","givenName","GN", "initials", "pseudonym", "generationQualifier", "domainComponent", "DC"}.
1982 : * Note: The object of C and countryName should be CSR Supported Country Codes
1983 : *
1984 : * @param[in, out] csr_len For input, csr_len is the size of store CSR buffer.
1985 : * For output, csr_len is CSR len for DER format
1986 : * @param[in, out] csr_pointer For input, csr_pointer is buffer address to store CSR.
1987 : * For output, csr_pointer is address for stored CSR.
1988 : * The csr_pointer address will be changed.
1989 : * @param[in] base_cert An optional leaf certificate whose
1990 : * extensions should be copied to the CSR
1991 : *
1992 : * @retval true Success.
1993 : * @retval false Failed to gen CSR.
1994 : **/
1995 6 : bool libspdm_gen_x509_csr(size_t hash_nid, size_t asym_nid,
1996 : uint8_t *requester_info, size_t requester_info_length,
1997 : bool is_ca,
1998 : void *context, char *subject_name,
1999 : size_t *csr_len, uint8_t *csr_pointer,
2000 : void *base_cert)
2001 : {
2002 : int ret;
2003 : bool result;
2004 : size_t csr_buffer_size;
2005 :
2006 : mbedtls_x509write_csr req;
2007 : mbedtls_md_type_t md_alg;
2008 : mbedtls_asn1_sequence extns;
2009 : mbedtls_asn1_sequence *next_oid;
2010 : mbedtls_x509_buf buf;
2011 : mbedtls_x509_crt *cert;
2012 : mbedtls_pk_context key;
2013 :
2014 : uint8_t pubkey_buffer[LIBSPDM_MAX_PUBKEY_DER_BUFFER_SIZE];
2015 : uint8_t *pubkey_der_data;
2016 : size_t pubkey_der_len;
2017 : size_t oid_tag_len;
2018 :
2019 : /*basic_constraints: CA: false */
2020 : #define BASIC_CONSTRAINTS_STRING_FALSE {0x30, 0x00}
2021 6 : uint8_t basic_constraints_false[] = BASIC_CONSTRAINTS_STRING_FALSE;
2022 :
2023 : /*basic_constraints: CA: true */
2024 : #define BASIC_CONSTRAINTS_STRING_TRUE {0x30, 0x03, 0x01, 0x01, 0xFF}
2025 6 : uint8_t basic_constraints_true[] = BASIC_CONSTRAINTS_STRING_TRUE;
2026 :
2027 : /* Init */
2028 6 : mbedtls_x509write_csr_init(&req);
2029 6 : mbedtls_pk_init(&key);
2030 6 : csr_buffer_size = *csr_len;
2031 6 : next_oid = NULL;
2032 :
2033 6 : ret = 1;
2034 6 : switch (asym_nid)
2035 : {
2036 0 : case LIBSPDM_CRYPTO_NID_RSASSA2048:
2037 : case LIBSPDM_CRYPTO_NID_RSAPSS2048:
2038 : case LIBSPDM_CRYPTO_NID_RSASSA3072:
2039 : case LIBSPDM_CRYPTO_NID_RSAPSS3072:
2040 : case LIBSPDM_CRYPTO_NID_RSASSA4096:
2041 : case LIBSPDM_CRYPTO_NID_RSAPSS4096:
2042 0 : ret = mbedtls_pk_setup(&key, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA));
2043 0 : if (ret != 0) {
2044 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"failed\n ! mbedtls_pk_setup %d", ret));
2045 0 : goto free_all;
2046 : }
2047 0 : ret = mbedtls_rsa_copy(mbedtls_pk_rsa(key), (mbedtls_rsa_context *)context);
2048 0 : if (ret != 0) {
2049 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"failed\n ! mbedtls_rsa_copy %d", ret));
2050 0 : goto free_all;
2051 : }
2052 0 : ret = mbedtls_rsa_complete(mbedtls_pk_rsa(key));
2053 0 : if (ret != 0) {
2054 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"failed\n ! mbedtls_rsa_complete %d", ret));
2055 0 : goto free_all;
2056 : }
2057 0 : break;
2058 6 : case LIBSPDM_CRYPTO_NID_ECDSA_NIST_P256:
2059 : case LIBSPDM_CRYPTO_NID_ECDSA_NIST_P384:
2060 : case LIBSPDM_CRYPTO_NID_ECDSA_NIST_P521:
2061 6 : ret = mbedtls_pk_setup(&key, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
2062 6 : if (ret != 0) {
2063 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"failed\n ! mbedtls_pk_setup %d", ret));
2064 0 : goto free_all;
2065 : }
2066 : /*mbedtls_ecdh_context include mbedtls_ecdsa_context,can be treated as mbedtls_ecdsa_context*/
2067 6 : ret = mbedtls_ecdsa_from_keypair(mbedtls_pk_ec(key), (mbedtls_ecdsa_context *)context);
2068 6 : if (ret != 0) {
2069 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"failed\n ! mbedtls_ecdsa_from_keypair %d", ret));
2070 0 : goto free_all;
2071 : }
2072 6 : break;
2073 0 : default:
2074 0 : return false;
2075 : }
2076 :
2077 6 : switch (hash_nid)
2078 : {
2079 6 : case LIBSPDM_CRYPTO_NID_SHA256:
2080 6 : md_alg = MBEDTLS_MD_SHA256;
2081 6 : break;
2082 0 : case LIBSPDM_CRYPTO_NID_SHA384:
2083 0 : md_alg = MBEDTLS_MD_SHA384;
2084 0 : break;
2085 0 : case LIBSPDM_CRYPTO_NID_SHA512:
2086 0 : md_alg = MBEDTLS_MD_SHA512;
2087 0 : break;
2088 0 : case LIBSPDM_CRYPTO_NID_SHA3_256:
2089 0 : md_alg = MBEDTLS_MD_SHA3_256;
2090 0 : break;
2091 0 : case LIBSPDM_CRYPTO_NID_SHA3_384:
2092 0 : md_alg = MBEDTLS_MD_SHA3_384;
2093 0 : break;
2094 0 : case LIBSPDM_CRYPTO_NID_SHA3_512:
2095 0 : md_alg = MBEDTLS_MD_SHA3_512;
2096 0 : break;
2097 0 : default:
2098 0 : ret = 1;
2099 0 : goto free_all;
2100 : }
2101 :
2102 : /* Set the md alg */
2103 6 : mbedtls_x509write_csr_set_md_alg(&req, md_alg);
2104 :
2105 : /* Set the subject name */
2106 6 : if (subject_name != NULL) {
2107 6 : ret = mbedtls_x509write_csr_set_subject_name(&req, subject_name);
2108 6 : if (ret != 0) {
2109 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
2110 : "failed\n ! mbedtls_x509write_csr_set_subject_name returned %d", ret));
2111 0 : goto free_all;
2112 : }
2113 : }
2114 :
2115 6 : libspdm_zero_mem(pubkey_buffer, sizeof(pubkey_buffer));
2116 6 : pubkey_der_len = mbedtls_pk_write_pubkey_der(&key, pubkey_buffer, sizeof(pubkey_buffer));
2117 6 : if (pubkey_der_len > 0) {
2118 : /*Note: data is written at the end of the buffer!*/
2119 6 : pubkey_der_data = pubkey_buffer + sizeof(pubkey_buffer) - pubkey_der_len;
2120 : } else {
2121 0 : goto free_all;
2122 : }
2123 :
2124 : /* requester info parse
2125 : * check the req_info version and subjectPKInfo;
2126 : * get attribute and subject from req_info and set them to CSR;
2127 : **/
2128 6 : if (requester_info_length != 0) {
2129 2 : result = libspdm_set_attribute_for_req(&req, requester_info, requester_info_length,
2130 : pubkey_der_data, pubkey_der_len);
2131 2 : if (!result) {
2132 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"set_attribute failed !\n"));
2133 0 : goto free_all;
2134 : }
2135 : }
2136 :
2137 : /* Set key */
2138 6 : mbedtls_x509write_csr_set_key(&req, &key);
2139 :
2140 : /*set basicConstraints*/
2141 6 : if (mbedtls_x509write_csr_set_extension(&req, MBEDTLS_OID_BASIC_CONSTRAINTS,
2142 : MBEDTLS_OID_SIZE(MBEDTLS_OID_BASIC_CONSTRAINTS),
2143 : 0,
2144 : is_ca ? basic_constraints_true : basic_constraints_false,
2145 : is_ca ?
2146 : sizeof(basic_constraints_true) :
2147 : sizeof(basic_constraints_false)
2148 : ) != 0) {
2149 0 : ret = 1;
2150 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
2151 : "mbedtls_x509write_csr_set_extension set basicConstraints failed \n"));
2152 0 : goto free_all;
2153 : }
2154 :
2155 6 : if (base_cert != NULL) {
2156 6 : cert = base_cert;
2157 6 : buf = cert->v3_ext;
2158 6 : if (mbedtls_asn1_get_sequence_of(&buf.p, buf.p + buf.len, &extns,
2159 : MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
2160 0 : ret = 1;
2161 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
2162 : "mbedtls_x509write_csr_set_extension unable to get sequence\n"));
2163 0 : goto free_all;
2164 : }
2165 :
2166 6 : next_oid = &extns;
2167 : }
2168 :
2169 42 : while (next_oid) {
2170 36 : if (mbedtls_asn1_get_tag(&(next_oid->buf.p), next_oid->buf.p + next_oid->buf.len,
2171 : &oid_tag_len, MBEDTLS_ASN1_OID)) {
2172 0 : ret = 1;
2173 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
2174 : "mbedtls_x509write_csr_set_extension unable to get OID tag\n"));
2175 0 : goto free_all;
2176 : }
2177 :
2178 36 : if (MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_BASIC_CONSTRAINTS, next_oid->buf.p, oid_tag_len) == 0) {
2179 6 : next_oid = next_oid->next;
2180 6 : continue;
2181 : }
2182 :
2183 30 : if (MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER, next_oid->buf.p,
2184 : oid_tag_len) == 0) {
2185 0 : next_oid = next_oid->next;
2186 0 : continue;
2187 : }
2188 :
2189 30 : if (mbedtls_x509write_csr_set_extension(&req, (const char *)next_oid->buf.p,
2190 : oid_tag_len, 0,
2191 30 : next_oid->buf.p + oid_tag_len,
2192 30 : next_oid->buf.len - oid_tag_len
2193 : ) != 0) {
2194 0 : ret = 1;
2195 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
2196 : "mbedtls_x509write_csr_set_extension set custom OID failed \n"));
2197 0 : goto free_all;
2198 : }
2199 :
2200 30 : next_oid = next_oid->next;
2201 : }
2202 :
2203 : /*csr data is written at the end of the buffer*/
2204 6 : ret = mbedtls_x509write_csr_der(&req, csr_pointer, csr_buffer_size, libspdm_myrand, NULL);
2205 6 : if (ret <= 0) {
2206 0 : ret = 1;
2207 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"mbedtls_x509write_csr_der failed \n"));
2208 0 : goto free_all;
2209 : }
2210 :
2211 6 : *csr_len = (size_t)ret;
2212 : /*make csr_pointer store csr data*/
2213 6 : memmove(csr_pointer, csr_pointer + csr_buffer_size - *csr_len, *csr_len);
2214 :
2215 6 : ret = 0;
2216 6 : free_all:
2217 6 : mbedtls_x509write_csr_free(&req);
2218 6 : mbedtls_pk_free(&key);
2219 :
2220 6 : return(ret == 0);
2221 : }
2222 :
2223 : #endif
|