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_RESPOND_IF_READY_SUPPORT
10 : /**
11 : * This function sends RESPOND_IF_READY and receives an expected SPDM response.
12 : *
13 : * @param spdm_context A pointer to the SPDM context.
14 : * @param response_size The size of the response.
15 : * On input, it means the size in bytes of response data buffer.
16 : * On output, it means the size in bytes of copied response data buffer if RETURN_SUCCESS is returned.
17 : * @param response The SPDM response message.
18 : * @param expected_response_code Indicate the expected response code.
19 : *
20 : * @retval RETURN_SUCCESS The RESPOND_IF_READY is sent and an expected SPDM response is received.
21 : * @retval RETURN_DEVICE_ERROR A device error occurs when communicates with the device.
22 : **/
23 29 : static libspdm_return_t libspdm_requester_respond_if_ready(libspdm_context_t *spdm_context,
24 : const uint32_t *session_id,
25 : size_t *response_size,
26 : void **response,
27 : uint8_t expected_response_code)
28 : {
29 : libspdm_return_t status;
30 : spdm_response_if_ready_request_t *spdm_request;
31 : size_t spdm_request_size;
32 : spdm_message_header_t *spdm_response;
33 : uint8_t *message;
34 : size_t message_size;
35 : size_t transport_header_size;
36 :
37 : /* the response might be in response buffer in normal SPDM message
38 : * or it is in scratch buffer in case of secure SPDM message
39 : * the response buffer is in acquired state, so we release it*/
40 29 : libspdm_release_receiver_buffer (spdm_context);
41 :
42 : /* now we can get sender buffer */
43 29 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
44 29 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
45 29 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
46 0 : return status;
47 : }
48 29 : LIBSPDM_ASSERT (message_size >= transport_header_size +
49 : spdm_context->local_context.capability.transport_tail_size);
50 29 : spdm_request = (void *)(message + transport_header_size);
51 29 : spdm_request_size = message_size - transport_header_size -
52 29 : spdm_context->local_context.capability.transport_tail_size;
53 :
54 29 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_response_if_ready_request_t));
55 29 : spdm_context->crypto_request = true;
56 29 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
57 29 : spdm_request->header.request_response_code = SPDM_RESPOND_IF_READY;
58 29 : spdm_request->header.param1 = spdm_context->error_data.request_code;
59 29 : spdm_request->header.param2 = spdm_context->error_data.token;
60 29 : spdm_request_size = sizeof(spdm_response_if_ready_request_t);
61 29 : status = libspdm_send_spdm_request(spdm_context, session_id, spdm_request_size, spdm_request);
62 29 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
63 0 : libspdm_release_sender_buffer (spdm_context);
64 : /* need acquire response buffer, so that the caller can release it */
65 0 : status = libspdm_acquire_receiver_buffer (spdm_context, response_size, response);
66 0 : return status;
67 : }
68 29 : libspdm_release_sender_buffer (spdm_context);
69 29 : spdm_request = (void *)spdm_context->last_spdm_request;
70 :
71 : /* receive
72 : * do not release response buffer in case of error, because caller will release it*/
73 :
74 29 : status = libspdm_acquire_receiver_buffer (spdm_context, response_size, response);
75 29 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
76 0 : return status;
77 : }
78 29 : LIBSPDM_ASSERT (*response_size >= transport_header_size);
79 :
80 29 : status = libspdm_receive_spdm_response(spdm_context, session_id,
81 : response_size, response);
82 29 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
83 0 : return status;
84 : }
85 29 : spdm_response = (void *)(*response);
86 29 : if (*response_size < sizeof(spdm_message_header_t)) {
87 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
88 : }
89 29 : if (spdm_response->spdm_version != spdm_request->header.spdm_version) {
90 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
91 : }
92 29 : if (spdm_response->request_response_code == SPDM_ERROR) {
93 16 : status = libspdm_handle_simple_error_response(spdm_context, spdm_response->param1);
94 16 : return status;
95 : }
96 13 : if (spdm_response->request_response_code != expected_response_code) {
97 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
98 : }
99 :
100 13 : return LIBSPDM_STATUS_SUCCESS;
101 : }
102 : #endif /* LIBSPDM_RESPOND_IF_READY_SUPPORT */
103 :
104 422 : libspdm_return_t libspdm_handle_simple_error_response(libspdm_context_t *spdm_context,
105 : uint8_t error_code)
106 : {
107 : spdm_set_certificate_request_t *last_spdm_request;
108 :
109 422 : if (error_code == SPDM_ERROR_CODE_RESPONSE_NOT_READY) {
110 18 : return LIBSPDM_STATUS_NOT_READY_PEER;
111 : }
112 :
113 404 : if (error_code == SPDM_ERROR_CODE_BUSY) {
114 44 : return LIBSPDM_STATUS_BUSY_PEER;
115 : }
116 :
117 360 : last_spdm_request = (void *)spdm_context->last_spdm_request;
118 360 : if ((last_spdm_request->header.request_response_code == SPDM_SET_CERTIFICATE) ||
119 359 : (last_spdm_request->header.request_response_code == SPDM_GET_CSR)) {
120 :
121 4 : if (error_code == SPDM_ERROR_CODE_RESET_REQUIRED) {
122 4 : if ((libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_13) &&
123 2 : !libspdm_is_capabilities_flag_supported(
124 : spdm_context, true, 0,
125 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_INSTALL_RESET_CAP)) {
126 1 : return LIBSPDM_STATUS_ERROR_PEER;
127 : }
128 : /* CERT_INSTALL_RESET_CAP for a 1.2 Responder is not checked because it was not defined
129 : * in SPDM 1.2.0. */
130 3 : return LIBSPDM_STATUS_RESET_REQUIRED_PEER;
131 : }
132 : }
133 :
134 356 : if (error_code == SPDM_ERROR_CODE_REQUEST_RESYNCH) {
135 19 : spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_NOT_STARTED;
136 19 : return LIBSPDM_STATUS_RESYNCH_PEER;
137 : }
138 :
139 337 : return LIBSPDM_STATUS_ERROR_PEER;
140 : }
141 :
142 : #if LIBSPDM_RESPOND_IF_READY_SUPPORT
143 : /**
144 : * This function handles RESPONSE_NOT_READY error code.
145 : *
146 : * @param spdm_context A pointer to the SPDM context.
147 : * @param response_size The size of the response.
148 : * On input, it means the size in bytes of response data buffer.
149 : * On output, it means the size in bytes of copied response data buffer if RETURN_SUCCESS is returned.
150 : * @param response The SPDM response message.
151 : * @param original_request_code Indicate the original request code.
152 : * @param expected_response_code Indicate the expected response code.
153 : *
154 : * @retval RETURN_SUCCESS The RESPOND_IF_READY is sent and an expected SPDM response is received.
155 : * @retval RETURN_DEVICE_ERROR A device error occurs when communicates with the device.
156 : **/
157 29 : static libspdm_return_t libspdm_handle_response_not_ready(libspdm_context_t *spdm_context,
158 : const uint32_t *session_id,
159 : size_t *response_size,
160 : void **response,
161 : uint8_t original_request_code,
162 : uint8_t expected_response_code)
163 : {
164 : spdm_error_response_t *spdm_response;
165 : spdm_error_data_response_not_ready_t *extend_error_data;
166 :
167 29 : if(*response_size < sizeof(spdm_error_response_t) +
168 : sizeof(spdm_error_data_response_not_ready_t)) {
169 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
170 : }
171 :
172 29 : spdm_response = *response;
173 29 : extend_error_data = (spdm_error_data_response_not_ready_t *)(spdm_response + 1);
174 29 : LIBSPDM_ASSERT(spdm_response->header.request_response_code == SPDM_ERROR);
175 29 : LIBSPDM_ASSERT(spdm_response->header.param1 == SPDM_ERROR_CODE_RESPONSE_NOT_READY);
176 :
177 29 : if (extend_error_data->request_code != original_request_code) {
178 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
179 : }
180 29 : if (extend_error_data->rd_tm <= 1) {
181 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
182 : }
183 29 : if (extend_error_data->rd_exponent > LIBSPDM_MAX_RDT_EXPONENT) {
184 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
185 : }
186 :
187 29 : spdm_context->error_data.rd_exponent = extend_error_data->rd_exponent;
188 29 : spdm_context->error_data.request_code = extend_error_data->request_code;
189 29 : spdm_context->error_data.token = extend_error_data->token;
190 29 : spdm_context->error_data.rd_tm = extend_error_data->rd_tm;
191 :
192 29 : libspdm_sleep((uint64_t)1 << extend_error_data->rd_exponent);
193 :
194 29 : return libspdm_requester_respond_if_ready(spdm_context, session_id,
195 : response_size, response,
196 : expected_response_code);
197 : }
198 : #endif /* LIBSPDM_RESPOND_IF_READY_SUPPORT */
199 :
200 : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
201 7 : libspdm_return_t libspdm_handle_error_large_response(
202 : libspdm_context_t *spdm_context,
203 : const uint32_t *session_id,
204 : size_t *inout_response_size,
205 : void *inout_response,
206 : size_t response_capacity)
207 : {
208 : libspdm_return_t status;
209 : uint8_t chunk_handle;
210 : spdm_error_response_t* error_response;
211 : spdm_error_data_large_response_t* extend_error_data;
212 :
213 : spdm_chunk_get_request_t* spdm_request;
214 : size_t spdm_request_size;
215 : spdm_chunk_response_response_t* spdm_response;
216 : uint8_t* message;
217 : size_t message_size;
218 : size_t transport_header_size;
219 :
220 : uint8_t* scratch_buffer;
221 : size_t scratch_buffer_size;
222 : uint16_t chunk_seq_no;
223 : uint8_t* chunk_ptr;
224 : uint8_t* large_response;
225 : size_t large_response_capacity;
226 : size_t large_response_size;
227 : size_t large_response_size_so_far;
228 : uint64_t max_chunk_data_transfer_size;
229 :
230 7 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_12) {
231 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
232 : }
233 :
234 : /* Fail if requester or responder does not support chunk cap */
235 7 : if (!libspdm_is_capabilities_flag_supported(
236 : spdm_context, true,
237 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP,
238 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP)) {
239 0 : return LIBSPDM_STATUS_ERROR_PEER;
240 : }
241 :
242 7 : if (*inout_response_size < sizeof(spdm_error_response_t) +
243 : sizeof(spdm_error_data_large_response_t)) {
244 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
245 : }
246 :
247 7 : error_response = inout_response;
248 7 : extend_error_data =
249 : (spdm_error_data_large_response_t*)(error_response + 1);
250 7 : chunk_handle = extend_error_data->handle;
251 :
252 : /* now we can get sender buffer */
253 7 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
254 :
255 7 : libspdm_get_scratch_buffer(spdm_context, (void**)&scratch_buffer, &scratch_buffer_size);
256 :
257 : /* The first section of the scratch
258 : * buffer may be used for other purposes. Use only after that section. */
259 7 : large_response = scratch_buffer + libspdm_get_scratch_buffer_large_message_offset(spdm_context);
260 7 : large_response_capacity = libspdm_get_scratch_buffer_large_message_capacity(spdm_context);
261 :
262 : /* Temporary send/receive buffers for chunking are in the scratch space */
263 7 : message = scratch_buffer + libspdm_get_scratch_buffer_sender_receiver_offset(spdm_context);
264 7 : message_size = libspdm_get_scratch_buffer_sender_receiver_capacity(spdm_context);
265 :
266 7 : max_chunk_data_transfer_size =
267 7 : ((size_t) spdm_context->local_context.capability.data_transfer_size
268 7 : - sizeof(spdm_chunk_response_response_t)) * 65536 - sizeof(uint32_t);
269 :
270 7 : libspdm_zero_mem(large_response, large_response_capacity);
271 7 : large_response_size = 0;
272 7 : large_response_size_so_far = 0;
273 7 : chunk_seq_no = 0;
274 :
275 : do {
276 65606 : LIBSPDM_ASSERT(message_size >= transport_header_size);
277 65606 : spdm_request = (spdm_chunk_get_request_t*)(void*) (message + transport_header_size);
278 65606 : spdm_request_size = message_size - transport_header_size;
279 :
280 65606 : LIBSPDM_ASSERT(spdm_request_size >= sizeof(spdm_chunk_get_request_t));
281 65606 : spdm_request->header.spdm_version = libspdm_get_connection_version(spdm_context);
282 65606 : spdm_request->header.request_response_code = SPDM_CHUNK_GET;
283 65606 : spdm_request->header.param1 = 0;
284 65606 : spdm_request->header.param2 = chunk_handle;
285 65606 : spdm_request->chunk_seq_no = chunk_seq_no;
286 65606 : spdm_request_size = sizeof(spdm_chunk_get_request_t);
287 :
288 65606 : if (chunk_seq_no == 0 && large_response_size_so_far != 0) {
289 : /* chunk_seq_no wrapped */
290 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
291 2 : break;
292 : }
293 :
294 65605 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
295 : "CHUNK_GET Handle %d SeqNo %d\n", chunk_handle, chunk_seq_no));
296 :
297 65605 : status = libspdm_send_spdm_request(spdm_context, session_id,
298 : spdm_request_size, spdm_request);
299 :
300 65605 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
301 0 : break;
302 : }
303 :
304 65605 : libspdm_zero_mem(message, message_size);
305 65605 : void* response = message;
306 65605 : size_t response_size = message_size;
307 :
308 65605 : status = libspdm_receive_spdm_response(
309 : spdm_context, session_id,
310 : &response_size, &response);
311 :
312 65605 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
313 0 : break;
314 : }
315 65605 : spdm_response = (void*) (response);
316 65605 : if (spdm_response->header.spdm_version != libspdm_get_connection_version(spdm_context)) {
317 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
318 0 : break;
319 : }
320 65605 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
321 0 : status = libspdm_handle_simple_error_response(spdm_context,
322 0 : spdm_response->header.param1);
323 0 : break;
324 : }
325 65605 : if (spdm_response->header.request_response_code != SPDM_CHUNK_RESPONSE) {
326 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
327 0 : break;
328 : }
329 65605 : if (chunk_seq_no == 0) {
330 :
331 7 : if (response_size
332 7 : < (sizeof(spdm_chunk_response_response_t) + sizeof(uint32_t))) {
333 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
334 0 : break;
335 : }
336 7 : if (response_size < SPDM_MIN_DATA_TRANSFER_SIZE_VERSION_12) {
337 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
338 0 : break;
339 : }
340 :
341 7 : if (spdm_response->chunk_size
342 : < SPDM_MIN_DATA_TRANSFER_SIZE_VERSION_12
343 : - sizeof(spdm_chunk_response_response_t)
344 : - sizeof(uint32_t)) {
345 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
346 0 : break;
347 : }
348 :
349 7 : large_response_size = *(uint32_t*) (spdm_response + 1);
350 7 : chunk_ptr = (uint8_t*) (((uint32_t*) (spdm_response + 1)) + 1);
351 :
352 7 : if (spdm_response->chunk_size > large_response_size) {
353 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
354 0 : break;
355 : }
356 7 : if (large_response_size > spdm_context->local_context.capability.max_spdm_msg_size) {
357 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
358 0 : break;
359 : }
360 7 : if (large_response_size > max_chunk_data_transfer_size) {
361 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
362 1 : break;
363 : }
364 6 : if (large_response_size <= SPDM_MIN_DATA_TRANSFER_SIZE_VERSION_12) {
365 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
366 0 : break;
367 : }
368 : } else {
369 65598 : if (response_size < sizeof(spdm_chunk_response_response_t)) {
370 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
371 0 : break;
372 : }
373 65598 : if (spdm_response->chunk_size + large_response_size_so_far > large_response_size) {
374 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
375 0 : break;
376 : }
377 :
378 65598 : if (!(spdm_response->header.param1 & SPDM_CHUNK_GET_RESPONSE_ATTRIBUTE_LAST_CHUNK)) {
379 65593 : if (response_size < SPDM_MIN_DATA_TRANSFER_SIZE_VERSION_12) {
380 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
381 0 : break;
382 : }
383 65593 : if (spdm_response->chunk_size
384 : < SPDM_MIN_DATA_TRANSFER_SIZE_VERSION_12
385 : - sizeof(spdm_chunk_response_response_t)) {
386 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
387 0 : break;
388 : }
389 : }
390 :
391 65598 : chunk_ptr = (uint8_t*) (spdm_response + 1);
392 : }
393 :
394 65604 : if (spdm_response->chunk_seq_no != chunk_seq_no) {
395 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
396 0 : break;
397 : }
398 :
399 65604 : libspdm_copy_mem(large_response + large_response_size_so_far,
400 : large_response_size - large_response_size_so_far,
401 65604 : chunk_ptr, spdm_response->chunk_size);
402 :
403 65604 : large_response_size_so_far += spdm_response->chunk_size;
404 :
405 65604 : chunk_seq_no++;
406 :
407 65604 : } while (LIBSPDM_STATUS_IS_SUCCESS(status)
408 65604 : && large_response_size_so_far < large_response_size
409 131203 : && !(spdm_response->header.param1 & SPDM_CHUNK_GET_RESPONSE_ATTRIBUTE_LAST_CHUNK));
410 :
411 :
412 7 : if (LIBSPDM_STATUS_IS_SUCCESS(status)) {
413 5 : if (large_response_size_so_far != large_response_size) {
414 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
415 5 : } else if (large_response_size <= response_capacity) {
416 5 : libspdm_copy_mem(inout_response, response_capacity,
417 : large_response, large_response_size);
418 5 : *inout_response_size = large_response_size;
419 :
420 5 : LIBSPDM_INTERNAL_DUMP_HEX(large_response, large_response_size);
421 : }
422 : }
423 :
424 7 : return status;
425 : }
426 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
427 :
428 389 : libspdm_return_t libspdm_handle_error_response_main(
429 : libspdm_context_t *spdm_context, const uint32_t *session_id,
430 : size_t *response_size, void **response,
431 : uint8_t original_request_code, uint8_t expected_response_code)
432 : {
433 : spdm_message_header_t *spdm_response;
434 :
435 389 : spdm_response = *response;
436 389 : LIBSPDM_ASSERT(spdm_response->request_response_code == SPDM_ERROR);
437 :
438 389 : if ((spdm_response->param1 == SPDM_ERROR_CODE_DECRYPT_ERROR) && (session_id != NULL)) {
439 5 : libspdm_free_session_id(spdm_context, *session_id);
440 5 : return LIBSPDM_STATUS_SESSION_MSG_ERROR;
441 384 : } else if(spdm_response->param1 == SPDM_ERROR_CODE_RESPONSE_NOT_READY) {
442 : #if LIBSPDM_RESPOND_IF_READY_SUPPORT
443 29 : return libspdm_handle_response_not_ready(spdm_context, session_id,
444 : response_size, response,
445 : original_request_code,
446 : expected_response_code);
447 : #else
448 : return LIBSPDM_STATUS_NOT_READY_PEER;
449 : #endif /* LIBSPDM_RESPOND_IF_READY_SUPPORT */
450 : } else {
451 355 : return libspdm_handle_simple_error_response(spdm_context, spdm_response->param1);
452 : }
453 : }
|