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_responder_lib.h"
8 : #include "internal/libspdm_secured_message_lib.h"
9 :
10 : /**
11 : * Return the GET_SPDM_RESPONSE function via request code.
12 : *
13 : * @param request_code The SPDM request code.
14 : *
15 : * @return GET_SPDM_RESPONSE function according to the request code.
16 : **/
17 14 : libspdm_get_spdm_response_func libspdm_get_response_func_via_request_code(uint8_t request_code)
18 : {
19 : size_t index;
20 :
21 : typedef struct {
22 : uint8_t request_response_code;
23 : libspdm_get_spdm_response_func get_response_func;
24 : } libspdm_get_response_struct_t;
25 :
26 14 : libspdm_get_response_struct_t get_response_struct[] = {
27 : { SPDM_GET_VERSION, libspdm_get_response_version },
28 : { SPDM_GET_CAPABILITIES, libspdm_get_response_capabilities },
29 : { SPDM_NEGOTIATE_ALGORITHMS, libspdm_get_response_algorithms },
30 :
31 : #if LIBSPDM_ENABLE_CAPABILITY_CERT_CAP
32 : { SPDM_GET_DIGESTS, libspdm_get_response_digests },
33 : { SPDM_GET_CERTIFICATE, libspdm_get_response_certificate },
34 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CERT_CAP */
35 :
36 : #if LIBSPDM_ENABLE_CAPABILITY_CHAL_CAP
37 : { SPDM_CHALLENGE, libspdm_get_response_challenge_auth },
38 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHAL_CAP*/
39 :
40 : #if LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP
41 : { SPDM_GET_MEASUREMENTS, libspdm_get_response_measurements },
42 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP*/
43 :
44 : #if LIBSPDM_ENABLE_CAPABILITY_MEL_CAP
45 : { SPDM_GET_MEASUREMENT_EXTENSION_LOG, libspdm_get_response_measurement_extension_log },
46 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MEL_CAP */
47 :
48 : #if LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP
49 : { SPDM_KEY_EXCHANGE, libspdm_get_response_key_exchange },
50 : #endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP*/
51 :
52 : #if LIBSPDM_ENABLE_CAPABILITY_PSK_CAP
53 : { SPDM_PSK_EXCHANGE, libspdm_get_response_psk_exchange },
54 : #endif /* LIBSPDM_ENABLE_CAPABILITY_PSK_CAP*/
55 :
56 : #if LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP
57 : { SPDM_GET_ENCAPSULATED_REQUEST, libspdm_get_response_encapsulated_request },
58 : { SPDM_DELIVER_ENCAPSULATED_RESPONSE, libspdm_get_response_encapsulated_response_ack },
59 : #endif /* LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP */
60 :
61 : #if LIBSPDM_RESPOND_IF_READY_SUPPORT
62 : { SPDM_RESPOND_IF_READY, libspdm_get_response_respond_if_ready },
63 : #endif /* LIBSPDM_RESPOND_IF_READY_SUPPORT */
64 :
65 : #if LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP
66 : { SPDM_FINISH, libspdm_get_response_finish },
67 : #endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP*/
68 :
69 : #if LIBSPDM_ENABLE_CAPABILITY_PSK_CAP
70 : { SPDM_PSK_FINISH, libspdm_get_response_psk_finish },
71 : #endif /* LIBSPDM_ENABLE_CAPABILITY_PSK_CAP*/
72 :
73 : #if (LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP) || (LIBSPDM_ENABLE_CAPABILITY_PSK_CAP)
74 : { SPDM_END_SESSION, libspdm_get_response_end_session },
75 : { SPDM_HEARTBEAT, libspdm_get_response_heartbeat },
76 : { SPDM_KEY_UPDATE, libspdm_get_response_key_update },
77 : #endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP || LIBSPDM_ENABLE_CAPABILITY_PSK_CAP*/
78 :
79 : #if LIBSPDM_ENABLE_CAPABILITY_ENDPOINT_INFO_CAP
80 : { SPDM_GET_ENDPOINT_INFO, libspdm_get_response_endpoint_info },
81 : #endif /*LIBSPDM_ENABLE_CAPABILITY_ENDPOINT_INFO_CAP*/
82 :
83 : #if LIBSPDM_ENABLE_CAPABILITY_CSR_CAP
84 : { SPDM_GET_CSR, libspdm_get_response_csr },
85 : #endif /*LIBSPDM_ENABLE_CAPABILITY_CSR_CAP*/
86 :
87 : #if LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP
88 : { SPDM_SET_CERTIFICATE, libspdm_get_response_set_certificate },
89 : #endif /*LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP*/
90 :
91 : #if LIBSPDM_ENABLE_CAPABILITY_GET_KEY_PAIR_INFO_CAP
92 : { SPDM_GET_KEY_PAIR_INFO, libspdm_get_response_key_pair_info },
93 : #endif /*LIBSPDM_ENABLE_CAPABILITY_GET_KEY_PAIR_INFO_CAP*/
94 :
95 : #if LIBSPDM_ENABLE_CAPABILITY_SET_KEY_PAIR_INFO_CAP
96 : { SPDM_SET_KEY_PAIR_INFO, libspdm_get_response_set_key_pair_info_ack },
97 : #endif /*LIBSPDM_ENABLE_CAPABILITY_SET_KEY_PAIR_INFO_CAP*/
98 :
99 : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
100 : { SPDM_CHUNK_GET, libspdm_get_response_chunk_get},
101 : { SPDM_CHUNK_SEND, libspdm_get_response_chunk_send},
102 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
103 :
104 : #if LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP
105 : { SPDM_GET_SUPPORTED_EVENT_TYPES, libspdm_get_response_supported_event_types },
106 : { SPDM_SUBSCRIBE_EVENT_TYPES, libspdm_get_response_subscribe_event_types_ack },
107 : #endif /* LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP */
108 :
109 : #if LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES
110 : { SPDM_VENDOR_DEFINED_REQUEST, libspdm_get_vendor_defined_response },
111 : #endif /*LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES*/
112 : };
113 :
114 147 : for (index = 0; index < LIBSPDM_ARRAY_SIZE(get_response_struct); index++) {
115 147 : if (request_code == get_response_struct[index].request_response_code) {
116 14 : return get_response_struct[index].get_response_func;
117 : }
118 : }
119 0 : return NULL;
120 : }
121 :
122 : /**
123 : * Return the GET_SPDM_RESPONSE function via last request.
124 : *
125 : * @param spdm_context The SPDM context for the device.
126 : *
127 : * @return GET_SPDM_RESPONSE function according to the last request.
128 : **/
129 4 : static libspdm_get_spdm_response_func libspdm_get_response_func_via_last_request(
130 : libspdm_context_t *spdm_context)
131 : {
132 : spdm_message_header_t *spdm_request;
133 :
134 4 : spdm_request = (void *)spdm_context->last_spdm_request;
135 4 : return libspdm_get_response_func_via_request_code(spdm_request->request_response_code);
136 : }
137 :
138 : /**
139 : * Process a SPDM request from a device.
140 : *
141 : * @param spdm_context The SPDM context for the device.
142 : * @param session_id Indicate if the request is a secured message.
143 : * If session_id is NULL, it is a normal message.
144 : * If session_id is NOT NULL, it is a secured message.
145 : * @param is_app_message Indicates if it is an APP message or SPDM message.
146 : * @param request_size size in bytes of the request data buffer.
147 : * @param request A pointer to a destination buffer to store the request.
148 : * The caller is responsible for having
149 : * either implicit or explicit ownership of the buffer.
150 : *
151 : * @retval RETURN_SUCCESS The SPDM request is received successfully.
152 : * @retval RETURN_DEVICE_ERROR A device error occurs when the SPDM request is received from the device.
153 : **/
154 0 : libspdm_return_t libspdm_process_request(void *spdm_context, uint32_t **session_id,
155 : bool *is_app_message,
156 : size_t request_size, void *request)
157 : {
158 : libspdm_context_t *context;
159 : void *temp_session_context;
160 : libspdm_return_t status;
161 : libspdm_session_info_t *session_info;
162 : uint32_t *message_session_id;
163 : uint8_t *decoded_message_ptr;
164 : size_t decoded_message_size;
165 : uint8_t *backup_decoded_message_ptr;
166 : size_t backup_decoded_message_size;
167 : bool result;
168 : bool reset_key_update;
169 :
170 0 : context = spdm_context;
171 : size_t transport_header_size;
172 : uint8_t *scratch_buffer;
173 : size_t scratch_buffer_size;
174 :
175 0 : if (request == NULL) {
176 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
177 : }
178 0 : if (request_size == 0) {
179 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
180 : }
181 :
182 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmReceiveRequest[.] ...\n"));
183 :
184 0 : message_session_id = NULL;
185 0 : context->last_spdm_request_session_id_valid = false;
186 0 : context->last_spdm_request_size =
187 0 : libspdm_get_scratch_buffer_last_spdm_request_capacity(context);
188 :
189 : /* always use scratch buffer to response.
190 : * if it is secured message, this scratch buffer will be used.
191 : * if it is normal message, the response ptr will point to receiver buffer. */
192 0 : transport_header_size = context->local_context.capability.transport_header_size;
193 0 : libspdm_get_scratch_buffer (context, (void **)&scratch_buffer, &scratch_buffer_size);
194 : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
195 0 : decoded_message_ptr = scratch_buffer +
196 0 : libspdm_get_scratch_buffer_secure_message_offset(context) +
197 : transport_header_size;
198 0 : decoded_message_size = libspdm_get_scratch_buffer_secure_message_capacity(context) -
199 : transport_header_size;
200 : #else
201 : decoded_message_ptr = scratch_buffer + transport_header_size;
202 : decoded_message_size = scratch_buffer_size - transport_header_size;
203 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
204 :
205 0 : backup_decoded_message_ptr = decoded_message_ptr;
206 0 : backup_decoded_message_size = decoded_message_size;
207 :
208 0 : status = context->transport_decode_message(
209 : context, &message_session_id, is_app_message, true,
210 : request_size, request, &decoded_message_size,
211 : (void **)&decoded_message_ptr);
212 :
213 0 : reset_key_update = false;
214 0 : temp_session_context = NULL;
215 :
216 0 : if (status == LIBSPDM_STATUS_SESSION_TRY_DISCARD_KEY_UPDATE) {
217 : /* Failed to decode, but have backup keys. Try rolling back before aborting.
218 : * message_session_id must be valid for us to have attempted decryption. */
219 0 : if (message_session_id == NULL) {
220 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
221 : }
222 0 : temp_session_context = libspdm_get_secured_message_context_via_session_id(
223 : context, *message_session_id);
224 0 : if (temp_session_context == NULL) {
225 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
226 : }
227 :
228 0 : result = libspdm_activate_update_session_data_key(
229 : temp_session_context, LIBSPDM_KEY_UPDATE_ACTION_REQUESTER, false);
230 0 : if (!result) {
231 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
232 : }
233 0 : libspdm_trigger_key_update_callback(
234 : context, *message_session_id,
235 : LIBSPDM_KEY_UPDATE_OPERATION_DISCARD_UPDATE,
236 : LIBSPDM_KEY_UPDATE_ACTION_REQUESTER);
237 :
238 : /* Retry decoding message with backup Requester key.
239 : * Must reset some of the parameters in case they were modified */
240 0 : message_session_id = NULL;
241 0 : decoded_message_ptr = backup_decoded_message_ptr;
242 0 : decoded_message_size = backup_decoded_message_size;
243 0 : status = context->transport_decode_message(
244 : context, &message_session_id, is_app_message, true,
245 : request_size, request, &decoded_message_size,
246 : (void **)&decoded_message_ptr);
247 :
248 0 : reset_key_update = true;
249 : }
250 :
251 0 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
252 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "transport_decode_message : %xu\n", status));
253 0 : if (context->last_spdm_error.error_code != 0) {
254 : /* If the SPDM error code is Non-Zero, that means we need send the error message back to requester.
255 : * In this case, we need return SUCCESS and let caller invoke libspdm_build_response() to send an ERROR message.*/
256 0 : *session_id = &context->last_spdm_error.session_id;
257 0 : *is_app_message = false;
258 0 : return LIBSPDM_STATUS_SUCCESS;
259 : }
260 0 : return status;
261 : }
262 :
263 : /* Handle special case for bi-directional communication:
264 : * If the Requester returns RESPONSE_NOT_READY error to KEY_UPDATE, the Responder needs
265 : * to activate backup key to parse the error. Then later the Requester will return SUCCESS,
266 : * the Responder needs new key. So we need to restore the environment by
267 : * libspdm_create_update_session_data_key() again.*/
268 0 : if (reset_key_update) {
269 : /* temp_session_context and message_session_id must necessarily
270 : * be valid for us to reach here. */
271 0 : if (temp_session_context == NULL || message_session_id == NULL) {
272 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
273 : }
274 0 : result = libspdm_create_update_session_data_key(
275 : temp_session_context, LIBSPDM_KEY_UPDATE_ACTION_REQUESTER);
276 0 : if (!result) {
277 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
278 : }
279 0 : libspdm_trigger_key_update_callback(
280 : context, *message_session_id,
281 : LIBSPDM_KEY_UPDATE_OPERATION_CREATE_UPDATE,
282 : LIBSPDM_KEY_UPDATE_ACTION_REQUESTER);
283 : }
284 :
285 0 : context->last_spdm_request_size = decoded_message_size;
286 0 : libspdm_copy_mem (context->last_spdm_request,
287 0 : libspdm_get_scratch_buffer_last_spdm_request_capacity(context),
288 : decoded_message_ptr,
289 : decoded_message_size);
290 :
291 0 : if (!(*is_app_message)) {
292 : /* Check for minimal SPDM message size. */
293 0 : if (context->last_spdm_request_size < sizeof(spdm_message_header_t)) {
294 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
295 : }
296 : }
297 :
298 0 : *session_id = message_session_id;
299 :
300 0 : if (message_session_id != NULL) {
301 0 : session_info = libspdm_get_session_info_via_session_id(context, *message_session_id);
302 0 : if (session_info == NULL) {
303 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
304 : }
305 0 : context->last_spdm_request_session_id = *message_session_id;
306 0 : context->last_spdm_request_session_id_valid = true;
307 : }
308 :
309 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmReceiveRequest[%x] msg %s(0x%x), size (0x%zx): \n",
310 : (message_session_id != NULL) ? *message_session_id : 0,
311 : libspdm_get_code_str(((spdm_message_header_t *)context->last_spdm_request)->
312 : request_response_code),
313 : ((spdm_message_header_t *)context->last_spdm_request)->request_response_code,
314 : context->last_spdm_request_size));
315 0 : LIBSPDM_INTERNAL_DUMP_HEX((uint8_t *)context->last_spdm_request,
316 : context->last_spdm_request_size);
317 :
318 0 : return LIBSPDM_STATUS_SUCCESS;
319 : }
320 :
321 : /**
322 : * Notify the session state to a session APP.
323 : *
324 : * @param spdm_context A pointer to the SPDM context.
325 : * @param session_id The session_id of a session.
326 : * @param session_state The state of a session.
327 : **/
328 22 : static void libspdm_trigger_session_state_callback(libspdm_context_t *spdm_context,
329 : uint32_t session_id,
330 : libspdm_session_state_t session_state)
331 : {
332 22 : if (spdm_context->spdm_session_state_callback != NULL) {
333 0 : ((libspdm_session_state_callback_func)
334 0 : spdm_context->spdm_session_state_callback)(spdm_context, session_id, session_state);
335 : }
336 22 : }
337 :
338 : /**
339 : * Set session_state to an SPDM secured message context and trigger callback.
340 : *
341 : * @param spdm_context A pointer to the SPDM context.
342 : * @param session_id Indicate the SPDM session ID.
343 : * @param session_state Indicate the SPDM session state.
344 : */
345 22 : void libspdm_set_session_state(libspdm_context_t *spdm_context,
346 : uint32_t session_id,
347 : libspdm_session_state_t session_state)
348 : {
349 : libspdm_session_info_t *session_info;
350 : libspdm_session_state_t old_session_state;
351 :
352 22 : session_info = libspdm_get_session_info_via_session_id(spdm_context, session_id);
353 22 : if (session_info == NULL) {
354 0 : LIBSPDM_ASSERT(false);
355 0 : return;
356 : }
357 :
358 22 : old_session_state = libspdm_secured_message_get_session_state(
359 : session_info->secured_message_context);
360 22 : if (old_session_state != session_state) {
361 22 : libspdm_secured_message_set_session_state(
362 : session_info->secured_message_context, session_state);
363 22 : libspdm_trigger_session_state_callback(
364 : spdm_context, session_info->session_id, session_state);
365 : }
366 : }
367 :
368 : /**
369 : * Notify the connection state to an SPDM context register.
370 : *
371 : * @param spdm_context A pointer to the SPDM context.
372 : * @param connection_state Indicate the SPDM connection state.
373 : **/
374 79 : static void libspdm_trigger_connection_state_callback(libspdm_context_t *spdm_context,
375 : const libspdm_connection_state_t
376 : connection_state)
377 : {
378 79 : if (spdm_context->spdm_connection_state_callback != NULL) {
379 0 : ((libspdm_connection_state_callback_func)
380 0 : spdm_context->spdm_connection_state_callback)(spdm_context, connection_state);
381 : }
382 79 : }
383 :
384 : /**
385 : * Set connection_state to an SPDM context and trigger callback.
386 : *
387 : * @param spdm_context A pointer to the SPDM context.
388 : * @param connection_state Indicate the SPDM connection state.
389 : */
390 81 : void libspdm_set_connection_state(libspdm_context_t *spdm_context,
391 : libspdm_connection_state_t connection_state)
392 : {
393 81 : if (spdm_context->connection_info.connection_state != connection_state) {
394 79 : spdm_context->connection_info.connection_state = connection_state;
395 79 : libspdm_trigger_connection_state_callback(spdm_context, connection_state);
396 : }
397 81 : }
398 :
399 15 : void libspdm_trigger_key_update_callback(void *spdm_context, uint32_t session_id,
400 : libspdm_key_update_operation_t key_update_op,
401 : libspdm_key_update_action_t key_update_action)
402 : {
403 : libspdm_context_t *context;
404 :
405 15 : context = spdm_context;
406 15 : if (context->spdm_key_update_callback != NULL) {
407 0 : ((libspdm_key_update_callback_func)
408 0 : context->spdm_key_update_callback)(context, session_id, key_update_op, key_update_action);
409 : }
410 15 : }
411 :
412 : /**
413 : * Build a SPDM response to a device.
414 : *
415 : * @param spdm_context The SPDM context for the device.
416 : * @param session_id Indicate if the response is a secured message.
417 : * If session_id is NULL, it is a normal message.
418 : * If session_id is NOT NULL, it is a secured message.
419 : * @param is_app_message Indicates if it is an APP message or SPDM message.
420 : * @param response_size size in bytes of the response data buffer.
421 : * @param response A pointer to a destination buffer to store the response.
422 : * The caller is responsible for having
423 : * either implicit or explicit ownership of the buffer.
424 : *
425 : * @retval RETURN_SUCCESS The SPDM response is sent successfully.
426 : * @retval RETURN_DEVICE_ERROR A device error occurs when the SPDM response is sent to the device.
427 : * @retval RETURN_UNSUPPORTED Just ignore this message: return UNSUPPORTED and clear response_size.
428 : * Continue the dispatch without send response.
429 : **/
430 4 : libspdm_return_t libspdm_build_response(void *spdm_context, const uint32_t *session_id,
431 : bool is_app_message,
432 : size_t *response_size,
433 : void **response)
434 : {
435 : libspdm_context_t *context;
436 : uint8_t *my_response;
437 : size_t my_response_size;
438 : libspdm_return_t status;
439 : libspdm_get_spdm_response_func get_response_func;
440 : libspdm_session_info_t *session_info;
441 : spdm_message_header_t *spdm_request;
442 : spdm_message_header_t *spdm_response;
443 : size_t transport_header_size;
444 : uint8_t *scratch_buffer;
445 : size_t scratch_buffer_size;
446 : uint8_t request_response_code;
447 : uint32_t actual_size;
448 :
449 : #if LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP
450 : bool result;
451 : #endif /* LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP */
452 :
453 : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
454 : uint8_t *large_buffer;
455 : size_t large_buffer_size;
456 : libspdm_chunk_info_t *get_info;
457 : spdm_chunk_response_response_t *chunk_rsp;
458 : uint8_t *chunk_ptr;
459 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
460 :
461 4 : context = spdm_context;
462 4 : status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
463 :
464 : /* For secure message, setup my_response to scratch buffer
465 : * For non-secure message, setup my_response to sender buffer*/
466 4 : transport_header_size = context->local_context.capability.transport_header_size;
467 4 : if (session_id != NULL) {
468 0 : libspdm_get_scratch_buffer (context, (void **)&scratch_buffer, &scratch_buffer_size);
469 : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
470 0 : my_response = scratch_buffer + libspdm_get_scratch_buffer_secure_message_offset(context) +
471 : transport_header_size;
472 0 : my_response_size = libspdm_get_scratch_buffer_secure_message_capacity(context) -
473 0 : transport_header_size -
474 0 : context->local_context.capability.transport_tail_size;
475 : #else
476 : my_response = scratch_buffer + transport_header_size;
477 : my_response_size = scratch_buffer_size - transport_header_size -
478 : context->local_context.capability.transport_tail_size;
479 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
480 : } else {
481 4 : my_response = (uint8_t *)*response + transport_header_size;
482 4 : my_response_size = *response_size - transport_header_size -
483 4 : context->local_context.capability.transport_tail_size;
484 : }
485 4 : libspdm_zero_mem(my_response, my_response_size);
486 :
487 4 : spdm_response = (void *)my_response;
488 :
489 4 : if (context->last_spdm_error.error_code != 0) {
490 : /* Error in libspdm_process_request(), and we need send error message directly. */
491 0 : switch (context->last_spdm_error.error_code) {
492 0 : case SPDM_ERROR_CODE_DECRYPT_ERROR:
493 : /* session ID is valid. Use it to encrypt the error message.*/
494 0 : if((context->handle_error_return_policy &
495 : LIBSPDM_DATA_HANDLE_ERROR_RETURN_POLICY_DROP_ON_DECRYPT_ERROR) == 0) {
496 0 : status = libspdm_generate_error_response(
497 : context, SPDM_ERROR_CODE_DECRYPT_ERROR, 0,
498 : &my_response_size, my_response);
499 : } else {
500 : /**
501 : * just ignore this message
502 : * return UNSUPPORTED and clear response_size to continue the dispatch without send response
503 : **/
504 0 : *response_size = 0;
505 0 : status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
506 : }
507 0 : break;
508 0 : case SPDM_ERROR_CODE_INVALID_SESSION:
509 : /**
510 : * don't use session ID, because we dont know which right session ID should be used.
511 : * just ignore this message
512 : * return UNSUPPORTED and clear response_size to continue the dispatch without send response
513 : **/
514 0 : *response_size = 0;
515 0 : status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
516 0 : break;
517 0 : default:
518 0 : LIBSPDM_ASSERT(false);
519 0 : status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
520 : }
521 :
522 0 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
523 0 : if ((session_id != NULL) &&
524 0 : (context->last_spdm_error.error_code == SPDM_ERROR_CODE_DECRYPT_ERROR)) {
525 0 : libspdm_free_session_id(context, *session_id);
526 : }
527 0 : return status;
528 : }
529 :
530 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmSendResponse[%x]: msg %s(0x%x), size (0x%zx): \n",
531 : (session_id != NULL) ? *session_id : 0,
532 : libspdm_get_code_str(spdm_response->request_response_code),
533 : spdm_response->request_response_code, my_response_size));
534 0 : LIBSPDM_INTERNAL_DUMP_HEX(my_response, my_response_size);
535 :
536 0 : status = context->transport_encode_message(
537 : context, session_id, false, false,
538 : my_response_size, my_response, response_size, response);
539 0 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
540 0 : if ((session_id != NULL) &&
541 0 : ((status == LIBSPDM_STATUS_SEQUENCE_NUMBER_OVERFLOW) ||
542 : (status == LIBSPDM_STATUS_CRYPTO_ERROR))) {
543 0 : libspdm_free_session_id(context, *session_id);
544 : }
545 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "transport_encode_message : %xu\n", status));
546 0 : return status;
547 : }
548 :
549 0 : if ((session_id != NULL) &&
550 0 : (context->last_spdm_error.error_code == SPDM_ERROR_CODE_DECRYPT_ERROR)) {
551 0 : libspdm_free_session_id(context, *session_id);
552 : }
553 :
554 0 : libspdm_zero_mem(&context->last_spdm_error, sizeof(context->last_spdm_error));
555 0 : return LIBSPDM_STATUS_SUCCESS;
556 : }
557 :
558 4 : if (session_id != NULL) {
559 0 : session_info = libspdm_get_session_info_via_session_id(context, *session_id);
560 0 : if (session_info == NULL) {
561 0 : LIBSPDM_ASSERT(false);
562 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
563 : }
564 : }
565 :
566 4 : if (*response == NULL) {
567 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
568 : }
569 4 : if ((response_size == NULL) || (*response_size == 0)) {
570 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
571 : }
572 :
573 4 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmSendResponse[%x] ...\n",
574 : (session_id != NULL) ? *session_id : 0));
575 :
576 4 : spdm_request = (void *)context->last_spdm_request;
577 4 : if (context->last_spdm_request_size == 0) {
578 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
579 : }
580 :
581 4 : get_response_func = NULL;
582 4 : if (!is_app_message) {
583 4 : get_response_func = libspdm_get_response_func_via_last_request(context);
584 :
585 : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
586 : /* If responder is expecting chunk_get or chunk_send requests
587 : * and gets other requests instead, drop out of chunking mode */
588 4 : if (context->chunk_context.get.chunk_in_use
589 0 : && get_response_func != libspdm_get_response_chunk_get) {
590 :
591 0 : context->chunk_context.get.chunk_in_use = false;
592 0 : context->chunk_context.get.chunk_handle++; /* implicit wrap - around to 0. */
593 0 : context->chunk_context.get.chunk_seq_no = 0;
594 :
595 0 : context->chunk_context.get.large_message = NULL;
596 0 : context->chunk_context.get.large_message_size = 0;
597 0 : context->chunk_context.get.chunk_bytes_transferred = 0;
598 : }
599 4 : if (context->chunk_context.send.chunk_in_use
600 0 : && get_response_func != libspdm_get_response_chunk_send) {
601 :
602 0 : context->chunk_context.send.chunk_in_use = false;
603 0 : context->chunk_context.send.chunk_handle = 0;
604 0 : context->chunk_context.send.chunk_seq_no = 0;
605 :
606 0 : context->chunk_context.send.large_message = NULL;
607 0 : context->chunk_context.send.large_message_size = 0;
608 0 : context->chunk_context.send.chunk_bytes_transferred = 0;
609 : }
610 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
611 :
612 4 : if (get_response_func != NULL) {
613 4 : status = get_response_func(
614 : context,
615 : context->last_spdm_request_size,
616 4 : context->last_spdm_request,
617 : &my_response_size, my_response);
618 : }
619 : }
620 4 : if (is_app_message || (get_response_func == NULL)) {
621 0 : if (context->get_response_func != NULL) {
622 0 : status = ((libspdm_get_response_func) context->get_response_func)(
623 : context, session_id, is_app_message,
624 : context->last_spdm_request_size,
625 0 : context->last_spdm_request,
626 : &my_response_size, my_response);
627 : } else {
628 0 : status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
629 : }
630 : }
631 :
632 4 : if (status == LIBSPDM_STATUS_SUCCESS) {
633 4 : LIBSPDM_ASSERT (my_response_size <= context->local_context.capability.max_spdm_msg_size);
634 : /* large SPDM message is the SPDM message whose size is greater than the DataTransferSize of the receiving
635 : * SPDM endpoint or greater than the transmit buffer size of the sending SPDM endpoint */
636 4 : if ((context->connection_info.capability.max_spdm_msg_size != 0) &&
637 4 : (my_response_size > context->connection_info.capability.max_spdm_msg_size)) {
638 1 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "my_response_size > req max_spdm_msg_size\n"));
639 1 : actual_size = (uint32_t)my_response_size;
640 1 : status = libspdm_generate_extended_error_response(context,
641 : SPDM_ERROR_CODE_RESPONSE_TOO_LARGE,
642 : 0,
643 : sizeof(uint32_t),
644 : (uint8_t *)&actual_size,
645 : &my_response_size, my_response);
646 3 : } else if ((((context->connection_info.capability.data_transfer_size != 0) &&
647 3 : (my_response_size > context->connection_info.capability.data_transfer_size)) ||
648 2 : ((context->local_context.capability.sender_data_transfer_size != 0) &&
649 2 : (my_response_size >
650 5 : context->local_context.capability.sender_data_transfer_size))) &&
651 3 : libspdm_is_capabilities_flag_supported(
652 : context, false, SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP,
653 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP)) {
654 : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
655 :
656 3 : get_info = &context->chunk_context.get;
657 :
658 : /* Saving multiple large responses is not an expected use case.
659 : * Therefore, if the requester did not perform chunk_get requests for
660 : * previous large responses, they will be lost. */
661 3 : if (get_info->chunk_in_use) {
662 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
663 : "Warning: Overwriting previous unrequested chunk_get info.\n"));
664 : }
665 :
666 3 : libspdm_get_scratch_buffer(context, (void **)&scratch_buffer, &scratch_buffer_size);
667 :
668 : /* The first section of the scratch
669 : * buffer may be used for other purposes. Use only after that section. */
670 6 : large_buffer = (uint8_t *)scratch_buffer +
671 3 : libspdm_get_scratch_buffer_large_message_offset(spdm_context);
672 3 : large_buffer_size = libspdm_get_scratch_buffer_large_message_capacity(spdm_context);
673 :
674 3 : get_info->chunk_in_use = true;
675 : /* Increment chunk_handle here as opposed to end of chunk_get handler
676 : * in case requester never issues chunk_get. */
677 3 : get_info->chunk_handle++;
678 3 : get_info->chunk_seq_no = 0;
679 3 : get_info->chunk_bytes_transferred = 0;
680 :
681 3 : libspdm_zero_mem(large_buffer, large_buffer_size);
682 :
683 : /* It's possible that the large response that was to be sent to the requester was
684 : * a CHUNK_SEND_ACK + non-chunk response. In this case, to prevent chunking within
685 : * chunking, only send back the actual response, by saving only non-chunk portion
686 : * in the scratch buffer, used to respond to the next CHUNK_GET request. */
687 3 : if (((spdm_message_header_t *)my_response)
688 3 : ->request_response_code == SPDM_CHUNK_SEND_ACK) {
689 0 : libspdm_copy_mem(large_buffer, large_buffer_size,
690 0 : my_response + sizeof(spdm_chunk_send_ack_response_t),
691 : my_response_size - sizeof(spdm_chunk_send_ack_response_t));
692 :
693 0 : get_info->large_message = large_buffer;
694 0 : get_info->large_message_size =
695 0 : my_response_size - sizeof(spdm_chunk_send_ack_response_t);
696 : } else {
697 3 : libspdm_copy_mem(large_buffer, large_buffer_size, my_response, my_response_size);
698 :
699 3 : get_info->large_message = large_buffer;
700 3 : get_info->large_message_size = my_response_size;
701 : }
702 :
703 3 : status = libspdm_generate_extended_error_response(context,
704 : SPDM_ERROR_CODE_LARGE_RESPONSE, 0,
705 : sizeof(uint8_t),
706 3 : &get_info->chunk_handle,
707 : &my_response_size, my_response);
708 : #else
709 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
710 : "Warning: Could not save chunk. Scratch buffer too small.\n"));
711 :
712 : status = libspdm_generate_extended_error_response(context,
713 : SPDM_ERROR_CODE_LARGE_RESPONSE,
714 : 0, 0, NULL,
715 : &my_response_size, my_response);
716 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
717 :
718 3 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
719 0 : return status;
720 : }
721 : }
722 : }
723 :
724 : /* if return the status: Responder drop the response
725 : * just ignore this message
726 : * return UNSUPPORTED and clear response_size to continue the dispatch without send response.*/
727 4 : if((my_response_size == 0) && (status == LIBSPDM_STATUS_UNSUPPORTED_CAP)) {
728 0 : *response_size = 0;
729 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
730 : }
731 :
732 4 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
733 0 : status = libspdm_generate_error_response(
734 : context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
735 0 : spdm_request->request_response_code, &my_response_size, my_response);
736 0 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
737 0 : return status;
738 : }
739 : }
740 :
741 4 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmSendResponse[%x]: msg %s(0x%x), size (0x%zx): \n",
742 : (session_id != NULL) ? *session_id : 0,
743 : libspdm_get_code_str(spdm_response->request_response_code),
744 : spdm_response->request_response_code,
745 : my_response_size));
746 4 : LIBSPDM_INTERNAL_DUMP_HEX(my_response, my_response_size);
747 :
748 4 : status = context->transport_encode_message(
749 : context, session_id, is_app_message, false,
750 : my_response_size, my_response, response_size, response);
751 4 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
752 0 : if ((session_id != NULL) &&
753 0 : ((status == LIBSPDM_STATUS_SEQUENCE_NUMBER_OVERFLOW) ||
754 : (status == LIBSPDM_STATUS_CRYPTO_ERROR))) {
755 0 : libspdm_free_session_id(context, *session_id);
756 : }
757 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "transport_encode_message : %xu\n", status));
758 0 : return status;
759 : }
760 :
761 4 : request_response_code = spdm_response->request_response_code;
762 : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
763 4 : switch (request_response_code) {
764 0 : case SPDM_CHUNK_SEND_ACK:
765 0 : if (my_response_size > sizeof(spdm_chunk_send_ack_response_t)) {
766 0 : request_response_code =
767 0 : ((spdm_message_header_t *)(my_response + sizeof(spdm_chunk_send_ack_response_t)))
768 : ->request_response_code;
769 : }
770 0 : break;
771 0 : case SPDM_CHUNK_RESPONSE:
772 0 : chunk_rsp = (spdm_chunk_response_response_t *)my_response;
773 0 : chunk_ptr = (uint8_t *)(((uint32_t *)(chunk_rsp + 1)) + 1);
774 0 : if (chunk_rsp->chunk_seq_no == 0) {
775 0 : request_response_code = ((spdm_message_header_t *)chunk_ptr)->request_response_code;
776 : }
777 0 : break;
778 4 : default:
779 4 : break;
780 : }
781 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
782 :
783 4 : if (session_id != NULL) {
784 0 : switch (request_response_code) {
785 0 : case SPDM_FINISH_RSP:
786 0 : if (!libspdm_is_capabilities_flag_supported(
787 : context, false,
788 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
789 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
790 0 : libspdm_set_session_state(
791 : context, *session_id,
792 : LIBSPDM_SESSION_STATE_ESTABLISHED);
793 : }
794 0 : break;
795 0 : case SPDM_PSK_FINISH_RSP:
796 0 : libspdm_set_session_state(context, *session_id, LIBSPDM_SESSION_STATE_ESTABLISHED);
797 0 : break;
798 0 : case SPDM_END_SESSION_ACK:
799 0 : libspdm_set_session_state(context, *session_id, LIBSPDM_SESSION_STATE_NOT_STARTED);
800 : #if LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP
801 0 : if (libspdm_is_capabilities_flag_supported(
802 : context, false,
803 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP,
804 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP)) {
805 0 : result = libspdm_stop_watchdog(*session_id);
806 0 : if (!result) {
807 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "libspdm_stop_watchdog error\n"));
808 : /* No need to return error for internal watchdog error. */
809 : }
810 : }
811 : #endif /* LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP */
812 0 : libspdm_free_session_id(context, *session_id);
813 0 : break;
814 0 : default:
815 : #if LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP
816 0 : if (libspdm_is_capabilities_flag_supported(
817 : context, false,
818 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP,
819 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP)) {
820 : /* reset watchdog in any session messages. */
821 0 : result = libspdm_reset_watchdog(*session_id);
822 0 : if (!result) {
823 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "libspdm_reset_watchdog error\n"));
824 : /* No need to return error for internal watchdog error. */
825 : }
826 : }
827 : #endif /* LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP */
828 0 : break;
829 : }
830 : } else {
831 4 : switch (request_response_code) {
832 0 : case SPDM_FINISH_RSP:
833 0 : if (libspdm_is_capabilities_flag_supported(
834 : context, false,
835 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
836 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
837 0 : libspdm_set_session_state(
838 : context,
839 : context->latest_session_id,
840 : LIBSPDM_SESSION_STATE_ESTABLISHED);
841 : }
842 0 : break;
843 4 : default:
844 : /* No session state update needed */
845 4 : break;
846 : }
847 : }
848 :
849 4 : return LIBSPDM_STATUS_SUCCESS;
850 : }
851 :
852 0 : void libspdm_register_get_response_func(void *context, libspdm_get_response_func get_response_func)
853 : {
854 : libspdm_context_t *spdm_context;
855 :
856 0 : spdm_context = context;
857 0 : spdm_context->get_response_func = (void *)get_response_func;
858 0 : }
859 :
860 0 : void libspdm_register_session_state_callback_func(
861 : void *spdm_context,
862 : libspdm_session_state_callback_func spdm_session_state_callback)
863 : {
864 : libspdm_context_t *context;
865 :
866 0 : LIBSPDM_ASSERT(spdm_context != NULL);
867 :
868 0 : context = spdm_context;
869 :
870 0 : context->spdm_session_state_callback = (void *)spdm_session_state_callback;
871 0 : }
872 :
873 0 : void libspdm_register_connection_state_callback_func(
874 : void *spdm_context,
875 : libspdm_connection_state_callback_func spdm_connection_state_callback)
876 : {
877 : libspdm_context_t *context;
878 :
879 0 : LIBSPDM_ASSERT(spdm_context != NULL);
880 :
881 0 : context = spdm_context;
882 0 : context->spdm_connection_state_callback = (void *)spdm_connection_state_callback;
883 0 : }
884 :
885 0 : void libspdm_register_key_update_callback_func(
886 : void *spdm_context, libspdm_key_update_callback_func spdm_key_update_callback)
887 : {
888 : libspdm_context_t *context;
889 :
890 0 : LIBSPDM_ASSERT(spdm_context != NULL);
891 :
892 0 : context = spdm_context;
893 0 : context->spdm_key_update_callback = (void *)spdm_key_update_callback;
894 0 : }
895 :
896 : #if (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) && (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP) && \
897 : (LIBSPDM_SEND_GET_CERTIFICATE_SUPPORT)
898 99 : void libspdm_register_cert_chain_buffer(
899 : void *spdm_context, void *cert_chain_buffer, size_t cert_chain_buffer_max_size)
900 : {
901 : libspdm_context_t *context;
902 :
903 99 : LIBSPDM_ASSERT(spdm_context != NULL);
904 :
905 99 : context = spdm_context;
906 99 : context->mut_auth_cert_chain_buffer = cert_chain_buffer;
907 99 : context->mut_auth_cert_chain_buffer_max_size = cert_chain_buffer_max_size;
908 99 : context->mut_auth_cert_chain_buffer_size = 0;
909 99 : }
910 : #endif
|