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 : #include "internal/libspdm_crypt_lib.h"
8 :
9 : #if LIBSPDM_CERT_PARSE_SUPPORT
10 :
11 : /**pathLenConstraint is optional.
12 : * In https://www.pkisolutions.com/basic-constraints-certificate-extension/:
13 : * pathLenConstraint: How many CAs are allowed in the chain below current CA certificate.
14 : * This setting has no meaning for end entity certificates.
15 : **/
16 :
17 : /**
18 : * leaf cert spdm extension len
19 : * len > 2 * (spdm id-DMTF-spdm size + 2)
20 : **/
21 :
22 : #ifndef LIBSPDM_MAX_EXTENSION_LEN
23 : #define LIBSPDM_MAX_EXTENSION_LEN 30
24 : #endif
25 :
26 : #ifndef LIBSPDM_MAX_NAME_SIZE
27 : #define LIBSPDM_MAX_NAME_SIZE 100
28 : #endif
29 :
30 : /*max public key encryption algo oid len*/
31 : #ifndef LIBSPDM_MAX_ENCRYPTION_ALGO_OID_LEN
32 : #define LIBSPDM_MAX_ENCRYPTION_ALGO_OID_LEN 10
33 : #endif
34 :
35 : /* Maximum size of basicConstraints. This includes space for both cA and pathLen. */
36 : #ifndef LIBSPDM_MAX_BASIC_CONSTRAINTS_CA_LEN
37 : #define LIBSPDM_MAX_BASIC_CONSTRAINTS_CA_LEN 10
38 : #endif
39 :
40 : /**
41 : * 0x02 is integer;
42 : * 0x82 indicates that the length is expressed in two bytes;
43 : * 0x01 and 0x01 are rsa key len;
44 : **/
45 : #if (LIBSPDM_RSA_SSA_2048_SUPPORT) || (LIBSPDM_RSA_PSS_2048_SUPPORT)
46 : #define KEY_ENCRY_ALGO_RSA2048_FLAG {0x02, 0x82, 0x01, 0x01}
47 : /* the other case is ASN1 code different when integer is 1 on highest position*/
48 : #define KEY_ENCRY_ALGO_RSA2048_FLAG_OTHER {0x02, 0x82, 0x01, 0x00}
49 : #endif
50 : #if (LIBSPDM_RSA_SSA_3072_SUPPORT) || (LIBSPDM_RSA_PSS_3072_SUPPORT)
51 : #define KEY_ENCRY_ALGO_RSA3072_FLAG {0x02, 0x82, 0x01, 0x81}
52 : /* the other case is ASN1 code different when integer is 1 on highest position*/
53 : #define KEY_ENCRY_ALGO_RSA3072_FLAG_OTHER {0x02, 0x82, 0x01, 0x80}
54 : #endif
55 : #if (LIBSPDM_RSA_SSA_4096_SUPPORT) || (LIBSPDM_RSA_PSS_4096_SUPPORT)
56 : #define KEY_ENCRY_ALGO_RSA4096_FLAG {0x02, 0x82, 0x02, 0x01}
57 : /* the other case is ASN1 code different when integer is 1 on highest position*/
58 : #define KEY_ENCRY_ALGO_RSA4096_FLAG_OTHER {0x02, 0x82, 0x02, 0x00}
59 : #endif
60 :
61 : /**
62 : * https://oidref.com/1.2.840.10045.3.1.7
63 : * ECC256 curve OID: 1.2.840.10045.3.1.7
64 : * https://oidref.com/1.3.132.0.34
65 : * ECC384 curve OID: 1.3.132.0.34
66 : * https://oidref.com/1.3.132.0.35
67 : * ECC521 curve OID: 1.3.132.0.35
68 : **/
69 : #if LIBSPDM_ECDSA_P256_SUPPORT
70 : #define KEY_ENCRY_ALGO_ECC256_OID {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07}
71 : #endif
72 : #if LIBSPDM_ECDSA_P384_SUPPORT
73 : #define KEY_ENCRY_ALGO_ECC384_OID {0x2B, 0x81, 0x04, 0x00, 0x22}
74 : #endif
75 : #if LIBSPDM_ECDSA_P521_SUPPORT
76 : #define KEY_ENCRY_ALGO_ECC521_OID {0x2B, 0x81, 0x04, 0x00, 0x23}
77 : #endif
78 :
79 : /**
80 : * EDxxx OID: https://datatracker.ietf.org/doc/html/rfc8420
81 : * ED448 OID: 1.3.101.113
82 : * ED25519 OID: 1.3.101.112
83 : **/
84 : #if LIBSPDM_EDDSA_ED25519_SUPPORT
85 : #define ENCRY_ALGO_ED25519_OID {0x2B, 0x65, 0x70}
86 : #endif
87 : #if LIBSPDM_EDDSA_ED448_SUPPORT
88 : #define ENCRY_ALGO_ED448_OID {0x2B, 0x65, 0x71}
89 : #endif
90 :
91 : /*leaf cert basic_constraints false case1: CA: false and CA object is excluded */
92 : #define BASIC_CONSTRAINTS_STRING_FALSE_CASE1 {0x30, 0x00}
93 :
94 : /*leaf cert basic_constraints false case2: CA: false */
95 : #define BASIC_CONSTRAINTS_STRING_FALSE_CASE2 {0x30, 0x03, 0x01, 0x01, 0x00}
96 :
97 : /*leaf cert basic_constraints true case: CA: true */
98 : #define BASIC_CONSTRAINTS_STRING_TRUE_CASE {0x30, 0x03, 0x01, 0x01, 0xFF}
99 :
100 : /**
101 : * Retrieve the asymmetric public key from one DER-encoded X509 certificate.
102 : *
103 : * @param cert Pointer to the DER-encoded X509 certificate.
104 : * @param cert_size Size of the X509 certificate in bytes.
105 : * @param context Pointer to newly generated asymmetric context which contain the retrieved public
106 : * key component. Use libspdm_asym_free() function to free the resource.
107 : *
108 : * @retval true public key was retrieved successfully.
109 : * @retval false Fail to retrieve public key from X509 certificate.
110 : **/
111 : typedef bool (*libspdm_asym_get_public_key_from_x509_func)(const uint8_t *cert,
112 : size_t cert_size,
113 : void **context);
114 :
115 : /**
116 : * Return asymmetric GET_PUBLIC_KEY_FROM_X509 function, based upon the negotiated asymmetric algorithm.
117 : *
118 : * @param base_asym_algo SPDM base_asym_algo
119 : *
120 : * @return asymmetric GET_PUBLIC_KEY_FROM_X509 function
121 : **/
122 : static libspdm_asym_get_public_key_from_x509_func
123 1022 : libspdm_get_asym_get_public_key_from_x509(uint32_t base_asym_algo)
124 : {
125 1022 : switch (base_asym_algo) {
126 100 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048:
127 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072:
128 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096:
129 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048:
130 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072:
131 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096:
132 : #if (LIBSPDM_RSA_SSA_SUPPORT) || (LIBSPDM_RSA_PSS_SUPPORT)
133 : #if !LIBSPDM_RSA_SSA_2048_SUPPORT
134 : LIBSPDM_ASSERT(base_asym_algo!= SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048);
135 : #endif
136 : #if !LIBSPDM_RSA_SSA_3072_SUPPORT
137 : LIBSPDM_ASSERT(base_asym_algo!= SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072);
138 : #endif
139 : #if !LIBSPDM_RSA_SSA_4096_SUPPORT
140 : LIBSPDM_ASSERT(base_asym_algo!= SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096);
141 : #endif
142 : #if !LIBSPDM_RSA_PSS_2048_SUPPORT
143 : LIBSPDM_ASSERT(base_asym_algo!= SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048);
144 : #endif
145 : #if !LIBSPDM_RSA_PSS_3072_SUPPORT
146 : LIBSPDM_ASSERT(base_asym_algo!= SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072);
147 : #endif
148 : #if !LIBSPDM_RSA_PSS_4096_SUPPORT
149 : LIBSPDM_ASSERT(base_asym_algo!= SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096);
150 : #endif
151 100 : return libspdm_rsa_get_public_key_from_x509;
152 : #else
153 : LIBSPDM_ASSERT(false);
154 : break;
155 : #endif
156 922 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256:
157 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384:
158 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521:
159 : #if LIBSPDM_ECDSA_SUPPORT
160 : #if !LIBSPDM_ECDSA_P256_SUPPORT
161 : LIBSPDM_ASSERT(base_asym_algo!= SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256);
162 : #endif
163 : #if !LIBSPDM_ECDSA_P384_SUPPORT
164 : LIBSPDM_ASSERT(base_asym_algo!= SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384);
165 : #endif
166 : #if !LIBSPDM_ECDSA_P521_SUPPORT
167 : LIBSPDM_ASSERT(base_asym_algo!= SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521);
168 : #endif
169 922 : return libspdm_ec_get_public_key_from_x509;
170 : #else
171 : LIBSPDM_ASSERT(false);
172 : break;
173 : #endif
174 0 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED25519:
175 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED448:
176 : #if (LIBSPDM_EDDSA_ED25519_SUPPORT) || (LIBSPDM_EDDSA_ED448_SUPPORT)
177 : #if !LIBSPDM_EDDSA_ED25519_SUPPORT
178 : LIBSPDM_ASSERT(base_asym_algo!= SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED25519);
179 : #endif
180 : #if !LIBSPDM_EDDSA_ED448_SUPPORT
181 : LIBSPDM_ASSERT(base_asym_algo!= SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED448);
182 : #endif
183 : return libspdm_ecd_get_public_key_from_x509;
184 : #else
185 0 : LIBSPDM_ASSERT(false);
186 0 : break;
187 : #endif
188 0 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_SM2_ECC_SM2_P256:
189 : #if LIBSPDM_SM2_DSA_SUPPORT
190 : return libspdm_sm2_get_public_key_from_x509;
191 : #else
192 0 : LIBSPDM_ASSERT(false);
193 0 : break;
194 : #endif
195 0 : default:
196 0 : LIBSPDM_ASSERT(false);
197 0 : break;
198 : }
199 :
200 0 : return NULL;
201 : }
202 :
203 : /**
204 : * Retrieve the asymmetric public key from one DER-encoded X509 certificate,
205 : * based upon negotiated asymmetric algorithm.
206 : *
207 : * @param base_asym_algo SPDM base_asym_algo
208 : * @param cert Pointer to the DER-encoded X509 certificate.
209 : * @param cert_size size of the X509 certificate in bytes.
210 : * @param context Pointer to newly generated asymmetric context which contain the retrieved public key component.
211 : * Use libspdm_asym_free() function to free the resource.
212 : *
213 : * @retval true public key was retrieved successfully.
214 : * @retval false Fail to retrieve public key from X509 certificate.
215 : **/
216 1022 : bool libspdm_asym_get_public_key_from_x509(uint32_t base_asym_algo,
217 : const uint8_t *cert,
218 : size_t cert_size,
219 : void **context)
220 : {
221 : libspdm_asym_get_public_key_from_x509_func get_public_key_from_x509_function;
222 1022 : get_public_key_from_x509_function = libspdm_get_asym_get_public_key_from_x509(base_asym_algo);
223 1022 : if (get_public_key_from_x509_function == NULL) {
224 0 : return false;
225 : }
226 1022 : return get_public_key_from_x509_function(cert, cert_size, context);
227 : }
228 :
229 : /**
230 : * Return requester asymmetric GET_PUBLIC_KEY_FROM_X509 function, based upon the negotiated requester asymmetric algorithm.
231 : *
232 : * @param req_base_asym_alg SPDM req_base_asym_alg
233 : *
234 : * @return requester asymmetric GET_PUBLIC_KEY_FROM_X509 function
235 : **/
236 : static libspdm_asym_get_public_key_from_x509_func
237 0 : libspdm_get_req_asym_get_public_key_from_x509(uint16_t req_base_asym_alg)
238 : {
239 0 : return libspdm_get_asym_get_public_key_from_x509(req_base_asym_alg);
240 : }
241 :
242 : /**
243 : * Retrieve the asymmetric public key from one DER-encoded X509 certificate,
244 : * based upon negotiated requester asymmetric algorithm.
245 : *
246 : * @param req_base_asym_alg SPDM req_base_asym_alg
247 : * @param cert Pointer to the DER-encoded X509 certificate.
248 : * @param cert_size size of the X509 certificate in bytes.
249 : * @param context Pointer to newly generated asymmetric context which contain the retrieved public key component.
250 : * Use libspdm_asym_free() function to free the resource.
251 : *
252 : * @retval true public key was retrieved successfully.
253 : * @retval false Fail to retrieve public key from X509 certificate.
254 : **/
255 0 : bool libspdm_req_asym_get_public_key_from_x509(uint16_t req_base_asym_alg,
256 : const uint8_t *cert,
257 : size_t cert_size,
258 : void **context)
259 : {
260 : libspdm_asym_get_public_key_from_x509_func get_public_key_from_x509_function;
261 : get_public_key_from_x509_function =
262 0 : libspdm_get_req_asym_get_public_key_from_x509(req_base_asym_alg);
263 0 : if (get_public_key_from_x509_function == NULL) {
264 0 : return false;
265 : }
266 0 : return get_public_key_from_x509_function(cert, cert_size, context);
267 : }
268 :
269 : /**
270 : * Check the X509 DataTime is within a valid range.
271 : *
272 : * @param spdm_context A pointer to the SPDM context.
273 : * @param from notBefore Pointer to date_time object.
274 : * @param from_size notBefore date_time object size.
275 : * @param to notAfter Pointer to date_time object.
276 : * @param to_size notAfter date_time object size.
277 : *
278 : * @retval true verification pass.
279 : * @retval false verification fail.
280 : **/
281 768 : static bool libspdm_internal_x509_date_time_check(const uint8_t *from,
282 : size_t from_size,
283 : const uint8_t *to,
284 : size_t to_size)
285 : {
286 : int32_t ret;
287 : bool status;
288 : uint8_t f0[64];
289 : uint8_t t0[64];
290 : size_t f0_size;
291 : size_t t0_size;
292 :
293 768 : f0_size = 64;
294 768 : t0_size = 64;
295 :
296 768 : status = libspdm_x509_set_date_time("19700101000000Z", f0, &f0_size);
297 768 : if (!status) {
298 0 : return false;
299 : }
300 :
301 768 : status = libspdm_x509_set_date_time("99991231235959Z", t0, &t0_size);
302 768 : if (!status) {
303 0 : return false;
304 : }
305 :
306 : /* from >= f0*/
307 768 : ret = libspdm_x509_compare_date_time(from, f0);
308 768 : if (ret < 0) {
309 0 : return false;
310 : }
311 :
312 : /* to <= t0*/
313 768 : ret = libspdm_x509_compare_date_time(t0, to);
314 768 : if (ret < 0) {
315 0 : return false;
316 : }
317 :
318 768 : return true;
319 : }
320 :
321 : /**
322 : * This function returns the SPDM public key encryption algorithm OID len.
323 : *
324 : * @param[in] base_asym_algo SPDM base_asym_algo
325 : *
326 : * @return SPDM public key encryption algorithms OID len.
327 : **/
328 1528 : static uint32_t libspdm_get_public_key_algo_OID_len(uint32_t base_asym_algo)
329 : {
330 1528 : switch (base_asym_algo) {
331 116 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048:
332 : #if LIBSPDM_RSA_SSA_2048_SUPPORT
333 116 : return 4;
334 : #else
335 : return 0;
336 : #endif
337 0 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048:
338 : #if LIBSPDM_RSA_PSS_2048_SUPPORT
339 0 : return 4;
340 : #else
341 : return 0;
342 : #endif
343 6 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072:
344 : #if LIBSPDM_RSA_SSA_3072_SUPPORT
345 6 : return 4;
346 : #else
347 : return 0;
348 : #endif
349 0 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072:
350 : #if LIBSPDM_RSA_PSS_3072_SUPPORT
351 0 : return 4;
352 : #else
353 : return 0;
354 : #endif
355 4 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096:
356 : #if LIBSPDM_RSA_SSA_4096_SUPPORT
357 4 : return 4;
358 : #else
359 : return 0;
360 : #endif
361 0 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096:
362 : #if LIBSPDM_RSA_PSS_4096_SUPPORT
363 0 : return 4;
364 : #else
365 : return 0;
366 : #endif
367 1398 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256:
368 : #if LIBSPDM_ECDSA_P256_SUPPORT
369 1398 : return 8;
370 : #else
371 : return 0;
372 : #endif
373 2 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384:
374 : #if LIBSPDM_ECDSA_P384_SUPPORT
375 2 : return 5;
376 : #else
377 : return 0;
378 : #endif
379 2 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521:
380 : #if LIBSPDM_ECDSA_P521_SUPPORT
381 2 : return 5;
382 : #else
383 : return 0;
384 : #endif
385 0 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED25519:
386 : #if LIBSPDM_EDDSA_ED25519_SUPPORT
387 : return 3;
388 : #else
389 0 : return 0;
390 : #endif
391 0 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED448:
392 : #if LIBSPDM_EDDSA_ED448_SUPPORT
393 : return 3;
394 : #else
395 0 : return 0;
396 : #endif
397 0 : default:
398 0 : LIBSPDM_ASSERT(false);
399 0 : return 0;
400 : }
401 : }
402 :
403 : /**
404 : * This function get the SPDM public key encryption algorithm OID.
405 : *
406 : * @param[in] base_asym_algo SPDM base_asym_algo
407 : * @param[in,out] oid SPDM public key encryption algorithm OID
408 : * @param[in,out] oid_other Other SPDM public key encryption algorithm OID
409 : * because of ASN1 code for integer
410 : *
411 : * @retval true get OID successful.
412 : * @retval false get OID fail.
413 : **/
414 764 : static bool libspdm_get_public_key_algo_OID(uint32_t base_asym_algo, uint8_t *oid,
415 : uint8_t *oid_other)
416 : {
417 : uint32_t oid_len;
418 764 : oid_len = libspdm_get_public_key_algo_OID_len(base_asym_algo);
419 764 : if(oid_len == 0) {
420 0 : return false;
421 : }
422 :
423 764 : switch (base_asym_algo) {
424 58 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048:
425 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048: {
426 : #if (LIBSPDM_RSA_SSA_2048_SUPPORT) || (LIBSPDM_RSA_PSS_2048_SUPPORT)
427 58 : uint8_t encry_algo_oid_rsa2048[] = KEY_ENCRY_ALGO_RSA2048_FLAG;
428 58 : uint8_t encry_algo_oid_rsa2048_ohter[] = KEY_ENCRY_ALGO_RSA2048_FLAG_OTHER;
429 58 : libspdm_copy_mem(oid, oid_len, encry_algo_oid_rsa2048, oid_len);
430 58 : libspdm_copy_mem(oid_other, oid_len, encry_algo_oid_rsa2048_ohter, oid_len);
431 58 : return true;
432 : #else
433 : return false;
434 : #endif
435 : }
436 3 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072:
437 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072: {
438 : #if (LIBSPDM_RSA_SSA_3072_SUPPORT) || (LIBSPDM_RSA_PSS_3072_SUPPORT)
439 3 : uint8_t encry_algo_oid_rsa3072[] = KEY_ENCRY_ALGO_RSA3072_FLAG;
440 3 : uint8_t encry_algo_oid_rsa3072_ohter[] = KEY_ENCRY_ALGO_RSA3072_FLAG_OTHER;
441 3 : libspdm_copy_mem(oid, oid_len, encry_algo_oid_rsa3072, oid_len);
442 3 : libspdm_copy_mem(oid_other, oid_len, encry_algo_oid_rsa3072_ohter, oid_len);
443 3 : return true;
444 : #else
445 : return false;
446 : #endif
447 : }
448 2 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096:
449 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096: {
450 : #if (LIBSPDM_RSA_SSA_4096_SUPPORT) || (LIBSPDM_RSA_PSS_4096_SUPPORT)
451 2 : uint8_t encry_algo_oid_rsa4096[] = KEY_ENCRY_ALGO_RSA4096_FLAG;
452 2 : uint8_t encry_algo_oid_rsa4096_ohter[] = KEY_ENCRY_ALGO_RSA4096_FLAG_OTHER;
453 2 : libspdm_copy_mem(oid, oid_len, encry_algo_oid_rsa4096, oid_len);
454 2 : libspdm_copy_mem(oid_other, oid_len, encry_algo_oid_rsa4096_ohter, oid_len);
455 2 : return true;
456 : #else
457 : return false;
458 : #endif
459 : }
460 :
461 699 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256: {
462 : #if LIBSPDM_ECDSA_P256_SUPPORT
463 699 : uint8_t encry_algo_oid_ecc256[] = KEY_ENCRY_ALGO_ECC256_OID;
464 699 : libspdm_copy_mem(oid, oid_len, encry_algo_oid_ecc256, oid_len);
465 699 : return true;
466 : #else
467 : return false;
468 : #endif
469 : }
470 1 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384: {
471 : #if LIBSPDM_ECDSA_P384_SUPPORT
472 1 : uint8_t encry_algo_oid_ecc384[] = KEY_ENCRY_ALGO_ECC384_OID;
473 1 : libspdm_copy_mem(oid, oid_len, encry_algo_oid_ecc384, oid_len);
474 1 : return true;
475 : #else
476 : return false;
477 : #endif
478 : }
479 1 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521: {
480 : #if LIBSPDM_ECDSA_P521_SUPPORT
481 1 : uint8_t encry_algo_oid_ecc521[] = KEY_ENCRY_ALGO_ECC521_OID;
482 1 : libspdm_copy_mem(oid, oid_len, encry_algo_oid_ecc521, oid_len);
483 1 : return true;
484 : #else
485 : return false;
486 : #endif
487 : }
488 :
489 : /*sm2 oid TBD*/
490 0 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_SM2_ECC_SM2_P256:
491 0 : return true;
492 :
493 0 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED25519: {
494 : #if LIBSPDM_EDDSA_ED25519_SUPPORT
495 : uint8_t encry_algo_oid_ed25519[] = ENCRY_ALGO_ED25519_OID;
496 : libspdm_copy_mem(oid, oid_len, encry_algo_oid_ed25519, oid_len);
497 : return true;
498 : #else
499 0 : return false;
500 : #endif
501 : break;
502 : }
503 0 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED448: {
504 : #if LIBSPDM_EDDSA_ED448_SUPPORT
505 : uint8_t encry_algo_oid_ed448[] = ENCRY_ALGO_ED448_OID;
506 : libspdm_copy_mem(oid, oid_len, encry_algo_oid_ed448, oid_len);
507 : return true;
508 : #else
509 0 : return false;
510 : #endif
511 : break;
512 : }
513 :
514 0 : default:
515 0 : LIBSPDM_ASSERT(false);
516 0 : return false;
517 : }
518 : }
519 :
520 : /**
521 : * Verify cert public key encryption algorithm is matched to negotiated base_aysm algo
522 : *
523 : * @param[in] cert Pointer to the DER-encoded certificate data.
524 : * @param[in] cert_size The size of certificate data in bytes.
525 : * @param[in] base_asym_algo SPDM base_asym_algo
526 : * @param[out] oid cert public key encryption algorithm OID
527 : * @param[in] oid_size the buffer size for required OID
528 : *
529 : * @retval true get public key oid from cert successfully
530 : * @retval false get public key oid from cert fail
531 : **/
532 764 : static bool libspdm_get_public_key_oid(const uint8_t *cert, size_t cert_size,
533 : uint8_t *oid, size_t oid_size, uint32_t base_asym_algo)
534 : {
535 : bool ret;
536 : uint8_t *ptr;
537 : int32_t length;
538 : size_t obj_len;
539 : uint8_t *end;
540 : uint8_t index;
541 : uint8_t sequence_time;
542 :
543 764 : length = (int32_t)cert_size;
544 764 : ptr = (uint8_t*)(size_t)cert;
545 764 : obj_len = 0;
546 764 : end = ptr + length;
547 764 : ret = true;
548 :
549 : /* TBSCertificate have 5 sequence before subjectPublicKeyInfo*/
550 764 : sequence_time = 5;
551 :
552 : /*all cert sequence*/
553 764 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
554 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
555 764 : if (!ret) {
556 0 : return false;
557 : }
558 :
559 : /*TBSCertificate sequence*/
560 764 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
561 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
562 764 : if (!ret) {
563 0 : return false;
564 : }
565 :
566 764 : end = ptr + obj_len;
567 : /*version*/
568 764 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
569 : LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC |
570 : LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
571 764 : if (!ret) {
572 0 : return false;
573 : }
574 :
575 764 : ptr += obj_len;
576 : /*serialNumber*/
577 764 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len, LIBSPDM_CRYPTO_ASN1_INTEGER);
578 764 : if (!ret) {
579 0 : return false;
580 : }
581 :
582 : /**
583 : * signature AlgorithmIdentifier,
584 : * issuer Name,
585 : * validity Validity,
586 : * subject Name,
587 : * subjectPublicKeyInfo
588 : **/
589 4584 : for (index = 0; index < sequence_time; index++) {
590 3820 : ptr += obj_len;
591 3820 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
592 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
593 3820 : if (!ret) {
594 0 : return false;
595 : }
596 : }
597 :
598 764 : switch (base_asym_algo)
599 : {
600 63 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048:
601 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048:
602 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072:
603 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072:
604 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096:
605 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096:
606 63 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
607 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
608 63 : if (!ret) {
609 0 : return false;
610 : }
611 :
612 63 : ptr += obj_len;
613 63 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len, LIBSPDM_CRYPTO_ASN1_BIT_STRING);
614 63 : if (!ret) {
615 0 : return false;
616 : }
617 :
618 : /*get rsa key len*/
619 63 : ptr++;
620 63 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
621 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
622 63 : if (!ret) {
623 1 : return false;
624 : }
625 62 : libspdm_copy_mem(oid, oid_size, ptr, oid_size);
626 62 : break;
627 701 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256:
628 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384:
629 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521:
630 701 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
631 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
632 701 : if (!ret) {
633 0 : return false;
634 : }
635 701 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len, LIBSPDM_CRYPTO_ASN1_OID);
636 701 : if (!ret) {
637 0 : return false;
638 : }
639 :
640 : /*get ecc second oid*/
641 701 : ptr +=obj_len;
642 701 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len, LIBSPDM_CRYPTO_ASN1_OID);
643 701 : if (!ret) {
644 0 : return false;
645 : }
646 :
647 701 : if (oid_size != obj_len) {
648 0 : return false;
649 : }
650 :
651 701 : libspdm_copy_mem(oid, oid_size, ptr, obj_len);
652 701 : break;
653 0 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED25519:
654 : case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED448:
655 0 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
656 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
657 0 : if (!ret) {
658 0 : return false;
659 : }
660 :
661 : /*get eddsa oid*/
662 0 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len, LIBSPDM_CRYPTO_ASN1_OID);
663 0 : if (!ret) {
664 0 : return false;
665 : }
666 :
667 0 : if (oid_size != obj_len) {
668 0 : return false;
669 : }
670 :
671 0 : libspdm_copy_mem(oid, oid_size, ptr, obj_len);
672 0 : break;
673 0 : default:
674 0 : LIBSPDM_ASSERT(false);
675 0 : return false;
676 : }
677 :
678 763 : return true;
679 : }
680 :
681 : /**
682 : * Verify cert public key encryption algorithm is matched to negotiated base_aysm algo
683 : *
684 : * @param[in] cert Pointer to the DER-encoded certificate data.
685 : * @param[in] cert_size The size of certificate data in bytes.
686 : * @param[in] base_asym_algo SPDM base_asym_algo
687 : *
688 : * @retval true verify pass
689 : * @retval false verify fail
690 : **/
691 764 : static bool libspdm_verify_cert_subject_public_key_info(const uint8_t *cert, size_t cert_size,
692 : uint32_t base_asym_algo)
693 : {
694 : size_t oid_len;
695 : bool status;
696 :
697 : /*public key encrypt algo OID from cert*/
698 : uint8_t cert_public_key_crypt_algo_oid[LIBSPDM_MAX_ENCRYPTION_ALGO_OID_LEN];
699 : /*public key encrypt algo OID from libspdm stored*/
700 : uint8_t libspdm_public_key_crypt_algo_oid[LIBSPDM_MAX_ENCRYPTION_ALGO_OID_LEN];
701 : uint8_t libspdm_public_key_crypt_algo_oid_other[LIBSPDM_MAX_ENCRYPTION_ALGO_OID_LEN];
702 :
703 764 : libspdm_zero_mem(libspdm_public_key_crypt_algo_oid, LIBSPDM_MAX_ENCRYPTION_ALGO_OID_LEN);
704 764 : libspdm_zero_mem(libspdm_public_key_crypt_algo_oid_other, LIBSPDM_MAX_ENCRYPTION_ALGO_OID_LEN);
705 :
706 : /*work around: skip the sm2*/
707 764 : if (base_asym_algo == SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_SM2_ECC_SM2_P256) {
708 0 : return true;
709 : }
710 :
711 764 : oid_len = libspdm_get_public_key_algo_OID_len(base_asym_algo);
712 764 : if(oid_len == 0) {
713 0 : return false;
714 : }
715 : /*get public key encrypt algo OID from libspdm stored*/
716 764 : status = libspdm_get_public_key_algo_OID(base_asym_algo,
717 : libspdm_public_key_crypt_algo_oid,
718 : libspdm_public_key_crypt_algo_oid_other);
719 764 : if (!status) {
720 0 : return status;
721 : }
722 :
723 : /*get public key encrypt algo OID from cert*/
724 764 : status = libspdm_get_public_key_oid(cert, cert_size, cert_public_key_crypt_algo_oid, oid_len,
725 : base_asym_algo);
726 764 : if (!status || (!libspdm_consttime_is_mem_equal(cert_public_key_crypt_algo_oid,
727 1 : libspdm_public_key_crypt_algo_oid, oid_len) &&
728 1 : !libspdm_consttime_is_mem_equal(cert_public_key_crypt_algo_oid,
729 : libspdm_public_key_crypt_algo_oid_other,
730 : oid_len))) {
731 2 : return false;
732 : }
733 :
734 762 : return status;
735 : }
736 :
737 : /**
738 : * Verify leaf cert basic_constraints CA is false
739 : *
740 : * @param[in] cert Pointer to the DER-encoded certificate data.
741 : * @param[in] cert_size The size of certificate data in bytes.
742 : * @param[in] need_basic_constraints This value indicates whether basic_constraints must be present in the Cert
743 : *
744 : * @retval true verify pass,two case: 1.basic constraints is not present in cert, when need_basic_constraints is false;
745 : * 2. cert basic_constraints CA is false;
746 : * @retval false verify fail
747 : **/
748 748 : static bool libspdm_verify_leaf_cert_basic_constraints(const uint8_t *cert, size_t cert_size,
749 : bool need_basic_constraints)
750 : {
751 : bool status;
752 : /*basic_constraints from cert*/
753 : uint8_t cert_basic_constraints[LIBSPDM_MAX_BASIC_CONSTRAINTS_CA_LEN];
754 : size_t len;
755 :
756 748 : uint8_t basic_constraints_false_case1[] = BASIC_CONSTRAINTS_STRING_FALSE_CASE1;
757 748 : uint8_t basic_constraints_false_case2[] = BASIC_CONSTRAINTS_STRING_FALSE_CASE2;
758 :
759 748 : len = LIBSPDM_MAX_BASIC_CONSTRAINTS_CA_LEN;
760 :
761 748 : status = libspdm_x509_get_extended_basic_constraints(cert, cert_size,
762 : cert_basic_constraints, &len);
763 748 : if (!status) {
764 0 : return false;
765 748 : } else if (len == 0) {
766 : /* basic constraints is not present in cert */
767 2 : if (need_basic_constraints) {
768 1 : return false;
769 : } else {
770 1 : return true;
771 : }
772 : }
773 :
774 1490 : if ((len == sizeof(basic_constraints_false_case1)) &&
775 744 : (libspdm_consttime_is_mem_equal(cert_basic_constraints,
776 : basic_constraints_false_case1,
777 : sizeof(basic_constraints_false_case1)))) {
778 744 : return true;
779 : }
780 :
781 4 : if ((len == sizeof(basic_constraints_false_case2)) &&
782 2 : (libspdm_consttime_is_mem_equal(cert_basic_constraints,
783 : basic_constraints_false_case2,
784 : sizeof(basic_constraints_false_case2)))) {
785 0 : return true;
786 : }
787 :
788 2 : return false;
789 : }
790 :
791 : /**
792 : * Verify leaf certificate basic_constraints CA is correct for set certificate.
793 : *
794 : * For SPDM 1.2
795 : * - If certificate model is DeviceCert and CA is present then CA must be false.
796 : * - If certificate model is AliasCert and CA is present then CA must be true.
797 : *
798 : * For SPDM 1.3 and up, CA must be present and
799 : * - If certificate model is DeviceCert or GenericCert then CA must be false.
800 : * - If certificate model is AliasCert then CA must be true.
801 : *
802 : * @param[in] cert Pointer to the DER-encoded certificate data.
803 : * @param[in] cert_size The size of certificate data in bytes.
804 : * @param[in] cert_model The certificate model.
805 : * @param[in] need_basic_constraints This value indicates whether basic_constraints must be present
806 : * in the certificate.
807 : *
808 : * @retval true verify pass 1. basic_constraints is not present when allowed.
809 : * 2. basic_constraints is present and correct.
810 : * @retval false verify fail
811 : **/
812 14 : static bool libspdm_verify_set_cert_leaf_cert_basic_constraints(
813 : const uint8_t *cert, size_t cert_size, uint8_t cert_model, bool need_basic_constraints)
814 : {
815 : bool status;
816 : /* basic_constraints from certificate. */
817 : uint8_t cert_basic_constraints[LIBSPDM_MAX_BASIC_CONSTRAINTS_CA_LEN];
818 : size_t len;
819 :
820 14 : const uint8_t basic_constraints_false_case1[] = BASIC_CONSTRAINTS_STRING_FALSE_CASE1;
821 14 : const uint8_t basic_constraints_false_case2[] = BASIC_CONSTRAINTS_STRING_FALSE_CASE2;
822 14 : const uint8_t basic_constraints_true_case[] = BASIC_CONSTRAINTS_STRING_TRUE_CASE;
823 :
824 14 : len = LIBSPDM_MAX_BASIC_CONSTRAINTS_CA_LEN;
825 :
826 14 : status = libspdm_x509_get_extended_basic_constraints(cert, cert_size,
827 : cert_basic_constraints, &len);
828 14 : if (!status) {
829 0 : return false;
830 14 : } else if (need_basic_constraints && (len == 0)) {
831 0 : return false;
832 : }
833 :
834 14 : if ((cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT) ||
835 : (cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT)) {
836 8 : if (need_basic_constraints || (len != 0)) {
837 16 : if ((len == sizeof(basic_constraints_false_case1)) &&
838 8 : (libspdm_consttime_is_mem_equal(cert_basic_constraints,
839 : basic_constraints_false_case1,
840 : sizeof(basic_constraints_false_case1)))) {
841 8 : return true;
842 : }
843 :
844 0 : if ((len == sizeof(basic_constraints_false_case2)) &&
845 0 : (libspdm_consttime_is_mem_equal(cert_basic_constraints,
846 : basic_constraints_false_case2,
847 : sizeof(basic_constraints_false_case2)))) {
848 0 : return true;
849 : }
850 : }
851 : } else {
852 : /* Alias certificate model. */
853 6 : if (need_basic_constraints || (len != 0)) {
854 : /* basicConstraints may include the pathLen field. Therefore do not check sequence
855 : * length. */
856 6 : if (len >= sizeof(basic_constraints_true_case)) {
857 4 : if (cert_basic_constraints[0] != basic_constraints_true_case[0]) {
858 0 : return false;
859 : }
860 4 : if (libspdm_consttime_is_mem_equal(&cert_basic_constraints[2],
861 : &basic_constraints_true_case[2],
862 : sizeof(basic_constraints_true_case) - 2)) {
863 4 : return true;
864 : }
865 : }
866 : }
867 : }
868 2 : return false;
869 : }
870 :
871 : /**
872 : * Verify leaf cert spdm defined extended key usage
873 : *
874 : * @param[in] cert Pointer to the DER-encoded certificate data.
875 : * @param[in] cert_size The size of certificate data in bytes.
876 : * @param[in] is_requester_cert Is the function verifying requester or responder cert.
877 : *
878 : * @retval true verify pass, two cases:
879 : * 1. spdm defined eku is not present in cert;
880 : * 2. spdm defined eku is compliant with requester/responder identity;
881 : * @retval false verify fail, two cases:
882 : * 1. requester's cert has only responder auth oid in eku;
883 : * 2. responder's cert has only requester auth oid in eku;
884 : **/
885 768 : static bool libspdm_verify_leaf_cert_spdm_eku(const uint8_t *cert, size_t cert_size,
886 : bool is_requester_cert)
887 : {
888 : bool status;
889 : uint8_t eku[256];
890 : size_t eku_size;
891 : bool req_auth_oid_find_success;
892 : bool rsp_auth_oid_find_success;
893 : uint8_t *ptr;
894 : size_t obj_len;
895 :
896 : /* SPDM defined OID */
897 768 : uint8_t eku_requester_auth_oid[] = SPDM_OID_DMTF_EKU_REQUESTER_AUTH;
898 768 : uint8_t eku_responder_auth_oid[] = SPDM_OID_DMTF_EKU_RESPONDER_AUTH;
899 :
900 768 : eku_size = sizeof(eku);
901 768 : status = libspdm_x509_get_extended_key_usage(cert, cert_size, eku, &eku_size);
902 768 : if (!status) {
903 0 : return false;
904 768 : } else if (eku_size == 0) {
905 : /* eku is not present in cert */
906 0 : return true;
907 : }
908 :
909 768 : ptr = eku;
910 768 : obj_len = 0;
911 768 : req_auth_oid_find_success = false;
912 768 : rsp_auth_oid_find_success = false;
913 :
914 768 : status = libspdm_asn1_get_tag(&ptr, eku + eku_size, &obj_len,
915 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
916 768 : if (!status) {
917 0 : return false;
918 : }
919 :
920 3075 : while(ptr < eku + eku_size) {
921 2307 : status = libspdm_asn1_get_tag(&ptr, eku + eku_size, &obj_len, LIBSPDM_CRYPTO_ASN1_OID);
922 2307 : if (!status) {
923 0 : return false;
924 : }
925 :
926 2315 : if ((obj_len == sizeof(eku_requester_auth_oid)) &&
927 8 : (libspdm_consttime_is_mem_equal(ptr, eku_requester_auth_oid,
928 : sizeof(eku_requester_auth_oid)))) {
929 4 : req_auth_oid_find_success = true;
930 : }
931 2315 : if ((obj_len == sizeof(eku_responder_auth_oid)) &&
932 8 : (libspdm_consttime_is_mem_equal(ptr, eku_responder_auth_oid,
933 : sizeof(eku_responder_auth_oid)))) {
934 4 : rsp_auth_oid_find_success = true;
935 : }
936 :
937 2307 : ptr += obj_len;
938 : }
939 :
940 768 : if (ptr != eku + eku_size) {
941 0 : return false;
942 : }
943 :
944 768 : if (is_requester_cert) {
945 : /* it should not only contain responder auth oid */
946 20 : if (!req_auth_oid_find_success && rsp_auth_oid_find_success) {
947 1 : return false;
948 : }
949 : } else {
950 : /* it should not only contain requester auth oid */
951 748 : if (req_auth_oid_find_success && !rsp_auth_oid_find_success) {
952 1 : return false;
953 : }
954 : }
955 :
956 766 : return true;
957 : }
958 :
959 : /**
960 : * Verify leaf cert spdm defined extension
961 : *
962 : * @param[in] cert Pointer to the DER-encoded certificate data.
963 : * @param[in] cert_size The size of certificate data in bytes.
964 : * @param[in] is_requester_cert Is the function verifying requester or responder cert.
965 : *
966 : * @retval true verify pass
967 : * @retval false verify fail,two case: 1. return is not RETURN_SUCCESS or RETURN_NOT_FOUND;
968 : * 2. hardware_identity_oid is found in AliasCert model;
969 : **/
970 760 : static bool libspdm_verify_leaf_cert_spdm_extension(const uint8_t *cert, size_t cert_size,
971 : bool is_requester_cert,
972 : uint8_t cert_model)
973 : {
974 : bool status;
975 : bool find_sucessful;
976 : uint8_t spdm_extension[LIBSPDM_MAX_EXTENSION_LEN];
977 : size_t len;
978 : uint8_t *ptr;
979 : uint8_t *temptr;
980 : size_t obj_len;
981 :
982 : /* SPDM defined OID */
983 760 : uint8_t oid_spdm_extension[] = SPDM_OID_DMTF_SPDM_EXTENSION;
984 760 : uint8_t hardware_identity_oid[] = SPDM_OID_DMTF_HARDWARE_IDENTITY;
985 :
986 760 : len = LIBSPDM_MAX_EXTENSION_LEN;
987 :
988 760 : if (cert == NULL || cert_size == 0) {
989 0 : return false;
990 : }
991 :
992 760 : status = libspdm_x509_get_extension_data(cert, cert_size,
993 : (const uint8_t *)oid_spdm_extension,
994 : sizeof(oid_spdm_extension),
995 : spdm_extension,
996 : &len);
997 760 : if (!status) {
998 0 : return false;
999 760 : } else if(len == 0) {
1000 13 : return true;
1001 : }
1002 :
1003 : /*find the spdm hardware identity OID*/
1004 747 : find_sucessful = false;
1005 747 : ptr = spdm_extension;
1006 747 : obj_len = 0;
1007 :
1008 : /*id-spdm-cert-oids ::= SEQUENCE SIZE (1..MAX) OF id-spdm-cert-oid*/
1009 747 : status = libspdm_asn1_get_tag(
1010 : &ptr, spdm_extension + len, &obj_len,
1011 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1012 747 : if (!status) {
1013 0 : return false;
1014 : }
1015 :
1016 1494 : while(ptr < spdm_extension + len) {
1017 747 : status = libspdm_asn1_get_tag(
1018 : &ptr, spdm_extension + len, &obj_len,
1019 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1020 747 : if (!status) {
1021 0 : return false;
1022 : }
1023 :
1024 747 : temptr = ptr + obj_len;
1025 747 : status = libspdm_asn1_get_tag(
1026 : &ptr, spdm_extension + len, &obj_len, LIBSPDM_CRYPTO_ASN1_OID);
1027 747 : if (!status) {
1028 0 : return false;
1029 : }
1030 1494 : if ((obj_len == sizeof(hardware_identity_oid)) &&
1031 747 : (libspdm_consttime_is_mem_equal(ptr, hardware_identity_oid,
1032 : sizeof(hardware_identity_oid)))) {
1033 747 : find_sucessful = true;
1034 : }
1035 747 : ptr = temptr;
1036 : }
1037 :
1038 747 : if (ptr != spdm_extension + len) {
1039 0 : return false;
1040 : }
1041 :
1042 : /* Responder does not determine Requester's certificate model */
1043 747 : if (!is_requester_cert) {
1044 732 : if ((find_sucessful) && (cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_ALIAS_CERT)) {
1045 : /* Hardware_identity_OID is found in alias cert model */
1046 4 : return false;
1047 : }
1048 : }
1049 :
1050 743 : return true;
1051 : }
1052 :
1053 : /**
1054 : * Certificate common Check for SPDM leaf cert when get_cert and set_cert.
1055 : *
1056 : * @param[in] cert Pointer to the DER-encoded certificate data.
1057 : * @param[in] cert_size The size of certificate data in bytes.
1058 : * @param[in] base_asym_algo SPDM base_asym_algo
1059 : * @param[in] base_hash_algo SPDM base_hash_algo
1060 : * @param[in] is_requester_cert Is the function verifying requester or responder cert.
1061 : * @param[in] cert_model One of the SPDM_CERTIFICATE_INFO_CERT_MODEL_* macros.
1062 : * @param[in] set_cert Is the function verifying a set certificate operation.
1063 : *
1064 : * @retval true Success.
1065 : * @retval false Certificate is not valid.
1066 : **/
1067 770 : bool libspdm_x509_common_certificate_check(const uint8_t *cert, size_t cert_size,
1068 : uint32_t base_asym_algo, uint32_t base_hash_algo,
1069 : bool is_requester_cert, uint8_t cert_model,
1070 : bool set_cert)
1071 : {
1072 : uint8_t end_cert_from[64];
1073 : size_t end_cert_from_len;
1074 : uint8_t end_cert_to[64];
1075 : size_t end_cert_to_len;
1076 : size_t asn1_buffer_len;
1077 : bool status;
1078 : size_t cert_version;
1079 : void *context;
1080 : #if LIBSPDM_ADDITIONAL_CHECK_CERT
1081 : size_t signature_algo_oid_size;
1082 : #endif /* LIBSPDM_ADDITIONAL_CHECK_CERT */
1083 :
1084 770 : if (cert == NULL || cert_size == 0) {
1085 0 : return false;
1086 : }
1087 :
1088 770 : status = true;
1089 770 : context = NULL;
1090 770 : end_cert_from_len = 64;
1091 770 : end_cert_to_len = 64;
1092 :
1093 : /* 1. version*/
1094 770 : cert_version = 0;
1095 770 : status = libspdm_x509_get_version(cert, cert_size, &cert_version);
1096 770 : if (!status) {
1097 0 : goto cleanup;
1098 : }
1099 770 : if (cert_version != 2) {
1100 0 : status = false;
1101 0 : goto cleanup;
1102 : }
1103 :
1104 : /* 2. serial_number*/
1105 770 : asn1_buffer_len = 0;
1106 770 : status = libspdm_x509_get_serial_number(cert, cert_size, NULL, &asn1_buffer_len);
1107 770 : if (asn1_buffer_len == 0) {
1108 0 : status = false;
1109 0 : goto cleanup;
1110 : }
1111 :
1112 : #if LIBSPDM_ADDITIONAL_CHECK_CERT
1113 : /* 3. Verify signature algorithm. */
1114 : signature_algo_oid_size = 0;
1115 : status = libspdm_x509_get_signature_algorithm(cert, cert_size, NULL, &signature_algo_oid_size);
1116 : if (status) {
1117 : if ((signature_algo_oid_size == 0) &&
1118 : (cert_model != SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT)) {
1119 : status = false;
1120 : goto cleanup;
1121 : }
1122 : } else {
1123 : if (signature_algo_oid_size == 0) {
1124 : status = false;
1125 : goto cleanup;
1126 : }
1127 : }
1128 : #endif /* LIBSPDM_ADDITIONAL_CHECK_CERT */
1129 :
1130 : /* 4. Verify public key algorithm.
1131 : * If this is a SET_CERTIFICATE operation and the endpoint uses the AliasCert model then the
1132 : * check should be skipped as the Device Certificate CA's public key does not have to use
1133 : * the same algorithms as the connection's negotiated algorithms. */
1134 770 : if (!set_cert || (cert_model != SPDM_CERTIFICATE_INFO_CERT_MODEL_ALIAS_CERT)) {
1135 764 : status = libspdm_verify_cert_subject_public_key_info(cert, cert_size, base_asym_algo);
1136 764 : if (!status) {
1137 2 : goto cleanup;
1138 : }
1139 : }
1140 :
1141 : /* 5. issuer_name*/
1142 768 : asn1_buffer_len = 0;
1143 768 : status = libspdm_x509_get_issuer_name(cert, cert_size, NULL, &asn1_buffer_len);
1144 768 : if (status) {
1145 0 : if ((asn1_buffer_len == 0) &&
1146 : (cert_model != SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT)) {
1147 0 : status = false;
1148 0 : goto cleanup;
1149 : }
1150 : } else {
1151 768 : if (asn1_buffer_len == 0) {
1152 0 : status = false;
1153 0 : goto cleanup;
1154 : }
1155 : }
1156 :
1157 : /* 6. subject_name*/
1158 768 : asn1_buffer_len = 0;
1159 768 : status = libspdm_x509_get_subject_name(cert, cert_size, NULL, &asn1_buffer_len);
1160 768 : if (status) {
1161 0 : if ((asn1_buffer_len == 0) &&
1162 : (cert_model != SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT)) {
1163 0 : status = false;
1164 0 : goto cleanup;
1165 : }
1166 : } else {
1167 768 : if (asn1_buffer_len == 0) {
1168 0 : status = false;
1169 0 : goto cleanup;
1170 : }
1171 : }
1172 :
1173 : /* 7. validity*/
1174 768 : status = libspdm_x509_get_validity(cert, cert_size, end_cert_from,
1175 : &end_cert_from_len, end_cert_to,
1176 : &end_cert_to_len);
1177 768 : if (status) {
1178 768 : if ((end_cert_from_len == 0) &&
1179 : (cert_model != SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT)) {
1180 0 : status = false;
1181 0 : goto cleanup;
1182 : }
1183 : } else {
1184 0 : if (end_cert_from_len == 0) {
1185 0 : status = false;
1186 0 : goto cleanup;
1187 : }
1188 : }
1189 :
1190 768 : if (end_cert_from_len != 0) {
1191 768 : status = libspdm_internal_x509_date_time_check(
1192 : end_cert_from, end_cert_from_len, end_cert_to, end_cert_to_len);
1193 768 : if (!status) {
1194 0 : goto cleanup;
1195 : }
1196 : }
1197 :
1198 : /* 8. subject_public_key*/
1199 768 : status = libspdm_asym_get_public_key_from_x509(base_asym_algo, cert, cert_size, &context);
1200 768 : if (!status) {
1201 0 : goto cleanup;
1202 : }
1203 :
1204 : /* 9. key_usage
1205 : * If this is a SET_CERTIFICATE operation and the endpoint uses the AliasCert model then the
1206 : * check should be skipped as the SPDM specification does not specify the presence or absence
1207 : * of the Device Certificate CA's keyUsage field. */
1208 768 : if (!set_cert || (cert_model != SPDM_CERTIFICATE_INFO_CERT_MODEL_ALIAS_CERT)) {
1209 762 : size_t value = 0;
1210 :
1211 762 : status = libspdm_x509_get_key_usage(cert, cert_size, &value);
1212 762 : if (!status) {
1213 0 : goto cleanup;
1214 : } else {
1215 762 : if (value == 0) {
1216 0 : if (cert_model != SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT) {
1217 0 : status = false;
1218 0 : goto cleanup;
1219 : }
1220 : } else {
1221 762 : if ((LIBSPDM_CRYPTO_X509_KU_DIGITAL_SIGNATURE & value) == 0) {
1222 0 : status = false;
1223 0 : goto cleanup;
1224 : }
1225 : }
1226 : }
1227 : }
1228 :
1229 : /* 10. verify spdm defined extended key usage*/
1230 768 : status = libspdm_verify_leaf_cert_spdm_eku(cert, cert_size, is_requester_cert);
1231 768 : if (!status) {
1232 2 : goto cleanup;
1233 : }
1234 :
1235 766 : if ((!set_cert) || (cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT)) {
1236 : /* 11. verify spdm defined extension*/
1237 760 : status = libspdm_verify_leaf_cert_spdm_extension(cert, cert_size,
1238 : is_requester_cert, cert_model);
1239 760 : if (!status) {
1240 4 : goto cleanup;
1241 : }
1242 : }
1243 :
1244 762 : cleanup:
1245 770 : libspdm_asym_free(base_asym_algo, context);
1246 770 : return status;
1247 : }
1248 :
1249 : /**
1250 : * Certificate Check for SPDM leaf cert when get_cert command
1251 : *
1252 : * @param[in] cert Pointer to the DER-encoded certificate data.
1253 : * @param[in] cert_size The size of certificate data in bytes.
1254 : * @param[in] base_asym_algo SPDM base_asym_algo
1255 : * @param[in] base_hash_algo SPDM base_hash_algo
1256 : * @param[in] is_requester Is the function verifying a cert as a requester or responder.
1257 : * @param[in] is_device_cert_model If true, the local endpoint uses the DeviceCert model.
1258 : * If false, the local endpoint uses the AliasCert model.
1259 : *
1260 : * @retval true Success.
1261 : * @retval false Certificate is not valid
1262 : **/
1263 743 : bool libspdm_x509_certificate_check(const uint8_t *cert, size_t cert_size,
1264 : uint32_t base_asym_algo,
1265 : uint32_t base_hash_algo,
1266 : bool is_requester,
1267 : bool is_device_cert_model)
1268 : {
1269 : bool status;
1270 : uint8_t cert_model;
1271 :
1272 743 : if (is_device_cert_model) {
1273 737 : cert_model = SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT;
1274 : } else {
1275 6 : cert_model = SPDM_CERTIFICATE_INFO_CERT_MODEL_ALIAS_CERT;
1276 : }
1277 :
1278 743 : status = libspdm_x509_common_certificate_check(cert, cert_size, base_asym_algo,
1279 : base_hash_algo, is_requester,
1280 : cert_model, false);
1281 743 : if (!status) {
1282 5 : return false;
1283 : }
1284 :
1285 : /* verify basic constraints: the leaf cert always is ca:false in get_cert*/
1286 738 : status = libspdm_verify_leaf_cert_basic_constraints(cert, cert_size, false);
1287 738 : return status;
1288 : }
1289 :
1290 :
1291 : /**
1292 : * Certificate Check for SPDM leaf cert when get_cert command. It is used for SPDM 1.3.
1293 : *
1294 : * @param[in] cert Pointer to the DER-encoded certificate data.
1295 : * @param[in] cert_size The size of certificate data in bytes.
1296 : * @param[in] base_asym_algo SPDM base_asym_algo
1297 : * @param[in] base_hash_algo SPDM base_hash_algo
1298 : * @param[in] is_requester Is the function verifying a cert as a requester or responder.
1299 : * @param[in] cert_model One of the SPDM_CERTIFICATE_INFO_CERT_MODEL_* macros.
1300 : *
1301 : * @retval true Success.
1302 : * @retval false Certificate is not valid
1303 : **/
1304 13 : bool libspdm_x509_certificate_check_ex(const uint8_t *cert, size_t cert_size,
1305 : uint32_t base_asym_algo,
1306 : uint32_t base_hash_algo,
1307 : bool is_requester,
1308 : uint8_t cert_model)
1309 : {
1310 : bool status;
1311 :
1312 13 : status = libspdm_x509_common_certificate_check(cert, cert_size, base_asym_algo,
1313 : base_hash_algo, is_requester,
1314 : cert_model, false);
1315 13 : if (!status) {
1316 3 : return false;
1317 : }
1318 :
1319 : /* verify basic constraints: the leaf cert always is ca:false in get_cert
1320 : * basic_constraints is mandatory in SPDM 1.3*/
1321 10 : status = libspdm_verify_leaf_cert_basic_constraints(cert, cert_size, true);
1322 10 : return status;
1323 : }
1324 :
1325 8 : bool libspdm_x509_set_cert_certificate_check(const uint8_t *cert, size_t cert_size,
1326 : uint32_t base_asym_algo, uint32_t base_hash_algo,
1327 : bool is_requester, bool is_device_cert_model)
1328 : {
1329 : bool status;
1330 : uint8_t cert_model;
1331 :
1332 8 : if (is_device_cert_model) {
1333 5 : cert_model = SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT;
1334 : } else {
1335 3 : cert_model = SPDM_CERTIFICATE_INFO_CERT_MODEL_ALIAS_CERT;
1336 : }
1337 :
1338 8 : status = libspdm_x509_common_certificate_check(cert, cert_size, base_asym_algo,
1339 : base_hash_algo, is_requester,
1340 : cert_model, true);
1341 8 : if (!status) {
1342 0 : return false;
1343 : }
1344 :
1345 : /* verify basic constraints: need check with is_device_cert_model*/
1346 8 : status = libspdm_verify_set_cert_leaf_cert_basic_constraints(
1347 : cert, cert_size, cert_model, false);
1348 8 : return status;
1349 : }
1350 :
1351 6 : bool libspdm_x509_set_cert_certificate_check_ex(const uint8_t *cert, size_t cert_size,
1352 : uint32_t base_asym_algo, uint32_t base_hash_algo,
1353 : bool is_requester, uint8_t cert_model)
1354 : {
1355 : bool status;
1356 :
1357 6 : status = libspdm_x509_common_certificate_check(cert, cert_size, base_asym_algo,
1358 : base_hash_algo, is_requester,
1359 : cert_model, true);
1360 6 : if (!status) {
1361 0 : return false;
1362 : }
1363 :
1364 : /* verify basic constraints: need check with is_device_cert_model*/
1365 6 : status = libspdm_verify_set_cert_leaf_cert_basic_constraints(
1366 : cert, cert_size, cert_model, true);
1367 :
1368 6 : return status;
1369 : }
1370 :
1371 : /**
1372 : * Return certificate is root cert or not.
1373 : * Certificate is considered as a root certificate if the subjectname equal issuername.
1374 : *
1375 : * @param[in] cert Pointer to the DER-encoded certificate data.
1376 : * @param[in] cert_size The size of certificate data in bytes.
1377 : *
1378 : * @retval true Certificate is self-signed.
1379 : * @retval false Certificate is not self-signed.
1380 : **/
1381 59 : bool libspdm_is_root_certificate(const uint8_t *cert, size_t cert_size)
1382 : {
1383 : uint8_t issuer_name[LIBSPDM_MAX_NAME_SIZE];
1384 : size_t issuer_name_len;
1385 : uint8_t subject_name[LIBSPDM_MAX_NAME_SIZE];
1386 : size_t subject_name_len;
1387 : bool result;
1388 :
1389 59 : if (cert == NULL || cert_size == 0) {
1390 0 : return false;
1391 : }
1392 :
1393 : /* 1. issuer_name*/
1394 59 : issuer_name_len = sizeof(issuer_name);
1395 59 : result = libspdm_x509_get_issuer_name(cert, cert_size, issuer_name, &issuer_name_len);
1396 59 : if (!result) {
1397 0 : return false;
1398 : }
1399 :
1400 : /* 2. subject_name*/
1401 59 : subject_name_len = sizeof(subject_name);
1402 59 : result = libspdm_x509_get_subject_name(cert, cert_size, subject_name, &subject_name_len);
1403 59 : if (!result) {
1404 0 : return false;
1405 : }
1406 :
1407 59 : if (issuer_name_len != subject_name_len) {
1408 3 : return false;
1409 : }
1410 56 : if (!libspdm_consttime_is_mem_equal(issuer_name, subject_name, issuer_name_len)) {
1411 0 : return false;
1412 : }
1413 :
1414 56 : return true;
1415 : }
1416 :
1417 : /**
1418 : * Retrieve the SubjectAltName from SubjectAltName Bytes.
1419 : *
1420 : * @param[in] buffer Pointer to subjectAltName oct bytes.
1421 : * @param[in] len size of buffer in bytes.
1422 : * @param[out] name_buffer buffer to contain the retrieved certificate
1423 : * SubjectAltName. At most name_buffer_size bytes will be
1424 : * written. Maybe NULL in order to determine the size
1425 : * buffer needed.
1426 : * @param[in,out] name_buffer_size The size in bytes of the name buffer on input,
1427 : * and the size of buffer returned name on output.
1428 : * If name_buffer is NULL then the amount of space needed
1429 : * in buffer (including the final null) is returned.
1430 : * @param[out] oid OID of otherName
1431 : * @param[in,out] oid_size the buffersize for required OID
1432 : *
1433 : * @retval true get the subjectAltName string successfully
1434 : * @retval failed get the subjectAltName string failed
1435 : **/
1436 9 : bool libspdm_get_dmtf_subject_alt_name_from_bytes(
1437 : uint8_t *buffer, const size_t len, char *name_buffer,
1438 : size_t *name_buffer_size, uint8_t *oid,
1439 : size_t *oid_size)
1440 : {
1441 : uint8_t *ptr;
1442 : int32_t length;
1443 : size_t obj_len;
1444 : int32_t ret;
1445 :
1446 : /*copy mem variable*/
1447 : volatile uint8_t* dst;
1448 : const volatile uint8_t* src;
1449 : size_t dst_len;
1450 : size_t src_len;
1451 :
1452 9 : length = (int32_t)len;
1453 9 : ptr = buffer;
1454 9 : obj_len = 0;
1455 :
1456 : /* Sequence*/
1457 9 : ret = libspdm_asn1_get_tag(&ptr, ptr + length, &obj_len,
1458 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1459 9 : if (!ret) {
1460 0 : return false;
1461 : }
1462 :
1463 9 : ret = libspdm_asn1_get_tag(&ptr, ptr + obj_len, &obj_len,
1464 : LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC |
1465 : LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1466 :
1467 9 : ret = libspdm_asn1_get_tag(&ptr, ptr + obj_len, &obj_len, LIBSPDM_CRYPTO_ASN1_OID);
1468 9 : if (!ret) {
1469 0 : return false;
1470 : }
1471 : /* CopyData to OID*/
1472 9 : if (*oid_size < (size_t)obj_len) {
1473 0 : *oid_size = (size_t)obj_len;
1474 0 : return false;
1475 : }
1476 9 : if (oid != NULL) {
1477 9 : libspdm_copy_mem(oid, *oid_size, ptr, obj_len);
1478 9 : *oid_size = obj_len;
1479 : }
1480 :
1481 : /* Move to next element*/
1482 9 : ptr += obj_len;
1483 :
1484 9 : ret = libspdm_asn1_get_tag(&ptr, (uint8_t *)(buffer + length), &obj_len,
1485 : LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC |
1486 : LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1487 9 : ret = libspdm_asn1_get_tag(&ptr, (uint8_t *)(buffer + length), &obj_len,
1488 : LIBSPDM_CRYPTO_ASN1_UTF8_STRING);
1489 9 : if (!ret) {
1490 0 : return false;
1491 : }
1492 :
1493 9 : if (*name_buffer_size < (size_t)obj_len + 1) {
1494 0 : *name_buffer_size = (size_t)obj_len + 1;
1495 0 : return false;
1496 : }
1497 :
1498 : /* the src and dst address are overlap,
1499 : * When the function is called by libspdm_get_dmtf_subject_alt_name.
1500 : * libspdm_copy_mem can not be used. */
1501 9 : if ((name_buffer != NULL) && (ptr != NULL)) {
1502 9 : dst = (volatile uint8_t*) name_buffer;
1503 9 : src = (const volatile uint8_t*) ptr;
1504 9 : dst_len = *name_buffer_size;
1505 9 : src_len = obj_len;
1506 :
1507 : /* Check for case where "dst_len" may be invalid. Do not zero "dst" in this case. */
1508 9 : if (dst_len > (SIZE_MAX >> 1)) {
1509 0 : LIBSPDM_ASSERT(0);
1510 0 : return false;
1511 : }
1512 :
1513 : /* Guard against invalid lengths. Zero "dst" in these cases. */
1514 9 : if (src_len > dst_len ||
1515 9 : src_len > (SIZE_MAX >> 1)) {
1516 0 : libspdm_zero_mem(name_buffer, dst_len);
1517 0 : LIBSPDM_ASSERT(0);
1518 0 : return false;
1519 : }
1520 :
1521 207 : while (src_len-- != 0) {
1522 198 : *(dst++) = *(src++);
1523 : }
1524 :
1525 : /*encode name buffer to string*/
1526 9 : *name_buffer_size = obj_len + 1;
1527 9 : name_buffer[obj_len] = 0;
1528 9 : return true;
1529 : }
1530 :
1531 0 : return false;
1532 : }
1533 :
1534 : /**
1535 : * Retrieve the SubjectAltName from one X.509 certificate.
1536 : *
1537 : * @param[in] cert Pointer to the DER-encoded X509 certificate.
1538 : * @param[in] cert_size size of the X509 certificate in bytes.
1539 : * @param[out] name_buffer buffer to contain the retrieved certificate
1540 : * SubjectAltName. At most name_buffer_size bytes will be
1541 : * written. Maybe NULL in order to determine the size
1542 : * buffer needed.
1543 : * @param[in,out] name_buffer_size The size in bytes of the name buffer on input,
1544 : * and the size of buffer returned name on output.
1545 : * If name_buffer is NULL then the amount of space needed
1546 : * in buffer (including the final null) is returned.
1547 : * @param[out] oid OID of otherName
1548 : * @param[in,out] oid_size the buffersize for required OID
1549 : *
1550 : * @retval true get the subjectAltName string successfully
1551 : * @retval failed get the subjectAltName string failed
1552 : **/
1553 6 : bool libspdm_get_dmtf_subject_alt_name(const uint8_t *cert, const size_t cert_size,
1554 : char *name_buffer,
1555 : size_t *name_buffer_size,
1556 : uint8_t *oid, size_t *oid_size)
1557 : {
1558 : bool status;
1559 : size_t extension_data_size;
1560 6 : uint8_t oid_subject_alt_name[] = { 0x55, 0x1D, 0x11 };
1561 :
1562 6 : extension_data_size = 0;
1563 6 : status = libspdm_x509_get_extension_data(cert, cert_size,
1564 : oid_subject_alt_name,
1565 : sizeof(oid_subject_alt_name), NULL,
1566 : &extension_data_size);
1567 6 : if (status || (extension_data_size == 0)) {
1568 0 : *name_buffer_size = 0;
1569 0 : return false;
1570 : }
1571 6 : if (extension_data_size > *name_buffer_size) {
1572 0 : *name_buffer_size = extension_data_size;
1573 0 : return false;
1574 : }
1575 : status =
1576 6 : libspdm_x509_get_extension_data(cert, cert_size,
1577 : oid_subject_alt_name,
1578 : sizeof(oid_subject_alt_name),
1579 : (uint8_t *)name_buffer, name_buffer_size);
1580 6 : if (!status) {
1581 0 : return status;
1582 : }
1583 :
1584 6 : return libspdm_get_dmtf_subject_alt_name_from_bytes(
1585 : (uint8_t *)name_buffer, *name_buffer_size, name_buffer,
1586 : name_buffer_size, oid, oid_size);
1587 : }
1588 :
1589 : /**
1590 : * This function verifies the integrity of certificate chain data without spdm_cert_chain_t header.
1591 : * It is used for SPDM 1.3.
1592 : *
1593 : * @param cert_chain_data The certificate chain data without spdm_cert_chain_t header.
1594 : * @param cert_chain_data_size Size in bytes of the certificate chain data.
1595 : * @param base_asym_algo SPDM base_asym_algo
1596 : * @param base_hash_algo SPDM base_hash_algo
1597 : * @param is_requester_cert Is the function verifying requester or responder cert.
1598 : * @param cert_model One of the SPDM_CERTIFICATE_INFO_CERT_MODEL_* macros.
1599 : *
1600 : * @retval true Certificate chain data integrity verification pass.
1601 : * @retval false Certificate chain data integrity verification fail.
1602 : **/
1603 6 : bool libspdm_verify_cert_chain_data_ex(uint8_t *cert_chain_data, size_t cert_chain_data_size,
1604 : uint32_t base_asym_algo, uint32_t base_hash_algo,
1605 : bool is_requester_cert, uint8_t cert_model)
1606 : {
1607 : const uint8_t *root_cert_buffer;
1608 : size_t root_cert_buffer_size;
1609 : const uint8_t *leaf_cert_buffer;
1610 : size_t leaf_cert_buffer_size;
1611 :
1612 6 : if (cert_chain_data_size >
1613 : 0xFFFF - (sizeof(spdm_cert_chain_t) + LIBSPDM_MAX_HASH_SIZE)) {
1614 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1615 : "!!! VerifyCertificateChainData - FAIL (chain size too large) !!!\n"));
1616 0 : return false;
1617 : }
1618 :
1619 6 : if (!libspdm_x509_get_cert_from_cert_chain(
1620 : cert_chain_data, cert_chain_data_size, 0, &root_cert_buffer,
1621 : &root_cert_buffer_size)) {
1622 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1623 : "!!! VerifyCertificateChainData - FAIL (get root certificate failed)!!!\n"));
1624 0 : return false;
1625 : }
1626 :
1627 6 : if (!libspdm_x509_verify_cert_chain(root_cert_buffer, root_cert_buffer_size,
1628 : cert_chain_data, cert_chain_data_size)) {
1629 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1630 : "!!! VerifyCertificateChainData - FAIL (cert chain verify failed)!!!\n"));
1631 2 : return false;
1632 : }
1633 :
1634 4 : if (!libspdm_x509_get_cert_from_cert_chain(
1635 : cert_chain_data, cert_chain_data_size, -1,
1636 : &leaf_cert_buffer, &leaf_cert_buffer_size)) {
1637 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1638 : "!!! VerifyCertificateChainData - FAIL (get leaf certificate failed)!!!\n"));
1639 0 : return false;
1640 : }
1641 :
1642 4 : if (!libspdm_x509_certificate_check_ex(leaf_cert_buffer, leaf_cert_buffer_size,
1643 : base_asym_algo, base_hash_algo,
1644 : is_requester_cert, cert_model)) {
1645 1 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1646 : "!!! VerifyCertificateChainData - FAIL (leaf certificate check failed)!!!\n"));
1647 1 : return false;
1648 : }
1649 :
1650 3 : return true;
1651 : }
1652 : /**
1653 : * This function verifies the integrity of certificate chain data without spdm_cert_chain_t header.
1654 : *
1655 : * @param cert_chain_data The certificate chain data without spdm_cert_chain_t header.
1656 : * @param cert_chain_data_size size in bytes of the certificate chain data.
1657 : * @param base_asym_algo SPDM base_asym_algo
1658 : * @param base_hash_algo SPDM base_hash_algo
1659 : * @param is_requester_cert Is the function verifying requester or responder cert.
1660 : * @param is_device_cert_model If true, the cert chain is DeviceCert model;
1661 : * If false, the cert chain is AliasCert model;
1662 : *
1663 : * @retval true certificate chain data integrity verification pass.
1664 : * @retval false certificate chain data integrity verification fail.
1665 : **/
1666 689 : bool libspdm_verify_cert_chain_data(uint8_t *cert_chain_data, size_t cert_chain_data_size,
1667 : uint32_t base_asym_algo, uint32_t base_hash_algo,
1668 : bool is_requester_cert, bool is_device_cert_model)
1669 : {
1670 : const uint8_t *root_cert_buffer;
1671 : size_t root_cert_buffer_size;
1672 : const uint8_t *leaf_cert_buffer;
1673 : size_t leaf_cert_buffer_size;
1674 :
1675 689 : if (cert_chain_data_size >
1676 : 0xFFFF - (sizeof(spdm_cert_chain_t) + LIBSPDM_MAX_HASH_SIZE)) {
1677 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1678 : "!!! VerifyCertificateChainData - FAIL (chain size too large) !!!\n"));
1679 0 : return false;
1680 : }
1681 :
1682 689 : if (!libspdm_x509_get_cert_from_cert_chain(
1683 : cert_chain_data, cert_chain_data_size, 0, &root_cert_buffer,
1684 : &root_cert_buffer_size)) {
1685 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1686 : "!!! VerifyCertificateChainData - FAIL (get root certificate failed)!!!\n"));
1687 0 : return false;
1688 : }
1689 :
1690 689 : if (!libspdm_x509_verify_cert_chain(root_cert_buffer, root_cert_buffer_size,
1691 : cert_chain_data, cert_chain_data_size)) {
1692 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1693 : "!!! VerifyCertificateChainData - FAIL (cert chain verify failed)!!!\n"));
1694 0 : return false;
1695 : }
1696 :
1697 689 : if (!libspdm_x509_get_cert_from_cert_chain(
1698 : cert_chain_data, cert_chain_data_size, -1,
1699 : &leaf_cert_buffer, &leaf_cert_buffer_size)) {
1700 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1701 : "!!! VerifyCertificateChainData - FAIL (get leaf certificate failed)!!!\n"));
1702 0 : return false;
1703 : }
1704 :
1705 689 : if (!libspdm_x509_certificate_check(leaf_cert_buffer, leaf_cert_buffer_size,
1706 : base_asym_algo, base_hash_algo,
1707 : is_requester_cert, is_device_cert_model)) {
1708 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1709 : "!!! VerifyCertificateChainData - FAIL (leaf certificate check failed)!!!\n"));
1710 0 : return false;
1711 : }
1712 :
1713 689 : return true;
1714 : }
1715 :
1716 : /**
1717 : * This function verifies the integrity of certificate chain buffer including
1718 : * spdm_cert_chain_t header. It is used for SPDM 1.3.
1719 : *
1720 : * @param base_hash_algo SPDM base_hash_algo
1721 : * @param base_asym_algo SPDM base_asym_algo
1722 : * @param cert_chain_buffer The certificate chain buffer including spdm_cert_chain_t header.
1723 : * @param cert_chain_buffer_size Size in bytes of the certificate chain buffer.
1724 : * @param is_requester_cert Is the function verifying requester or responder cert.
1725 : * @param cert_model One of the SPDM_CERTIFICATE_INFO_CERT_MODEL_* macros.
1726 : *
1727 : * @retval true Certificate chain buffer integrity verification pass.
1728 : * @retval false Certificate chain buffer integrity verification fail.
1729 : **/
1730 6 : bool libspdm_verify_certificate_chain_buffer_ex(uint32_t base_hash_algo, uint32_t base_asym_algo,
1731 : const void *cert_chain_buffer,
1732 : size_t cert_chain_buffer_size,
1733 : bool is_requester_cert, uint8_t cert_model)
1734 : {
1735 : const uint8_t *cert_chain_data;
1736 : size_t cert_chain_data_size;
1737 : const uint8_t *first_cert_buffer;
1738 : size_t first_cert_buffer_size;
1739 : size_t hash_size;
1740 : uint8_t calc_root_cert_hash[LIBSPDM_MAX_HASH_SIZE];
1741 : const uint8_t *leaf_cert_buffer;
1742 : size_t leaf_cert_buffer_size;
1743 : bool result;
1744 : const spdm_cert_chain_t *cert_chain_header;
1745 :
1746 6 : hash_size = libspdm_get_hash_size(base_hash_algo);
1747 :
1748 6 : if (cert_chain_buffer_size <= sizeof(spdm_cert_chain_t) + hash_size) {
1749 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1750 : "!!! VerifyCertificateChainBuffer - FAIL (buffer too small) !!!\n"));
1751 0 : return false;
1752 : }
1753 :
1754 6 : cert_chain_header = cert_chain_buffer;
1755 6 : if (cert_chain_header->length != cert_chain_buffer_size) {
1756 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1757 : "!!! VerifyCertificateChainBuffer - FAIL (cert_chain->length mismatch) !!!\n"));
1758 2 : return false;
1759 : }
1760 :
1761 4 : cert_chain_data = (const uint8_t *)cert_chain_buffer + sizeof(spdm_cert_chain_t) + hash_size;
1762 4 : cert_chain_data_size = cert_chain_buffer_size - sizeof(spdm_cert_chain_t) - hash_size;
1763 4 : if (!libspdm_x509_get_cert_from_cert_chain(
1764 : cert_chain_data, cert_chain_data_size, 0, &first_cert_buffer,
1765 : &first_cert_buffer_size)) {
1766 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1767 : "!!! VerifyCertificateChainBuffer - FAIL (get root certificate failed)!!!\n"));
1768 0 : return false;
1769 : }
1770 :
1771 4 : if (libspdm_is_root_certificate(first_cert_buffer, first_cert_buffer_size)) {
1772 4 : result = libspdm_hash_all(base_hash_algo, first_cert_buffer, first_cert_buffer_size,
1773 : calc_root_cert_hash);
1774 4 : if (!result) {
1775 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1776 : "!!! VerifyCertificateChainBuffer - FAIL (hash calculation fail) !!!\n"));
1777 0 : return false;
1778 : }
1779 4 : if (!libspdm_consttime_is_mem_equal((const uint8_t *)cert_chain_buffer +
1780 : sizeof(spdm_cert_chain_t),
1781 : calc_root_cert_hash, hash_size)) {
1782 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1783 : "!!! VerifyCertificateChainBuffer - FAIL (cert root hash mismatch) !!!\n"));
1784 0 : return false;
1785 : }
1786 4 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1787 : "!!! VerifyCertificateChainBuffer - PASS (cert root hash match) !!!\n"));
1788 : }
1789 :
1790 : /*If the number of certificates in the certificate chain is more than 1,
1791 : * other certificates need to be verified.*/
1792 4 : if (cert_chain_data_size > first_cert_buffer_size) {
1793 4 : if (!libspdm_x509_verify_cert_chain(first_cert_buffer, first_cert_buffer_size,
1794 : cert_chain_data + first_cert_buffer_size,
1795 : cert_chain_data_size - first_cert_buffer_size)) {
1796 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1797 : "!!! VerifyCertificateChainBuffer - FAIL (cert chain verify failed)!!!\n"));
1798 0 : return false;
1799 : }
1800 : }
1801 :
1802 4 : if (!libspdm_x509_get_cert_from_cert_chain(
1803 : cert_chain_data, cert_chain_data_size, -1,
1804 : &leaf_cert_buffer, &leaf_cert_buffer_size)) {
1805 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1806 : "!!! VerifyCertificateChainBuffer - FAIL (get leaf certificate failed)!!!\n"));
1807 0 : return false;
1808 : }
1809 :
1810 4 : if (!libspdm_x509_certificate_check_ex(leaf_cert_buffer, leaf_cert_buffer_size,
1811 : base_asym_algo, base_hash_algo,
1812 : is_requester_cert, cert_model)) {
1813 1 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1814 : "!!! VerifyCertificateChainBuffer - FAIL (leaf certificate check failed)!!!\n"));
1815 1 : return false;
1816 : }
1817 :
1818 3 : return true;
1819 : }
1820 :
1821 34 : bool libspdm_verify_certificate_chain_buffer(uint32_t base_hash_algo, uint32_t base_asym_algo,
1822 : const void *cert_chain_buffer,
1823 : size_t cert_chain_buffer_size,
1824 : bool is_requester_cert,
1825 : bool is_device_cert_model)
1826 : {
1827 : const uint8_t *cert_chain_data;
1828 : size_t cert_chain_data_size;
1829 : const uint8_t *first_cert_buffer;
1830 : size_t first_cert_buffer_size;
1831 : size_t hash_size;
1832 : uint8_t calc_root_cert_hash[LIBSPDM_MAX_HASH_SIZE];
1833 : const uint8_t *leaf_cert_buffer;
1834 : size_t leaf_cert_buffer_size;
1835 : bool result;
1836 : const spdm_cert_chain_t *cert_chain_header;
1837 :
1838 34 : hash_size = libspdm_get_hash_size(base_hash_algo);
1839 :
1840 34 : if (cert_chain_buffer_size <= sizeof(spdm_cert_chain_t) + hash_size) {
1841 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1842 : "!!! VerifyCertificateChainBuffer - FAIL (buffer too small) !!!\n"));
1843 0 : return false;
1844 : }
1845 :
1846 34 : cert_chain_header = cert_chain_buffer;
1847 34 : if (cert_chain_header->length != cert_chain_buffer_size) {
1848 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1849 : "!!! VerifyCertificateChainBuffer - FAIL (cert_chain->length mismatch) !!!\n"));
1850 0 : return false;
1851 : }
1852 :
1853 34 : cert_chain_data = (const uint8_t *)cert_chain_buffer + sizeof(spdm_cert_chain_t) + hash_size;
1854 34 : cert_chain_data_size = cert_chain_buffer_size - sizeof(spdm_cert_chain_t) - hash_size;
1855 34 : if (!libspdm_x509_get_cert_from_cert_chain(
1856 : cert_chain_data, cert_chain_data_size, 0, &first_cert_buffer,
1857 : &first_cert_buffer_size)) {
1858 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1859 : "!!! VerifyCertificateChainBuffer - FAIL (get root certificate failed)!!!\n"));
1860 0 : return false;
1861 : }
1862 :
1863 34 : if (libspdm_is_root_certificate(first_cert_buffer, first_cert_buffer_size)) {
1864 32 : result = libspdm_hash_all(base_hash_algo, first_cert_buffer, first_cert_buffer_size,
1865 : calc_root_cert_hash);
1866 32 : if (!result) {
1867 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1868 : "!!! VerifyCertificateChainBuffer - FAIL (hash calculation fail) !!!\n"));
1869 0 : return false;
1870 : }
1871 32 : if (!libspdm_consttime_is_mem_equal((const uint8_t *)cert_chain_buffer +
1872 : sizeof(spdm_cert_chain_t),
1873 : calc_root_cert_hash, hash_size)) {
1874 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1875 : "!!! VerifyCertificateChainBuffer - FAIL (cert root hash mismatch) !!!\n"));
1876 0 : return false;
1877 : }
1878 32 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1879 : "!!! VerifyCertificateChainBuffer - PASS (cert root hash match) !!!\n"));
1880 : }
1881 :
1882 : /*If the number of certificates in the certificate chain is more than 1,
1883 : * other certificates need to be verified.*/
1884 34 : if (cert_chain_data_size > first_cert_buffer_size) {
1885 34 : if (!libspdm_x509_verify_cert_chain(first_cert_buffer, first_cert_buffer_size,
1886 : cert_chain_data + first_cert_buffer_size,
1887 : cert_chain_data_size - first_cert_buffer_size)) {
1888 3 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1889 : "!!! VerifyCertificateChainBuffer - FAIL (cert chain verify failed)!!!\n"));
1890 3 : return false;
1891 : }
1892 : }
1893 :
1894 31 : if (!libspdm_x509_get_cert_from_cert_chain(
1895 : cert_chain_data, cert_chain_data_size, -1,
1896 : &leaf_cert_buffer, &leaf_cert_buffer_size)) {
1897 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1898 : "!!! VerifyCertificateChainBuffer - FAIL (get leaf certificate failed)!!!\n"));
1899 0 : return false;
1900 : }
1901 :
1902 31 : if (!libspdm_x509_certificate_check(leaf_cert_buffer, leaf_cert_buffer_size,
1903 : base_asym_algo, base_hash_algo,
1904 : is_requester_cert, is_device_cert_model)) {
1905 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
1906 : "!!! VerifyCertificateChainBuffer - FAIL (leaf certificate check failed)!!!\n"));
1907 2 : return false;
1908 : }
1909 :
1910 29 : return true;
1911 : }
1912 :
1913 254 : bool libspdm_get_leaf_cert_public_key_from_cert_chain(uint32_t base_hash_algo,
1914 : uint32_t base_asym_alg,
1915 : uint8_t *cert_chain_data,
1916 : size_t cert_chain_data_size,
1917 : void **public_key)
1918 : {
1919 : size_t hash_size;
1920 : const uint8_t *cert_buffer;
1921 : size_t cert_buffer_size;
1922 : bool result;
1923 :
1924 254 : hash_size = libspdm_get_hash_size(base_hash_algo);
1925 :
1926 254 : cert_chain_data = cert_chain_data + sizeof(spdm_cert_chain_t) + hash_size;
1927 254 : cert_chain_data_size = cert_chain_data_size - (sizeof(spdm_cert_chain_t) + hash_size);
1928 :
1929 : /* Get leaf cert from cert chain */
1930 254 : result = libspdm_x509_get_cert_from_cert_chain(cert_chain_data,
1931 : cert_chain_data_size, -1,
1932 : &cert_buffer, &cert_buffer_size);
1933 254 : if (!result) {
1934 0 : return false;
1935 : }
1936 :
1937 254 : result = libspdm_asym_get_public_key_from_x509(
1938 : base_asym_alg,
1939 : cert_buffer, cert_buffer_size, public_key);
1940 254 : if (!result) {
1941 4 : return false;
1942 : }
1943 :
1944 250 : return true;
1945 : }
1946 :
1947 29 : bool libspdm_verify_req_info(uint8_t *req_info, uint16_t req_info_len)
1948 : {
1949 : bool ret;
1950 : uint8_t *ptr;
1951 : int32_t length;
1952 : size_t obj_len;
1953 : uint8_t *end;
1954 :
1955 29 : length = (int32_t)req_info_len;
1956 29 : ptr = req_info;
1957 29 : obj_len = 0;
1958 29 : end = ptr + length;
1959 29 : ret = true;
1960 :
1961 29 : if (req_info_len == 0) {
1962 4 : return true;
1963 : }
1964 :
1965 : /*req_info sequence*/
1966 25 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
1967 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1968 25 : if (!ret) {
1969 2 : return false;
1970 : }
1971 :
1972 : /*integer:version*/
1973 23 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len, LIBSPDM_CRYPTO_ASN1_INTEGER);
1974 23 : if (!ret) {
1975 0 : return false;
1976 : } else {
1977 23 : ptr += obj_len;
1978 : }
1979 :
1980 : /*sequence:subject name*/
1981 23 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
1982 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1983 23 : if (!ret) {
1984 0 : return false;
1985 : } else {
1986 23 : ptr += obj_len;
1987 : }
1988 :
1989 : /*sequence:subject pkinfo*/
1990 23 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
1991 : LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
1992 23 : if (!ret) {
1993 0 : return false;
1994 : } else {
1995 23 : ptr += obj_len;
1996 : }
1997 :
1998 : /*[0]: attributes*/
1999 23 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
2000 : LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC |
2001 : LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
2002 : /*req_info format error, don't have attributes tag*/
2003 23 : if (!ret) {
2004 0 : return false;
2005 : }
2006 :
2007 : /*there is no attributes object*/
2008 23 : if (ptr == end) {
2009 0 : return true;
2010 : }
2011 :
2012 : /*there is some attributes object: 0,1,2 ...*/
2013 46 : while (ret)
2014 : {
2015 46 : ret = libspdm_asn1_get_tag(&ptr, end, &obj_len,
2016 : LIBSPDM_CRYPTO_ASN1_SEQUENCE |
2017 : LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
2018 46 : if (ret) {
2019 23 : ptr += obj_len;
2020 : } else {
2021 23 : break;
2022 : }
2023 : }
2024 :
2025 23 : if (ptr == end) {
2026 23 : return true;
2027 : } else {
2028 0 : return false;
2029 : }
2030 : }
2031 :
2032 : #endif
|