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_requester_lib.h"
8 :
9 : #if LIBSPDM_SEND_GET_CERTIFICATE_SUPPORT
10 :
11 : /**
12 : * This function sends GET_CERTIFICATE and receives CERTIFICATE.
13 : *
14 : * This function verify the integrity of the certificate chain.
15 : * root_hash -> Root certificate -> Intermediate certificate -> Leaf certificate.
16 : *
17 : * If the peer root certificate hash is deployed,
18 : * this function also verifies the digest with the root hash in the certificate chain.
19 : *
20 : * @param spdm_context A pointer to the SPDM context.
21 : * @param slot_id The number of slot for the certificate chain.
22 : * @param cert_chain_size On input, indicate the size in bytes of the destination buffer to store
23 : * the digest buffer.
24 : * On output, indicate the size in bytes of the certificate chain.
25 : * @param cert_chain A pointer to a destination buffer to store the certificate chain.
26 : * @param trust_anchor A buffer to hold the trust_anchor which is used to validate the peer
27 : * certificate, if not NULL.
28 : * @param trust_anchor_size A buffer to hold the trust_anchor_size, if not NULL.
29 : *
30 : * @retval LIBSPDM_STATUS_SUCCESS
31 : * GET_CERTIFICATE was sent and CERTIFICATE was received.
32 : * @retval LIBSPDM_STATUS_INVALID_STATE_LOCAL
33 : * Cannot send GET_CERTIFICATE due to Requester's state.
34 : * @retval LIBSPDM_STATUS_UNSUPPORTED_CAP
35 : * Cannot send GET_CERTIFICATE because the Requester's and/or Responder's CERT_CAP = 0.
36 : * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE
37 : * The size of the CERTIFICATE response is invalid.
38 : * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD
39 : * The CERTIFICATE response contains one or more invalid fields.
40 : * @retval LIBSPDM_STATUS_ERROR_PEER
41 : * The Responder returned an unexpected error.
42 : * @retval LIBSPDM_STATUS_BUSY_PEER
43 : * The Responder continually returned Busy error messages.
44 : * @retval LIBSPDM_STATUS_RESYNCH_PEER
45 : * The Responder returned a RequestResynch error message.
46 : * @retval LIBSPDM_STATUS_BUFFER_FULL
47 : * The buffer used to store transcripts is exhausted.
48 : * @retval LIBSPDM_STATUS_VERIF_FAIL
49 : * Verification of the certificate chain failed.
50 : * @retval LIBSPDM_STATUS_INVALID_CERT
51 : * The certificate is unable to be parsed or contains invalid field values.
52 : * @retval LIBSPDM_STATUS_CRYPTO_ERROR
53 : * A generic cryptography error occurred.
54 : **/
55 57 : static libspdm_return_t libspdm_try_get_large_certificate(libspdm_context_t *spdm_context,
56 : const uint32_t *session_id,
57 : uint8_t slot_id,
58 : uint32_t length,
59 : size_t *cert_chain_size,
60 : void *cert_chain,
61 : const void **trust_anchor,
62 : size_t *trust_anchor_size)
63 : {
64 : bool result;
65 : libspdm_return_t status;
66 : spdm_get_certificate_large_request_t *spdm_request;
67 : size_t spdm_request_size;
68 : spdm_certificate_large_response_t *spdm_response;
69 : size_t spdm_response_size;
70 : uint32_t total_responder_cert_chain_buffer_length;
71 : size_t cert_chain_capacity;
72 : size_t cert_chain_size_internal;
73 : uint32_t remainder_length;
74 : uint8_t *message;
75 : size_t message_size;
76 : size_t transport_header_size;
77 : libspdm_session_info_t *session_info;
78 : libspdm_session_state_t session_state;
79 : bool chunk_enabled;
80 : uint8_t cert_model;
81 : uint32_t req_msg_length;
82 : uint32_t req_msg_offset;
83 : uint32_t rsp_msg_portion_length;
84 : uint32_t rsp_msg_remainder_length;
85 : bool use_large_cert_chain;
86 : uint32_t req_msg_header_size;
87 : uint32_t rsp_msg_header_size;
88 : uint32_t max_cert_chain_size;
89 :
90 : /* -=[Check Parameters Phase]=- */
91 57 : LIBSPDM_ASSERT(slot_id < SPDM_MAX_SLOT_COUNT);
92 57 : LIBSPDM_ASSERT(cert_chain_size != NULL);
93 57 : LIBSPDM_ASSERT(*cert_chain_size > 0);
94 57 : LIBSPDM_ASSERT(cert_chain != NULL);
95 :
96 57 : if ((length > SPDM_MAX_CERTIFICATE_CHAIN_SIZE) &&
97 0 : (libspdm_get_connection_version (spdm_context) < SPDM_MESSAGE_VERSION_14)) {
98 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
99 : }
100 :
101 57 : if ((length == SPDM_MAX_CERTIFICATE_CHAIN_SIZE) &&
102 0 : (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_14)) {
103 : /* support compatibility */
104 0 : length = SPDM_MAX_CERTIFICATE_CHAIN_SIZE_14;
105 : }
106 :
107 57 : if ((libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_14) &&
108 0 : libspdm_is_capabilities_flag_supported(
109 : spdm_context, true, 0,
110 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_LARGE_RESP_CAP)) {
111 0 : use_large_cert_chain = true;
112 : } else {
113 57 : use_large_cert_chain = false;
114 : }
115 :
116 57 : if (use_large_cert_chain) {
117 0 : max_cert_chain_size = SPDM_MAX_CERTIFICATE_CHAIN_SIZE_14;
118 0 : req_msg_header_size = sizeof(spdm_get_certificate_large_request_t);
119 0 : rsp_msg_header_size = sizeof(spdm_certificate_large_response_t);
120 : } else {
121 57 : max_cert_chain_size = SPDM_MAX_CERTIFICATE_CHAIN_SIZE;
122 57 : req_msg_header_size = sizeof(spdm_get_certificate_request_t);
123 57 : rsp_msg_header_size = sizeof(spdm_certificate_response_t);
124 : }
125 :
126 : /* use default max buffer length */
127 57 : if (length == 0) {
128 56 : length = spdm_context->local_context.capability.max_spdm_msg_size - rsp_msg_header_size;
129 :
130 56 : if (!use_large_cert_chain) {
131 56 : length = LIBSPDM_MIN(length, SPDM_MAX_CERTIFICATE_CHAIN_SIZE);
132 : }
133 : }
134 :
135 : /* -=[Verify State Phase]=- */
136 57 : if (!libspdm_is_capabilities_flag_supported(
137 : spdm_context, true, 0,
138 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP)) {
139 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
140 : }
141 57 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
142 1 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
143 : }
144 :
145 56 : session_info = NULL;
146 56 : if (session_id != NULL) {
147 1 : session_info = libspdm_get_session_info_via_session_id(spdm_context, *session_id);
148 1 : if (session_info == NULL) {
149 0 : LIBSPDM_ASSERT(false);
150 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
151 : }
152 1 : session_state = libspdm_secured_message_get_session_state(
153 : session_info->secured_message_context);
154 1 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
155 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
156 : }
157 : }
158 :
159 56 : libspdm_reset_message_buffer_via_request_code(spdm_context, session_info, SPDM_GET_CERTIFICATE);
160 :
161 : chunk_enabled =
162 56 : libspdm_is_capabilities_flag_supported(spdm_context, true,
163 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP,
164 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP);
165 :
166 56 : remainder_length = 0;
167 56 : total_responder_cert_chain_buffer_length = 0;
168 56 : cert_chain_capacity = *cert_chain_size;
169 56 : cert_chain_size_internal = 0;
170 :
171 56 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
172 :
173 : do {
174 : /* -=[Construct Request Phase]=- */
175 1468 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
176 1468 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
177 0 : return status;
178 : }
179 1468 : LIBSPDM_ASSERT (message_size >= transport_header_size +
180 : spdm_context->local_context.capability.transport_tail_size);
181 1468 : spdm_request = (void *)(message + transport_header_size);
182 1468 : spdm_request_size = message_size - transport_header_size -
183 1468 : spdm_context->local_context.capability.transport_tail_size;
184 :
185 1468 : LIBSPDM_ASSERT (spdm_request_size >= req_msg_header_size);
186 1468 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
187 1468 : spdm_request->header.request_response_code = SPDM_GET_CERTIFICATE;
188 1468 : spdm_request->header.param1 = slot_id;
189 1468 : spdm_request->header.param2 = 0;
190 1468 : req_msg_offset = (uint32_t)cert_chain_size_internal;
191 1468 : if (req_msg_offset == 0) {
192 56 : req_msg_length = length;
193 : } else {
194 1412 : req_msg_length = LIBSPDM_MIN(length, remainder_length);
195 : }
196 1468 : if (use_large_cert_chain) {
197 0 : spdm_request->header.param1 |= SPDM_GET_CERTIFICATE_REQUEST_LARGE_CERT_CHAIN;
198 0 : spdm_request->offset = 0;
199 0 : spdm_request->length = 0;
200 0 : spdm_request->large_offset = req_msg_offset;
201 0 : spdm_request->large_length = req_msg_length;
202 : } else {
203 1468 : spdm_request->offset = (uint16_t)req_msg_offset;
204 1468 : spdm_request->length = (uint16_t)req_msg_length;
205 : }
206 1468 : spdm_request_size = req_msg_header_size;
207 1468 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "request (offset 0x%x, size 0x%x):\n",
208 : req_msg_offset,req_msg_length));
209 :
210 : /* -=[Send Request Phase]=- */
211 : status =
212 1468 : libspdm_send_spdm_request(spdm_context, session_id, spdm_request_size, spdm_request);
213 1468 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
214 1 : libspdm_release_sender_buffer (spdm_context);
215 1 : status = LIBSPDM_STATUS_SEND_FAIL;
216 1 : goto done;
217 : }
218 1467 : libspdm_release_sender_buffer (spdm_context);
219 1467 : spdm_request = (void *)spdm_context->last_spdm_request;
220 :
221 : /* -=[Receive Response Phase]=- */
222 1467 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
223 1467 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
224 0 : return status;
225 : }
226 1467 : LIBSPDM_ASSERT (message_size >= transport_header_size);
227 1467 : spdm_response = (void *)(message);
228 1467 : spdm_response_size = message_size;
229 :
230 1467 : status = libspdm_receive_spdm_response(spdm_context, session_id,
231 : &spdm_response_size,
232 : (void **)&spdm_response);
233 1467 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
234 0 : libspdm_release_receiver_buffer (spdm_context);
235 0 : status = LIBSPDM_STATUS_RECEIVE_FAIL;
236 0 : goto done;
237 : }
238 :
239 : /* -=[Validate Response Phase]=- */
240 1467 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
241 0 : libspdm_release_receiver_buffer (spdm_context);
242 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
243 0 : goto done;
244 : }
245 1467 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
246 24 : status = libspdm_handle_error_response_main(
247 : spdm_context, session_id,
248 : &spdm_response_size,
249 : (void **)&spdm_response, SPDM_GET_CERTIFICATE,
250 : SPDM_CERTIFICATE);
251 24 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
252 23 : libspdm_release_receiver_buffer (spdm_context);
253 23 : goto done;
254 : }
255 1443 : } else if (spdm_response->header.request_response_code != SPDM_CERTIFICATE) {
256 0 : libspdm_release_receiver_buffer (spdm_context);
257 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
258 0 : goto done;
259 : }
260 1444 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
261 0 : libspdm_release_receiver_buffer (spdm_context);
262 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
263 0 : goto done;
264 : }
265 1444 : if (spdm_response_size < rsp_msg_header_size) {
266 0 : libspdm_release_receiver_buffer (spdm_context);
267 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
268 0 : goto done;
269 : }
270 1444 : if (use_large_cert_chain) {
271 0 : if ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_LARGE_CERT_CHAIN) == 0) {
272 0 : libspdm_release_receiver_buffer (spdm_context);
273 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
274 0 : goto done;
275 : }
276 : } else {
277 1444 : if ((spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_14) &&
278 0 : ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_LARGE_CERT_CHAIN) != 0)) {
279 0 : libspdm_release_receiver_buffer (spdm_context);
280 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
281 0 : goto done;
282 : }
283 : }
284 1444 : if (use_large_cert_chain) {
285 0 : rsp_msg_portion_length = spdm_response->large_portion_length;
286 0 : rsp_msg_remainder_length = spdm_response->large_remainder_length;
287 : } else {
288 1444 : rsp_msg_portion_length = spdm_response->portion_length;
289 1444 : rsp_msg_remainder_length = spdm_response->remainder_length;
290 : }
291 :
292 1444 : if ((rsp_msg_portion_length > req_msg_length) ||
293 : (rsp_msg_portion_length == 0)) {
294 3 : libspdm_release_receiver_buffer (spdm_context);
295 3 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
296 3 : goto done;
297 : }
298 1441 : if ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_SLOT_ID_MASK) != slot_id) {
299 1 : libspdm_release_receiver_buffer (spdm_context);
300 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
301 1 : goto done;
302 : }
303 1440 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
304 10 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "cert_info - 0x%02x\n",
305 : spdm_response->header.param2));
306 10 : cert_model = spdm_response->header.param2 &
307 : SPDM_CERTIFICATE_RESPONSE_ATTRIBUTES_CERTIFICATE_INFO_MASK;
308 10 : if (spdm_context->connection_info.multi_key_conn_rsp) {
309 8 : if (cert_model > SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT) {
310 0 : libspdm_release_receiver_buffer (spdm_context);
311 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
312 0 : goto done;
313 : }
314 8 : if ((slot_id == 0) &&
315 : (cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT)) {
316 1 : libspdm_release_receiver_buffer (spdm_context);
317 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
318 1 : goto done;
319 : }
320 7 : if ((cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) &&
321 : (rsp_msg_portion_length != 0)) {
322 1 : libspdm_release_receiver_buffer (spdm_context);
323 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
324 1 : goto done;
325 : }
326 : } else {
327 2 : if (cert_model != SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) {
328 0 : libspdm_release_receiver_buffer (spdm_context);
329 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
330 0 : goto done;
331 : }
332 : }
333 8 : if (spdm_context->connection_info.peer_cert_info[slot_id] ==
334 : SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) {
335 5 : spdm_context->connection_info.peer_cert_info[slot_id] = cert_model;
336 3 : } else if (spdm_context->connection_info.peer_cert_info[slot_id] != cert_model) {
337 0 : libspdm_release_receiver_buffer (spdm_context);
338 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
339 0 : goto done;
340 : }
341 : }
342 1438 : if (spdm_response_size < rsp_msg_header_size +
343 : rsp_msg_portion_length) {
344 0 : libspdm_release_receiver_buffer (spdm_context);
345 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
346 0 : goto done;
347 : }
348 1438 : if (rsp_msg_portion_length > max_cert_chain_size - req_msg_offset) {
349 0 : libspdm_release_receiver_buffer (spdm_context);
350 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
351 0 : goto done;
352 : }
353 1438 : if (rsp_msg_remainder_length > max_cert_chain_size - req_msg_offset -
354 : rsp_msg_portion_length) {
355 0 : libspdm_release_receiver_buffer (spdm_context);
356 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
357 0 : goto done;
358 : }
359 1438 : if (req_msg_offset == 0) {
360 27 : total_responder_cert_chain_buffer_length = rsp_msg_portion_length +
361 : rsp_msg_remainder_length;
362 27 : if (total_responder_cert_chain_buffer_length > cert_chain_capacity) {
363 1 : libspdm_release_receiver_buffer (spdm_context);
364 1 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
365 1 : goto done;
366 : }
367 1411 : } else if (req_msg_offset + rsp_msg_portion_length +
368 : rsp_msg_remainder_length != total_responder_cert_chain_buffer_length) {
369 0 : libspdm_release_receiver_buffer (spdm_context);
370 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
371 0 : goto done;
372 : }
373 1437 : if (chunk_enabled && (req_msg_offset == 0) && (req_msg_length == max_cert_chain_size) &&
374 : (rsp_msg_remainder_length != 0)) {
375 0 : libspdm_release_receiver_buffer (spdm_context);
376 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
377 0 : goto done;
378 : }
379 :
380 : /* -=[Process Response Phase]=- */
381 1437 : remainder_length = rsp_msg_remainder_length;
382 1437 : spdm_response_size = rsp_msg_header_size + rsp_msg_portion_length;
383 :
384 1437 : if (session_id == NULL) {
385 1435 : status = libspdm_append_message_b(spdm_context, spdm_request, spdm_request_size);
386 1435 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
387 0 : libspdm_release_receiver_buffer (spdm_context);
388 0 : goto done;
389 : }
390 1435 : status = libspdm_append_message_b(spdm_context, spdm_response, spdm_response_size);
391 1435 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
392 0 : libspdm_release_receiver_buffer (spdm_context);
393 0 : goto done;
394 : }
395 : }
396 :
397 1437 : if (cert_chain_size_internal + rsp_msg_portion_length > cert_chain_capacity) {
398 0 : libspdm_release_receiver_buffer (spdm_context);
399 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "cert_chain_buffer full\n"));
400 0 : status = LIBSPDM_STATUS_BUFFER_FULL;
401 0 : goto done;
402 : }
403 :
404 1437 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Certificate (offset 0x%x, size 0x%x):\n",
405 : req_msg_offset, rsp_msg_portion_length));
406 1437 : LIBSPDM_INTERNAL_DUMP_HEX((uint8_t *)spdm_response + rsp_msg_header_size,
407 : rsp_msg_portion_length);
408 :
409 1437 : libspdm_copy_mem((uint8_t *)cert_chain + cert_chain_size_internal,
410 : cert_chain_capacity - cert_chain_size_internal,
411 1437 : (uint8_t *)spdm_response + rsp_msg_header_size,
412 : rsp_msg_portion_length);
413 :
414 1437 : cert_chain_size_internal += rsp_msg_portion_length;
415 :
416 1437 : if (spdm_context->connection_info.connection_state <
417 : LIBSPDM_CONNECTION_STATE_AFTER_CERTIFICATE) {
418 22 : spdm_context->connection_info.connection_state =
419 : LIBSPDM_CONNECTION_STATE_AFTER_CERTIFICATE;
420 : }
421 :
422 : /* -=[Log Message Phase]=- */
423 : #if LIBSPDM_ENABLE_MSG_LOG
424 1437 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
425 : #endif /* LIBSPDM_ENABLE_MSG_LOG */
426 :
427 1437 : libspdm_release_receiver_buffer (spdm_context);
428 1437 : } while (remainder_length != 0);
429 :
430 25 : *cert_chain_size = cert_chain_size_internal;
431 25 : LIBSPDM_ASSERT(*cert_chain_size <= SPDM_MAX_CERTIFICATE_CHAIN_SIZE_14);
432 :
433 25 : if (spdm_context->local_context.verify_peer_spdm_cert_chain != NULL) {
434 0 : result = spdm_context->local_context.verify_peer_spdm_cert_chain (
435 : spdm_context, slot_id, cert_chain_size_internal, cert_chain,
436 : trust_anchor, trust_anchor_size);
437 0 : if (!result) {
438 0 : status = LIBSPDM_STATUS_VERIF_FAIL;
439 0 : goto done;
440 : }
441 : } else {
442 25 : result = libspdm_verify_peer_cert_chain_buffer_integrity(
443 : spdm_context, cert_chain, cert_chain_size_internal);
444 25 : if (!result) {
445 5 : status = LIBSPDM_STATUS_VERIF_FAIL;
446 5 : goto done;
447 : }
448 :
449 : /*verify peer cert chain authority*/
450 20 : result = libspdm_verify_peer_cert_chain_buffer_authority(
451 : spdm_context, cert_chain,cert_chain_size_internal,
452 : trust_anchor, trust_anchor_size);
453 20 : if (!result) {
454 2 : status = LIBSPDM_STATUS_VERIF_NO_AUTHORITY;
455 : }
456 : }
457 :
458 20 : spdm_context->connection_info.peer_used_cert_chain_slot_id = slot_id;
459 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
460 : spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_size =
461 : cert_chain_size_internal;
462 : libspdm_copy_mem(spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer,
463 : sizeof(spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer),
464 : cert_chain, cert_chain_size_internal);
465 : #else
466 20 : result = libspdm_hash_all(
467 : spdm_context->connection_info.algorithm.base_hash_algo,
468 : cert_chain, cert_chain_size_internal,
469 20 : spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_hash);
470 20 : if (!result) {
471 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
472 0 : goto done;
473 : }
474 :
475 40 : spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_hash_size =
476 20 : libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
477 :
478 20 : if (spdm_context->connection_info.algorithm.pqc_asym_algo != 0) {
479 0 : result = libspdm_get_pqc_leaf_cert_public_key_from_cert_chain(
480 : spdm_context->connection_info.algorithm.base_hash_algo,
481 : spdm_context->connection_info.algorithm.pqc_asym_algo,
482 : cert_chain, cert_chain_size_internal,
483 0 : &spdm_context->connection_info.peer_used_cert_chain[slot_id].leaf_cert_public_key);
484 : } else {
485 20 : result = libspdm_get_leaf_cert_public_key_from_cert_chain(
486 : spdm_context->connection_info.algorithm.base_hash_algo,
487 : spdm_context->connection_info.algorithm.base_asym_algo,
488 : cert_chain, cert_chain_size_internal,
489 20 : &spdm_context->connection_info.peer_used_cert_chain[slot_id].leaf_cert_public_key);
490 : }
491 20 : if (!result) {
492 0 : status = LIBSPDM_STATUS_INVALID_CERT;
493 0 : goto done;
494 : }
495 : #endif
496 :
497 20 : if (status != LIBSPDM_STATUS_VERIF_NO_AUTHORITY) {
498 18 : status = LIBSPDM_STATUS_SUCCESS;
499 : }
500 2 : done:
501 56 : return status;
502 : }
503 :
504 54 : libspdm_return_t libspdm_get_certificate(void *spdm_context, const uint32_t *session_id,
505 : uint8_t slot_id,
506 : size_t *cert_chain_size,
507 : void *cert_chain)
508 : {
509 54 : return libspdm_get_certificate_choose_length_ex(spdm_context, session_id, slot_id,
510 : 0, cert_chain_size, cert_chain,
511 : NULL, NULL);
512 : }
513 :
514 1 : libspdm_return_t libspdm_get_certificate_ex(void *spdm_context, const uint32_t *session_id,
515 : uint8_t slot_id,
516 : size_t *cert_chain_size,
517 : void *cert_chain,
518 : const void **trust_anchor,
519 : size_t *trust_anchor_size)
520 : {
521 1 : return libspdm_get_certificate_choose_length_ex(spdm_context, session_id, slot_id,
522 : 0, cert_chain_size, cert_chain,
523 : trust_anchor, trust_anchor_size);
524 : }
525 :
526 56 : libspdm_return_t libspdm_get_certificate_choose_length_ex(void *spdm_context,
527 : const uint32_t *session_id,
528 : uint8_t slot_id,
529 : uint32_t length,
530 : size_t *cert_chain_size,
531 : void *cert_chain,
532 : const void **trust_anchor,
533 : size_t *trust_anchor_size)
534 : {
535 : libspdm_context_t *context;
536 : size_t retry;
537 : uint64_t retry_delay_time;
538 : libspdm_return_t status;
539 :
540 56 : context = spdm_context;
541 56 : context->crypto_request = true;
542 56 : retry = context->retry_times;
543 56 : retry_delay_time = context->retry_delay_time;
544 : do {
545 57 : status = libspdm_try_get_large_certificate(context, session_id, slot_id, length,
546 : cert_chain_size, cert_chain, trust_anchor,
547 : trust_anchor_size);
548 57 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
549 55 : return status;
550 : }
551 :
552 2 : libspdm_sleep(retry_delay_time);
553 2 : } while (retry-- != 0);
554 :
555 1 : return status;
556 : }
557 :
558 : #endif /* LIBSPDM_SEND_GET_CERTIFICATE_SUPPORT */
|