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 : /* -=[Verify State Phase]=- */
127 57 : if (!libspdm_is_capabilities_flag_supported(
128 : spdm_context, true, 0,
129 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP)) {
130 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
131 : }
132 57 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
133 1 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
134 : }
135 :
136 56 : session_info = NULL;
137 56 : if (session_id != NULL) {
138 1 : session_info = libspdm_get_session_info_via_session_id(spdm_context, *session_id);
139 1 : if (session_info == NULL) {
140 0 : LIBSPDM_ASSERT(false);
141 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
142 : }
143 1 : session_state = libspdm_secured_message_get_session_state(
144 : session_info->secured_message_context);
145 1 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
146 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
147 : }
148 : }
149 :
150 56 : libspdm_reset_message_buffer_via_request_code(spdm_context, session_info, SPDM_GET_CERTIFICATE);
151 :
152 : chunk_enabled =
153 56 : libspdm_is_capabilities_flag_supported(spdm_context, true,
154 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP,
155 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP);
156 :
157 56 : remainder_length = 0;
158 56 : total_responder_cert_chain_buffer_length = 0;
159 56 : cert_chain_capacity = *cert_chain_size;
160 56 : cert_chain_size_internal = 0;
161 :
162 56 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
163 :
164 : do {
165 : /* -=[Construct Request Phase]=- */
166 1469 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
167 1469 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
168 0 : return status;
169 : }
170 1469 : LIBSPDM_ASSERT (message_size >= transport_header_size +
171 : spdm_context->local_context.capability.transport_tail_size);
172 1469 : spdm_request = (void *)(message + transport_header_size);
173 1469 : spdm_request_size = message_size - transport_header_size -
174 1469 : spdm_context->local_context.capability.transport_tail_size;
175 :
176 1469 : LIBSPDM_ASSERT (spdm_request_size >= req_msg_header_size);
177 1469 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
178 1469 : spdm_request->header.request_response_code = SPDM_GET_CERTIFICATE;
179 1469 : spdm_request->header.param1 = slot_id;
180 1469 : spdm_request->header.param2 = 0;
181 1469 : req_msg_offset = (uint32_t)cert_chain_size_internal;
182 1469 : if (req_msg_offset == 0) {
183 56 : req_msg_length = length;
184 : } else {
185 1413 : req_msg_length = LIBSPDM_MIN(length, remainder_length);
186 : }
187 1469 : if (use_large_cert_chain) {
188 0 : spdm_request->header.param1 |= SPDM_GET_CERTIFICATE_REQUEST_LARGE_CERT_CHAIN;
189 0 : spdm_request->offset = 0;
190 0 : spdm_request->length = 0;
191 0 : spdm_request->large_offset = req_msg_offset;
192 0 : spdm_request->large_length = req_msg_length;
193 : } else {
194 1469 : spdm_request->offset = (uint16_t)req_msg_offset;
195 1469 : spdm_request->length = (uint16_t)req_msg_length;
196 : }
197 1469 : spdm_request_size = req_msg_header_size;
198 1469 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "request (offset 0x%x, size 0x%x):\n",
199 : req_msg_offset,req_msg_length));
200 :
201 : /* -=[Send Request Phase]=- */
202 : status =
203 1469 : libspdm_send_spdm_request(spdm_context, session_id, spdm_request_size, spdm_request);
204 1469 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
205 1 : libspdm_release_sender_buffer (spdm_context);
206 1 : status = LIBSPDM_STATUS_SEND_FAIL;
207 1 : goto done;
208 : }
209 1468 : libspdm_release_sender_buffer (spdm_context);
210 1468 : spdm_request = (void *)spdm_context->last_spdm_request;
211 :
212 : /* -=[Receive Response Phase]=- */
213 1468 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
214 1468 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
215 0 : return status;
216 : }
217 1468 : LIBSPDM_ASSERT (message_size >= transport_header_size);
218 1468 : spdm_response = (void *)(message);
219 1468 : spdm_response_size = message_size;
220 :
221 1468 : status = libspdm_receive_spdm_response(spdm_context, session_id,
222 : &spdm_response_size,
223 : (void **)&spdm_response);
224 1468 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
225 0 : libspdm_release_receiver_buffer (spdm_context);
226 0 : status = LIBSPDM_STATUS_RECEIVE_FAIL;
227 0 : goto done;
228 : }
229 :
230 : /* -=[Validate Response Phase]=- */
231 1468 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
232 0 : libspdm_release_receiver_buffer (spdm_context);
233 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
234 0 : goto done;
235 : }
236 1468 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
237 24 : status = libspdm_handle_error_response_main(
238 : spdm_context, session_id,
239 : &spdm_response_size,
240 : (void **)&spdm_response, SPDM_GET_CERTIFICATE,
241 : SPDM_CERTIFICATE);
242 24 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
243 23 : libspdm_release_receiver_buffer (spdm_context);
244 23 : goto done;
245 : }
246 1444 : } else if (spdm_response->header.request_response_code != SPDM_CERTIFICATE) {
247 0 : libspdm_release_receiver_buffer (spdm_context);
248 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
249 0 : goto done;
250 : }
251 1445 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
252 0 : libspdm_release_receiver_buffer (spdm_context);
253 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
254 0 : goto done;
255 : }
256 1445 : if (spdm_response_size < rsp_msg_header_size) {
257 0 : libspdm_release_receiver_buffer (spdm_context);
258 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
259 0 : goto done;
260 : }
261 1445 : if (use_large_cert_chain) {
262 0 : if ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_LARGE_CERT_CHAIN) == 0) {
263 0 : libspdm_release_receiver_buffer (spdm_context);
264 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
265 0 : goto done;
266 : }
267 : } else {
268 1445 : if ((spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_14) &&
269 0 : ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_LARGE_CERT_CHAIN) != 0)) {
270 0 : libspdm_release_receiver_buffer (spdm_context);
271 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
272 0 : goto done;
273 : }
274 : }
275 1445 : if (use_large_cert_chain) {
276 0 : rsp_msg_portion_length = spdm_response->large_portion_length;
277 0 : rsp_msg_remainder_length = spdm_response->large_remainder_length;
278 : } else {
279 1445 : rsp_msg_portion_length = spdm_response->portion_length;
280 1445 : rsp_msg_remainder_length = spdm_response->remainder_length;
281 : }
282 :
283 1445 : if ((rsp_msg_portion_length > req_msg_length) ||
284 : (rsp_msg_portion_length == 0)) {
285 3 : libspdm_release_receiver_buffer (spdm_context);
286 3 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
287 3 : goto done;
288 : }
289 1442 : if ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_SLOT_ID_MASK) != slot_id) {
290 1 : libspdm_release_receiver_buffer (spdm_context);
291 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
292 1 : goto done;
293 : }
294 1441 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
295 10 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "cert_info - 0x%02x\n",
296 : spdm_response->header.param2));
297 10 : cert_model = spdm_response->header.param2 &
298 : SPDM_CERTIFICATE_RESPONSE_ATTRIBUTES_CERTIFICATE_INFO_MASK;
299 10 : if (spdm_context->connection_info.multi_key_conn_rsp) {
300 8 : if (cert_model > SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT) {
301 0 : libspdm_release_receiver_buffer (spdm_context);
302 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
303 0 : goto done;
304 : }
305 8 : if ((slot_id == 0) &&
306 : (cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT)) {
307 1 : libspdm_release_receiver_buffer (spdm_context);
308 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
309 1 : goto done;
310 : }
311 7 : if ((cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) &&
312 : (rsp_msg_portion_length != 0)) {
313 1 : libspdm_release_receiver_buffer (spdm_context);
314 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
315 1 : goto done;
316 : }
317 : } else {
318 2 : if (cert_model != SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) {
319 0 : libspdm_release_receiver_buffer (spdm_context);
320 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
321 0 : goto done;
322 : }
323 : }
324 8 : if (spdm_context->connection_info.peer_cert_info[slot_id] ==
325 : SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) {
326 5 : spdm_context->connection_info.peer_cert_info[slot_id] = cert_model;
327 3 : } else if (spdm_context->connection_info.peer_cert_info[slot_id] != cert_model) {
328 0 : libspdm_release_receiver_buffer (spdm_context);
329 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
330 0 : goto done;
331 : }
332 : }
333 1439 : if (spdm_response_size < rsp_msg_header_size +
334 : rsp_msg_portion_length) {
335 0 : libspdm_release_receiver_buffer (spdm_context);
336 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
337 0 : goto done;
338 : }
339 1439 : if (rsp_msg_portion_length > max_cert_chain_size - req_msg_offset) {
340 0 : libspdm_release_receiver_buffer (spdm_context);
341 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
342 0 : goto done;
343 : }
344 1439 : if (rsp_msg_remainder_length > max_cert_chain_size - req_msg_offset -
345 : rsp_msg_portion_length) {
346 0 : libspdm_release_receiver_buffer (spdm_context);
347 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
348 0 : goto done;
349 : }
350 1439 : if (req_msg_offset == 0) {
351 27 : total_responder_cert_chain_buffer_length = rsp_msg_portion_length +
352 : rsp_msg_remainder_length;
353 27 : if (total_responder_cert_chain_buffer_length > cert_chain_capacity) {
354 1 : libspdm_release_receiver_buffer (spdm_context);
355 1 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
356 1 : goto done;
357 : }
358 1412 : } else if (req_msg_offset + rsp_msg_portion_length +
359 : rsp_msg_remainder_length != total_responder_cert_chain_buffer_length) {
360 0 : libspdm_release_receiver_buffer (spdm_context);
361 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
362 0 : goto done;
363 : }
364 1438 : if (chunk_enabled && (req_msg_offset == 0) && (req_msg_length == max_cert_chain_size) &&
365 : (rsp_msg_remainder_length != 0)) {
366 0 : libspdm_release_receiver_buffer (spdm_context);
367 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
368 0 : goto done;
369 : }
370 :
371 : /* -=[Process Response Phase]=- */
372 1438 : remainder_length = rsp_msg_remainder_length;
373 1438 : spdm_response_size = rsp_msg_header_size + rsp_msg_portion_length;
374 :
375 1438 : if (session_id == NULL) {
376 1436 : status = libspdm_append_message_b(spdm_context, spdm_request, spdm_request_size);
377 1436 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
378 0 : libspdm_release_receiver_buffer (spdm_context);
379 0 : goto done;
380 : }
381 1436 : status = libspdm_append_message_b(spdm_context, spdm_response, spdm_response_size);
382 1436 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
383 0 : libspdm_release_receiver_buffer (spdm_context);
384 0 : goto done;
385 : }
386 : }
387 :
388 1438 : if (cert_chain_size_internal + rsp_msg_portion_length > cert_chain_capacity) {
389 0 : libspdm_release_receiver_buffer (spdm_context);
390 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "cert_chain_buffer full\n"));
391 0 : status = LIBSPDM_STATUS_BUFFER_FULL;
392 0 : goto done;
393 : }
394 :
395 1438 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Certificate (offset 0x%x, size 0x%x):\n",
396 : req_msg_offset, rsp_msg_portion_length));
397 1438 : LIBSPDM_INTERNAL_DUMP_HEX((uint8_t *)spdm_response + rsp_msg_header_size,
398 : rsp_msg_portion_length);
399 :
400 1438 : libspdm_copy_mem((uint8_t *)cert_chain + cert_chain_size_internal,
401 : cert_chain_capacity - cert_chain_size_internal,
402 1438 : (uint8_t *)spdm_response + rsp_msg_header_size,
403 : rsp_msg_portion_length);
404 :
405 1438 : cert_chain_size_internal += rsp_msg_portion_length;
406 :
407 1438 : if (spdm_context->connection_info.connection_state <
408 : LIBSPDM_CONNECTION_STATE_AFTER_CERTIFICATE) {
409 22 : spdm_context->connection_info.connection_state =
410 : LIBSPDM_CONNECTION_STATE_AFTER_CERTIFICATE;
411 : }
412 :
413 : /* -=[Log Message Phase]=- */
414 : #if LIBSPDM_ENABLE_MSG_LOG
415 1438 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
416 : #endif /* LIBSPDM_ENABLE_MSG_LOG */
417 :
418 1438 : libspdm_release_receiver_buffer (spdm_context);
419 1438 : } while (remainder_length != 0);
420 :
421 25 : *cert_chain_size = cert_chain_size_internal;
422 25 : LIBSPDM_ASSERT(*cert_chain_size <= SPDM_MAX_CERTIFICATE_CHAIN_SIZE_14);
423 :
424 25 : if (spdm_context->local_context.verify_peer_spdm_cert_chain != NULL) {
425 0 : result = spdm_context->local_context.verify_peer_spdm_cert_chain (
426 : spdm_context, slot_id, cert_chain_size_internal, cert_chain,
427 : trust_anchor, trust_anchor_size);
428 0 : if (!result) {
429 0 : status = LIBSPDM_STATUS_VERIF_FAIL;
430 0 : goto done;
431 : }
432 : } else {
433 25 : result = libspdm_verify_peer_cert_chain_buffer_integrity(
434 : spdm_context, cert_chain, cert_chain_size_internal);
435 25 : if (!result) {
436 5 : status = LIBSPDM_STATUS_VERIF_FAIL;
437 5 : goto done;
438 : }
439 :
440 : /*verify peer cert chain authority*/
441 20 : result = libspdm_verify_peer_cert_chain_buffer_authority(
442 : spdm_context, cert_chain,cert_chain_size_internal,
443 : trust_anchor, trust_anchor_size);
444 20 : if (!result) {
445 2 : status = LIBSPDM_STATUS_VERIF_NO_AUTHORITY;
446 : }
447 : }
448 :
449 20 : spdm_context->connection_info.peer_used_cert_chain_slot_id = slot_id;
450 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
451 : spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_size =
452 : cert_chain_size_internal;
453 : libspdm_copy_mem(spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer,
454 : sizeof(spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer),
455 : cert_chain, cert_chain_size_internal);
456 : #else
457 20 : result = libspdm_hash_all(
458 : spdm_context->connection_info.algorithm.base_hash_algo,
459 : cert_chain, cert_chain_size_internal,
460 20 : spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_hash);
461 20 : if (!result) {
462 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
463 0 : goto done;
464 : }
465 :
466 40 : spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_hash_size =
467 20 : libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
468 :
469 20 : if (spdm_context->connection_info.algorithm.pqc_asym_algo != 0) {
470 0 : result = libspdm_get_pqc_leaf_cert_public_key_from_cert_chain(
471 : spdm_context->connection_info.algorithm.base_hash_algo,
472 : spdm_context->connection_info.algorithm.pqc_asym_algo,
473 : cert_chain, cert_chain_size_internal,
474 0 : &spdm_context->connection_info.peer_used_cert_chain[slot_id].leaf_cert_public_key);
475 : } else {
476 20 : result = libspdm_get_leaf_cert_public_key_from_cert_chain(
477 : spdm_context->connection_info.algorithm.base_hash_algo,
478 : spdm_context->connection_info.algorithm.base_asym_algo,
479 : cert_chain, cert_chain_size_internal,
480 20 : &spdm_context->connection_info.peer_used_cert_chain[slot_id].leaf_cert_public_key);
481 : }
482 20 : if (!result) {
483 0 : status = LIBSPDM_STATUS_INVALID_CERT;
484 0 : goto done;
485 : }
486 : #endif
487 :
488 20 : if (status != LIBSPDM_STATUS_VERIF_NO_AUTHORITY) {
489 18 : status = LIBSPDM_STATUS_SUCCESS;
490 : }
491 2 : done:
492 56 : return status;
493 : }
494 :
495 57 : static libspdm_return_t libspdm_try_get_certificate(libspdm_context_t *spdm_context,
496 : const uint32_t *session_id,
497 : uint8_t slot_id,
498 : uint16_t length,
499 : size_t *cert_chain_size,
500 : void *cert_chain,
501 : const void **trust_anchor,
502 : size_t *trust_anchor_size)
503 : {
504 57 : return libspdm_try_get_large_certificate(spdm_context, session_id, slot_id, length,
505 : cert_chain_size, cert_chain,
506 : trust_anchor, trust_anchor_size);
507 : }
508 :
509 54 : libspdm_return_t libspdm_get_certificate(void *spdm_context, const uint32_t *session_id,
510 : uint8_t slot_id,
511 : size_t *cert_chain_size,
512 : void *cert_chain)
513 : {
514 54 : return libspdm_get_certificate_choose_length(spdm_context, session_id, slot_id,
515 : LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN,
516 : cert_chain_size, cert_chain);
517 : }
518 :
519 1 : libspdm_return_t libspdm_get_certificate_ex(void *spdm_context, const uint32_t *session_id,
520 : uint8_t slot_id,
521 : size_t *cert_chain_size,
522 : void *cert_chain,
523 : const void **trust_anchor,
524 : size_t *trust_anchor_size)
525 : {
526 1 : return libspdm_get_certificate_choose_length_ex(spdm_context, session_id, slot_id,
527 : LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN,
528 : cert_chain_size, cert_chain,
529 : trust_anchor, trust_anchor_size);
530 : }
531 :
532 55 : libspdm_return_t libspdm_get_certificate_choose_length(void *spdm_context,
533 : const uint32_t *session_id,
534 : uint8_t slot_id,
535 : uint16_t length,
536 : size_t *cert_chain_size,
537 : void *cert_chain)
538 : {
539 : libspdm_context_t *context;
540 : size_t retry;
541 : uint64_t retry_delay_time;
542 : libspdm_return_t status;
543 :
544 55 : context = spdm_context;
545 55 : context->crypto_request = true;
546 55 : retry = context->retry_times;
547 55 : retry_delay_time = context->retry_delay_time;
548 : do {
549 56 : status = libspdm_try_get_certificate(context, session_id, slot_id, length,
550 : cert_chain_size, cert_chain, NULL, NULL);
551 56 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
552 54 : return status;
553 : }
554 :
555 2 : libspdm_sleep(retry_delay_time);
556 2 : } while (retry-- != 0);
557 :
558 1 : return status;
559 : }
560 :
561 1 : libspdm_return_t libspdm_get_certificate_choose_length_ex(void *spdm_context,
562 : const uint32_t *session_id,
563 : uint8_t slot_id,
564 : uint32_t length,
565 : size_t *cert_chain_size,
566 : void *cert_chain,
567 : const void **trust_anchor,
568 : size_t *trust_anchor_size)
569 : {
570 : libspdm_context_t *context;
571 : size_t retry;
572 : uint64_t retry_delay_time;
573 : libspdm_return_t status;
574 :
575 : /* -=[Check Parameters Phase]=- */
576 1 : LIBSPDM_ASSERT(length <= SPDM_MAX_CERTIFICATE_CHAIN_SIZE);
577 :
578 1 : context = spdm_context;
579 1 : context->crypto_request = true;
580 1 : retry = context->retry_times;
581 1 : retry_delay_time = context->retry_delay_time;
582 : do {
583 1 : status = libspdm_try_get_certificate(context, session_id, slot_id, (uint16_t)length,
584 : cert_chain_size, cert_chain, trust_anchor,
585 : trust_anchor_size);
586 1 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
587 1 : return status;
588 : }
589 :
590 0 : libspdm_sleep(retry_delay_time);
591 0 : } while (retry-- != 0);
592 :
593 0 : return status;
594 : }
595 :
596 : #endif /* LIBSPDM_SEND_GET_CERTIFICATE_SUPPORT */
|