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