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 15 : 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 15 : 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 150 : for (index = 0; index < LIBSPDM_ARRAY_SIZE(get_response_struct); index++) {
115 150 : if (request_code == get_response_struct[index].request_response_code) {
116 15 : 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 0 : libspdm_return_t libspdm_process_request(void *spdm_context, uint32_t **session_id,
152 : bool *is_app_message,
153 : size_t request_size, void *request)
154 : {
155 : libspdm_context_t *context;
156 : void *temp_session_context;
157 : libspdm_return_t status;
158 : libspdm_session_info_t *session_info;
159 : uint32_t *message_session_id;
160 : uint8_t *decoded_message_ptr;
161 : size_t decoded_message_size;
162 : uint8_t *backup_decoded_message_ptr;
163 : size_t backup_decoded_message_size;
164 : bool result;
165 : bool reset_key_update;
166 :
167 0 : context = spdm_context;
168 : size_t transport_header_size;
169 : uint8_t *scratch_buffer;
170 : size_t scratch_buffer_size;
171 :
172 0 : if (request == NULL) {
173 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
174 : }
175 0 : if (request_size == 0) {
176 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
177 : }
178 :
179 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmReceiveRequest[.] ...\n"));
180 :
181 0 : message_session_id = NULL;
182 0 : context->last_spdm_request_session_id_valid = false;
183 0 : context->last_spdm_request_size =
184 0 : libspdm_get_scratch_buffer_last_spdm_request_capacity(context);
185 :
186 : /* always use scratch buffer to response.
187 : * if it is secured message, this scratch buffer will be used.
188 : * if it is normal message, the response ptr will point to receiver buffer. */
189 0 : transport_header_size = context->local_context.capability.transport_header_size;
190 0 : libspdm_get_scratch_buffer (context, (void **)&scratch_buffer, &scratch_buffer_size);
191 : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
192 0 : decoded_message_ptr = scratch_buffer +
193 0 : libspdm_get_scratch_buffer_secure_message_offset(context) +
194 : transport_header_size;
195 0 : decoded_message_size = libspdm_get_scratch_buffer_secure_message_capacity(context) -
196 : transport_header_size;
197 : #else
198 : decoded_message_ptr = scratch_buffer + transport_header_size;
199 : decoded_message_size = scratch_buffer_size - transport_header_size;
200 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
201 :
202 0 : backup_decoded_message_ptr = decoded_message_ptr;
203 0 : backup_decoded_message_size = decoded_message_size;
204 :
205 0 : status = context->transport_decode_message(
206 : context, &message_session_id, is_app_message, true,
207 : request_size, request, &decoded_message_size,
208 : (void **)&decoded_message_ptr);
209 :
210 0 : reset_key_update = false;
211 0 : temp_session_context = NULL;
212 :
213 0 : if (status == LIBSPDM_STATUS_SESSION_TRY_DISCARD_KEY_UPDATE) {
214 : /* Failed to decode, but have backup keys. Try rolling back before aborting.
215 : * message_session_id must be valid for us to have attempted decryption. */
216 0 : if (message_session_id == NULL) {
217 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
218 : }
219 0 : temp_session_context = libspdm_get_secured_message_context_via_session_id(
220 : context, *message_session_id);
221 0 : if (temp_session_context == NULL) {
222 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
223 : }
224 :
225 0 : result = libspdm_activate_update_session_data_key(
226 : temp_session_context, LIBSPDM_KEY_UPDATE_ACTION_REQUESTER, false);
227 0 : if (!result) {
228 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
229 : }
230 0 : libspdm_trigger_key_update_callback(
231 : context, *message_session_id,
232 : LIBSPDM_KEY_UPDATE_OPERATION_DISCARD_UPDATE,
233 : LIBSPDM_KEY_UPDATE_ACTION_REQUESTER);
234 :
235 : /* Retry decoding message with backup Requester key.
236 : * Must reset some of the parameters in case they were modified */
237 0 : message_session_id = NULL;
238 0 : decoded_message_ptr = backup_decoded_message_ptr;
239 0 : decoded_message_size = backup_decoded_message_size;
240 0 : status = context->transport_decode_message(
241 : context, &message_session_id, is_app_message, true,
242 : request_size, request, &decoded_message_size,
243 : (void **)&decoded_message_ptr);
244 :
245 0 : reset_key_update = true;
246 : }
247 :
248 0 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
249 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "transport_decode_message : %xu\n", status));
250 0 : if (context->last_spdm_error.error_code != 0) {
251 : /* If the SPDM error code is Non-Zero, that means we need send the error message back to requester.
252 : * In this case, we need return SUCCESS and let caller invoke libspdm_build_response() to send an ERROR message.*/
253 0 : *session_id = &context->last_spdm_error.session_id;
254 0 : *is_app_message = false;
255 0 : return LIBSPDM_STATUS_SUCCESS;
256 : }
257 0 : return status;
258 : }
259 :
260 : /* Handle special case for bi-directional communication:
261 : * If the Requester returns RESPONSE_NOT_READY error to KEY_UPDATE, the Responder needs
262 : * to activate backup key to parse the error. Then later the Requester will return SUCCESS,
263 : * the Responder needs new key. So we need to restore the environment by
264 : * libspdm_create_update_session_data_key() again.*/
265 0 : if (reset_key_update) {
266 : /* temp_session_context and message_session_id must necessarily
267 : * be valid for us to reach here. */
268 0 : if (temp_session_context == NULL || message_session_id == NULL) {
269 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
270 : }
271 0 : result = libspdm_create_update_session_data_key(
272 : temp_session_context, LIBSPDM_KEY_UPDATE_ACTION_REQUESTER);
273 0 : if (!result) {
274 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
275 : }
276 0 : libspdm_trigger_key_update_callback(
277 : context, *message_session_id,
278 : LIBSPDM_KEY_UPDATE_OPERATION_CREATE_UPDATE,
279 : LIBSPDM_KEY_UPDATE_ACTION_REQUESTER);
280 : }
281 :
282 : /*
283 : * decoded_message may contain padding zeros due to transport layer alignment requirements.
284 : * trim the decoded_message size to the maximum data_transfer_size.
285 : */
286 0 : decoded_message_size = LIBSPDM_MIN(decoded_message_size,
287 : context->local_context.capability.data_transfer_size);
288 :
289 0 : context->last_spdm_request_size = decoded_message_size;
290 0 : libspdm_copy_mem (context->last_spdm_request,
291 0 : libspdm_get_scratch_buffer_last_spdm_request_capacity(context),
292 : decoded_message_ptr,
293 : decoded_message_size);
294 0 : libspdm_zero_mem (decoded_message_ptr, decoded_message_size);
295 :
296 0 : if (!(*is_app_message)) {
297 : /* Check for minimal SPDM message size. */
298 0 : if (context->last_spdm_request_size < sizeof(spdm_message_header_t)) {
299 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
300 : }
301 : }
302 :
303 0 : *session_id = message_session_id;
304 :
305 0 : if (message_session_id != NULL) {
306 0 : session_info = libspdm_get_session_info_via_session_id(context, *message_session_id);
307 0 : if (session_info == NULL) {
308 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
309 : }
310 0 : context->last_spdm_request_session_id = *message_session_id;
311 0 : context->last_spdm_request_session_id_valid = true;
312 : }
313 :
314 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmReceiveRequest[%x] msg %s(0x%x), size (0x%zx): \n",
315 : (message_session_id != NULL) ? *message_session_id : 0,
316 : libspdm_get_code_str(((spdm_message_header_t *)context->last_spdm_request)->
317 : request_response_code),
318 : ((spdm_message_header_t *)context->last_spdm_request)->request_response_code,
319 : context->last_spdm_request_size));
320 0 : LIBSPDM_INTERNAL_DUMP_HEX((uint8_t *)context->last_spdm_request,
321 : context->last_spdm_request_size);
322 :
323 0 : return LIBSPDM_STATUS_SUCCESS;
324 : }
325 :
326 : /**
327 : * Notify the session state to a session APP.
328 : *
329 : * @param spdm_context A pointer to the SPDM context.
330 : * @param session_id The session_id of a session.
331 : * @param session_state The state of a session.
332 : **/
333 22 : static void libspdm_trigger_session_state_callback(libspdm_context_t *spdm_context,
334 : uint32_t session_id,
335 : libspdm_session_state_t session_state)
336 : {
337 22 : if (spdm_context->spdm_session_state_callback != NULL) {
338 0 : ((libspdm_session_state_callback_func)
339 0 : spdm_context->spdm_session_state_callback)(spdm_context, session_id, session_state);
340 : }
341 22 : }
342 :
343 : /**
344 : * Set session_state to an SPDM secured message context and trigger callback.
345 : *
346 : * @param spdm_context A pointer to the SPDM context.
347 : * @param session_id Indicate the SPDM session ID.
348 : * @param session_state Indicate the SPDM session state.
349 : */
350 22 : void libspdm_set_session_state(libspdm_context_t *spdm_context,
351 : uint32_t session_id,
352 : libspdm_session_state_t session_state)
353 : {
354 : libspdm_session_info_t *session_info;
355 : libspdm_session_state_t old_session_state;
356 :
357 22 : session_info = libspdm_get_session_info_via_session_id(spdm_context, session_id);
358 22 : if (session_info == NULL) {
359 0 : LIBSPDM_ASSERT(false);
360 0 : return;
361 : }
362 :
363 22 : old_session_state = libspdm_secured_message_get_session_state(
364 : session_info->secured_message_context);
365 22 : if (old_session_state != session_state) {
366 22 : libspdm_secured_message_set_session_state(
367 : session_info->secured_message_context, session_state);
368 22 : libspdm_trigger_session_state_callback(
369 : spdm_context, session_info->session_id, session_state);
370 : }
371 : }
372 :
373 : /**
374 : * This function allows the consumer to terminate a session.
375 : * For example, it can be used when the heartbeat period is over.
376 : *
377 : * @param spdm_context A pointer to the SPDM context.
378 : * @param session_id session_id of the session to be terminated.
379 : *
380 : * @retval LIBSPDM_STATUS_SUCCESS Success
381 : * @retval LIBSPDM_STATUS_INVALID_PARAMETER session_id is invalid.
382 : **/
383 0 : libspdm_return_t libspdm_terminate_session(
384 : void *spdm_context, uint32_t session_id)
385 : {
386 : libspdm_session_info_t *session_info;
387 :
388 0 : session_info = libspdm_get_session_info_via_session_id(spdm_context, session_id);
389 0 : if (session_info == NULL) {
390 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
391 : }
392 :
393 0 : libspdm_set_session_state(spdm_context, session_id, LIBSPDM_SESSION_STATE_NOT_STARTED);
394 0 : libspdm_free_session_id(spdm_context, session_id);
395 0 : return LIBSPDM_STATUS_SUCCESS;
396 : }
397 :
398 : /**
399 : * Notify the connection state to an SPDM context register.
400 : *
401 : * @param spdm_context A pointer to the SPDM context.
402 : * @param connection_state Indicate the SPDM connection state.
403 : **/
404 81 : static void libspdm_trigger_connection_state_callback(libspdm_context_t *spdm_context,
405 : const libspdm_connection_state_t
406 : connection_state)
407 : {
408 81 : if (spdm_context->spdm_connection_state_callback != NULL) {
409 0 : ((libspdm_connection_state_callback_func)
410 0 : spdm_context->spdm_connection_state_callback)(spdm_context, connection_state);
411 : }
412 81 : }
413 :
414 : /**
415 : * Set connection_state to an SPDM context and trigger callback.
416 : *
417 : * @param spdm_context A pointer to the SPDM context.
418 : * @param connection_state Indicate the SPDM connection state.
419 : */
420 83 : void libspdm_set_connection_state(libspdm_context_t *spdm_context,
421 : libspdm_connection_state_t connection_state)
422 : {
423 83 : if (spdm_context->connection_info.connection_state != connection_state) {
424 81 : spdm_context->connection_info.connection_state = connection_state;
425 81 : libspdm_trigger_connection_state_callback(spdm_context, connection_state);
426 : }
427 83 : }
428 :
429 15 : void libspdm_trigger_key_update_callback(void *spdm_context, uint32_t session_id,
430 : libspdm_key_update_operation_t key_update_op,
431 : libspdm_key_update_action_t key_update_action)
432 : {
433 : libspdm_context_t *context;
434 :
435 15 : context = spdm_context;
436 15 : if (context->spdm_key_update_callback != NULL) {
437 0 : ((libspdm_key_update_callback_func)
438 0 : context->spdm_key_update_callback)(context, session_id, key_update_op, key_update_action);
439 : }
440 15 : }
441 :
442 4 : libspdm_return_t libspdm_build_response(void *spdm_context, const uint32_t *session_id,
443 : bool is_app_message,
444 : size_t *response_size,
445 : void **response)
446 : {
447 : libspdm_context_t *context;
448 : uint8_t *my_response;
449 : size_t my_response_size;
450 : libspdm_return_t status;
451 : libspdm_get_spdm_response_func get_response_func;
452 : libspdm_session_info_t *session_info;
453 : spdm_message_header_t *spdm_request;
454 : spdm_message_header_t *spdm_response;
455 : size_t transport_header_size;
456 : uint8_t *scratch_buffer;
457 : size_t scratch_buffer_size;
458 : uint8_t request_response_code;
459 : uint32_t actual_size;
460 :
461 : #if LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP
462 : bool result;
463 : #endif /* LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP */
464 :
465 : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
466 : uint8_t *large_buffer;
467 : size_t large_buffer_size;
468 : libspdm_chunk_info_t *get_info;
469 : spdm_chunk_response_response_t *chunk_rsp;
470 : uint8_t *chunk_ptr;
471 : size_t chunk_send_ack_response_header_size;
472 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
473 :
474 4 : context = spdm_context;
475 4 : status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
476 :
477 : /* For secure message, setup my_response to scratch buffer
478 : * For non-secure message, setup my_response to sender buffer*/
479 4 : transport_header_size = context->local_context.capability.transport_header_size;
480 4 : if (session_id != NULL) {
481 0 : libspdm_get_scratch_buffer (context, (void **)&scratch_buffer, &scratch_buffer_size);
482 : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
483 0 : my_response = scratch_buffer + libspdm_get_scratch_buffer_secure_message_offset(context) +
484 : transport_header_size;
485 0 : my_response_size = libspdm_get_scratch_buffer_secure_message_capacity(context) -
486 0 : transport_header_size -
487 0 : context->local_context.capability.transport_tail_size;
488 : #else
489 : my_response = scratch_buffer + transport_header_size;
490 : my_response_size = scratch_buffer_size - transport_header_size -
491 : context->local_context.capability.transport_tail_size;
492 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
493 : } else {
494 4 : my_response = (uint8_t *)*response + transport_header_size;
495 4 : my_response_size = *response_size - transport_header_size -
496 4 : context->local_context.capability.transport_tail_size;
497 : }
498 4 : libspdm_zero_mem(my_response, my_response_size);
499 :
500 4 : spdm_response = (void *)my_response;
501 :
502 4 : if (context->last_spdm_error.error_code != 0) {
503 : /* Error in libspdm_process_request(), and we need send error message directly. */
504 0 : switch (context->last_spdm_error.error_code) {
505 0 : case SPDM_ERROR_CODE_DECRYPT_ERROR:
506 : /* session ID is valid. Use it to encrypt the error message.*/
507 0 : if ((context->handle_error_return_policy &
508 : LIBSPDM_DATA_HANDLE_ERROR_RETURN_POLICY_DROP_ON_DECRYPT_ERROR) == 0) {
509 0 : status = libspdm_generate_error_response(
510 : context, SPDM_ERROR_CODE_DECRYPT_ERROR, 0,
511 : &my_response_size, my_response);
512 : } else {
513 : /**
514 : * just ignore this message
515 : * return UNSUPPORTED and clear response_size to continue the dispatch without send response
516 : **/
517 0 : *response_size = 0;
518 0 : status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
519 : }
520 0 : break;
521 0 : case SPDM_ERROR_CODE_INVALID_SESSION:
522 : /**
523 : * don't use session ID, because we dont know which right session ID should be used.
524 : * just ignore this message
525 : * return UNSUPPORTED and clear response_size to continue the dispatch without send response
526 : **/
527 0 : *response_size = 0;
528 0 : status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
529 0 : break;
530 0 : default:
531 0 : LIBSPDM_ASSERT(false);
532 0 : status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
533 : }
534 :
535 0 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
536 0 : if ((session_id != NULL) &&
537 0 : (context->last_spdm_error.error_code == SPDM_ERROR_CODE_DECRYPT_ERROR)) {
538 0 : libspdm_free_session_id(context, *session_id);
539 : }
540 0 : return status;
541 : }
542 :
543 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmSendResponse[%x]: msg %s(0x%x), size (0x%zx): \n",
544 : (session_id != NULL) ? *session_id : 0,
545 : libspdm_get_code_str(spdm_response->request_response_code),
546 : spdm_response->request_response_code, my_response_size));
547 0 : LIBSPDM_INTERNAL_DUMP_HEX(my_response, my_response_size);
548 :
549 0 : status = context->transport_encode_message(
550 : context, session_id, false, false,
551 : my_response_size, my_response, response_size, response);
552 0 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
553 0 : if ((session_id != NULL) &&
554 0 : ((status == LIBSPDM_STATUS_SEQUENCE_NUMBER_OVERFLOW) ||
555 : (status == LIBSPDM_STATUS_CRYPTO_ERROR))) {
556 0 : libspdm_free_session_id(context, *session_id);
557 : }
558 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "transport_encode_message : %xu\n", status));
559 0 : return status;
560 : }
561 :
562 0 : if ((session_id != NULL) &&
563 0 : (context->last_spdm_error.error_code == SPDM_ERROR_CODE_DECRYPT_ERROR)) {
564 0 : libspdm_free_session_id(context, *session_id);
565 : }
566 :
567 0 : libspdm_zero_mem(&context->last_spdm_error, sizeof(context->last_spdm_error));
568 0 : return LIBSPDM_STATUS_SUCCESS;
569 : }
570 :
571 4 : if (session_id != NULL) {
572 0 : session_info = libspdm_get_session_info_via_session_id(context, *session_id);
573 0 : if (session_info == NULL) {
574 0 : LIBSPDM_ASSERT(false);
575 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
576 : }
577 : }
578 :
579 4 : if (*response == NULL) {
580 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
581 : }
582 4 : if ((response_size == NULL) || (*response_size == 0)) {
583 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
584 : }
585 :
586 4 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmSendResponse[%x] ...\n",
587 : (session_id != NULL) ? *session_id : 0));
588 :
589 4 : spdm_request = (void *)context->last_spdm_request;
590 4 : if (context->last_spdm_request_size == 0) {
591 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
592 : }
593 :
594 4 : get_response_func = NULL;
595 4 : if (!is_app_message) {
596 4 : get_response_func = libspdm_get_response_func_via_last_request(context);
597 :
598 : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
599 : /* If responder is expecting chunk_get or chunk_send requests
600 : * and gets other requests instead, drop out of chunking mode */
601 4 : if (context->chunk_context.get.chunk_in_use
602 0 : && get_response_func != libspdm_get_response_chunk_get) {
603 :
604 0 : context->chunk_context.get.chunk_in_use = false;
605 0 : context->chunk_context.get.chunk_handle++; /* implicit wrap - around to 0. */
606 0 : context->chunk_context.get.chunk_seq_no = 0;
607 :
608 0 : context->chunk_context.get.large_message = NULL;
609 0 : context->chunk_context.get.large_message_size = 0;
610 0 : context->chunk_context.get.chunk_bytes_transferred = 0;
611 : }
612 4 : if (context->chunk_context.send.chunk_in_use
613 0 : && get_response_func != libspdm_get_response_chunk_send) {
614 :
615 0 : context->chunk_context.send.chunk_in_use = false;
616 0 : context->chunk_context.send.chunk_handle = 0;
617 0 : context->chunk_context.send.chunk_seq_no = 0;
618 :
619 0 : context->chunk_context.send.large_message = NULL;
620 0 : context->chunk_context.send.large_message_size = 0;
621 0 : context->chunk_context.send.chunk_bytes_transferred = 0;
622 : }
623 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
624 :
625 4 : if (get_response_func != NULL) {
626 4 : status = get_response_func(
627 : context,
628 : context->last_spdm_request_size,
629 4 : context->last_spdm_request,
630 : &my_response_size, my_response);
631 : }
632 : }
633 4 : if (is_app_message || (get_response_func == NULL)) {
634 0 : if (context->get_response_func != NULL) {
635 0 : status = ((libspdm_get_response_func) context->get_response_func)(
636 : context, session_id, is_app_message,
637 : context->last_spdm_request_size,
638 0 : context->last_spdm_request,
639 : &my_response_size, my_response);
640 : } else {
641 0 : status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
642 : }
643 : }
644 :
645 : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
646 4 : if (libspdm_get_connection_version(context) < SPDM_MESSAGE_VERSION_14) {
647 4 : chunk_send_ack_response_header_size = sizeof(spdm_chunk_send_ack_response_t);
648 : } else {
649 0 : chunk_send_ack_response_header_size = sizeof(spdm_chunk_send_ack_response_14_t);
650 : }
651 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
652 :
653 4 : if (status == LIBSPDM_STATUS_SUCCESS) {
654 4 : LIBSPDM_ASSERT (my_response_size <= context->local_context.capability.max_spdm_msg_size);
655 : /* large SPDM message is the SPDM message whose size is greater than the DataTransferSize of the receiving
656 : * SPDM endpoint or greater than the transmit buffer size of the sending SPDM endpoint */
657 4 : if ((context->connection_info.capability.max_spdm_msg_size != 0) &&
658 4 : (my_response_size > context->connection_info.capability.max_spdm_msg_size)) {
659 1 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "my_response_size > req max_spdm_msg_size\n"));
660 1 : actual_size = (uint32_t)my_response_size;
661 1 : status = libspdm_generate_extended_error_response(context,
662 : SPDM_ERROR_CODE_RESPONSE_TOO_LARGE,
663 : 0,
664 : sizeof(uint32_t),
665 : (uint8_t *)&actual_size,
666 : &my_response_size, my_response);
667 3 : } else if ((((context->connection_info.capability.data_transfer_size != 0) &&
668 3 : (my_response_size > context->connection_info.capability.data_transfer_size)) ||
669 2 : ((context->local_context.capability.sender_data_transfer_size != 0) &&
670 2 : (my_response_size >
671 5 : context->local_context.capability.sender_data_transfer_size))) &&
672 3 : libspdm_is_capabilities_flag_supported(
673 : context, false, SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP,
674 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP)) {
675 : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
676 :
677 3 : get_info = &context->chunk_context.get;
678 :
679 : /* Saving multiple large responses is not an expected use case.
680 : * Therefore, if the requester did not perform chunk_get requests for
681 : * previous large responses, they will be lost. */
682 3 : if (get_info->chunk_in_use) {
683 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
684 : "Warning: Overwriting previous unrequested chunk_get info.\n"));
685 : }
686 :
687 3 : libspdm_get_scratch_buffer(context, (void **)&scratch_buffer, &scratch_buffer_size);
688 :
689 : /* The first section of the scratch
690 : * buffer may be used for other purposes. Use only after that section. */
691 6 : large_buffer = (uint8_t *)scratch_buffer +
692 3 : libspdm_get_scratch_buffer_large_message_offset(spdm_context);
693 3 : large_buffer_size = libspdm_get_scratch_buffer_large_message_capacity(spdm_context);
694 :
695 3 : get_info->chunk_in_use = true;
696 : /* Increment chunk_handle here as opposed to end of chunk_get handler
697 : * in case requester never issues chunk_get. */
698 3 : get_info->chunk_handle++;
699 3 : get_info->chunk_seq_no = 0;
700 3 : get_info->chunk_bytes_transferred = 0;
701 :
702 3 : libspdm_zero_mem(large_buffer, large_buffer_size);
703 :
704 : /* It's possible that the large response that was to be sent to the requester was
705 : * a CHUNK_SEND_ACK + non-chunk response. In this case, to prevent chunking within
706 : * chunking, only send back the actual response, by saving only non-chunk portion
707 : * in the scratch buffer, used to respond to the next CHUNK_GET request. */
708 3 : if (((spdm_message_header_t *)my_response)
709 3 : ->request_response_code == SPDM_CHUNK_SEND_ACK) {
710 0 : libspdm_copy_mem(large_buffer, large_buffer_size,
711 0 : my_response + chunk_send_ack_response_header_size,
712 : my_response_size - chunk_send_ack_response_header_size);
713 0 : get_info->large_message = large_buffer;
714 0 : get_info->large_message_size =
715 0 : my_response_size - chunk_send_ack_response_header_size;
716 : } else {
717 3 : libspdm_copy_mem(large_buffer, large_buffer_size, my_response, my_response_size);
718 :
719 3 : get_info->large_message = large_buffer;
720 3 : get_info->large_message_size = my_response_size;
721 : }
722 :
723 3 : status = libspdm_generate_extended_error_response(context,
724 : SPDM_ERROR_CODE_LARGE_RESPONSE, 0,
725 : sizeof(uint8_t),
726 3 : &get_info->chunk_handle,
727 : &my_response_size, my_response);
728 : #else
729 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
730 : "Warning: Could not save chunk. Scratch buffer too small.\n"));
731 :
732 : status = libspdm_generate_extended_error_response(context,
733 : SPDM_ERROR_CODE_LARGE_RESPONSE,
734 : 0, 0, NULL,
735 : &my_response_size, my_response);
736 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
737 :
738 3 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
739 0 : return status;
740 : }
741 : }
742 : }
743 :
744 : /* if return the status: Responder drop the response
745 : * just ignore this message
746 : * return UNSUPPORTED and clear response_size to continue the dispatch without send response.*/
747 4 : if ((my_response_size == 0) && (status == LIBSPDM_STATUS_UNSUPPORTED_CAP)) {
748 0 : *response_size = 0;
749 0 : status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
750 0 : goto done;
751 : }
752 :
753 4 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
754 0 : status = libspdm_generate_error_response(
755 : context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
756 0 : spdm_request->request_response_code, &my_response_size, my_response);
757 0 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
758 0 : goto done;
759 : }
760 : }
761 :
762 4 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmSendResponse[%x]: msg %s(0x%x), size (0x%zx): \n",
763 : (session_id != NULL) ? *session_id : 0,
764 : libspdm_get_code_str(spdm_response->request_response_code),
765 : spdm_response->request_response_code,
766 : my_response_size));
767 4 : LIBSPDM_INTERNAL_DUMP_HEX(my_response, my_response_size);
768 :
769 4 : status = context->transport_encode_message(
770 : context, session_id, is_app_message, false,
771 : my_response_size, my_response, response_size, response);
772 4 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
773 0 : if ((session_id != NULL) &&
774 0 : ((status == LIBSPDM_STATUS_SEQUENCE_NUMBER_OVERFLOW) ||
775 : (status == LIBSPDM_STATUS_CRYPTO_ERROR))) {
776 0 : libspdm_free_session_id(context, *session_id);
777 : }
778 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "transport_encode_message : %xu\n", status));
779 0 : goto done;
780 : }
781 :
782 4 : request_response_code = spdm_response->request_response_code;
783 : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
784 4 : switch (request_response_code) {
785 0 : case SPDM_CHUNK_SEND_ACK:
786 0 : if (my_response_size > chunk_send_ack_response_header_size) {
787 0 : request_response_code =
788 0 : ((spdm_message_header_t *)(my_response + chunk_send_ack_response_header_size))
789 : ->request_response_code;
790 : }
791 0 : break;
792 0 : case SPDM_CHUNK_RESPONSE:
793 0 : chunk_rsp = (spdm_chunk_response_response_t *)my_response;
794 0 : chunk_ptr = (uint8_t *)(((uint32_t *)(chunk_rsp + 1)) + 1);
795 0 : if (chunk_rsp->chunk_seq_no == 0) {
796 0 : request_response_code = ((spdm_message_header_t *)chunk_ptr)->request_response_code;
797 : }
798 0 : break;
799 4 : default:
800 4 : break;
801 : }
802 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
803 :
804 4 : if (session_id != NULL) {
805 0 : switch (request_response_code) {
806 0 : case SPDM_FINISH_RSP:
807 0 : if (!libspdm_is_capabilities_flag_supported(
808 : context, false,
809 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
810 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
811 0 : libspdm_set_session_state(
812 : context, *session_id,
813 : LIBSPDM_SESSION_STATE_ESTABLISHED);
814 : }
815 0 : break;
816 0 : case SPDM_PSK_FINISH_RSP:
817 0 : libspdm_set_session_state(context, *session_id, LIBSPDM_SESSION_STATE_ESTABLISHED);
818 0 : break;
819 0 : case SPDM_END_SESSION_ACK:
820 : #if LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP
821 0 : if (libspdm_is_capabilities_flag_supported(
822 : context, false,
823 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP,
824 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP)) {
825 0 : result = libspdm_stop_watchdog(*session_id);
826 0 : if (!result) {
827 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "libspdm_stop_watchdog error\n"));
828 : /* No need to return error for internal watchdog error. */
829 : }
830 : }
831 : #endif /* LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP */
832 0 : libspdm_terminate_session(context, *session_id);
833 0 : break;
834 0 : default:
835 : #if LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP
836 0 : if (libspdm_is_capabilities_flag_supported(
837 : context, false,
838 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP,
839 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP)) {
840 : /* reset watchdog in any session messages. */
841 0 : result = libspdm_reset_watchdog(*session_id);
842 0 : if (!result) {
843 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "libspdm_reset_watchdog error\n"));
844 : /* No need to return error for internal watchdog error. */
845 : }
846 : }
847 : #endif /* LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP */
848 0 : break;
849 : }
850 : } else {
851 4 : switch (request_response_code) {
852 0 : case SPDM_FINISH_RSP:
853 0 : if (libspdm_is_capabilities_flag_supported(
854 : context, false,
855 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
856 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
857 0 : libspdm_set_session_state(
858 : context,
859 : context->latest_session_id,
860 : LIBSPDM_SESSION_STATE_ESTABLISHED);
861 : }
862 0 : break;
863 4 : default:
864 : /* No session state update needed */
865 4 : break;
866 : }
867 : }
868 :
869 4 : status = LIBSPDM_STATUS_SUCCESS;
870 4 : done:
871 4 : if (session_id != NULL) {
872 : /* clean plain text in stratch buffer */
873 0 : libspdm_zero_mem (my_response, my_response_size);
874 : }
875 4 : libspdm_zero_mem (context->last_spdm_request,
876 4 : libspdm_get_scratch_buffer_last_spdm_request_capacity(context));
877 4 : context->last_spdm_request_size = 0;
878 4 : context->last_spdm_request_session_id_valid = false;
879 4 : return status;
880 : }
881 :
882 0 : void libspdm_register_get_response_func(void *context, libspdm_get_response_func get_response_func)
883 : {
884 : libspdm_context_t *spdm_context;
885 :
886 0 : spdm_context = context;
887 0 : spdm_context->get_response_func = (void *)get_response_func;
888 0 : }
889 :
890 0 : void libspdm_register_session_state_callback_func(
891 : void *spdm_context,
892 : libspdm_session_state_callback_func spdm_session_state_callback)
893 : {
894 : libspdm_context_t *context;
895 :
896 0 : LIBSPDM_ASSERT(spdm_context != NULL);
897 :
898 0 : context = spdm_context;
899 :
900 0 : context->spdm_session_state_callback = (void *)spdm_session_state_callback;
901 0 : }
902 :
903 0 : void libspdm_register_connection_state_callback_func(
904 : void *spdm_context,
905 : libspdm_connection_state_callback_func spdm_connection_state_callback)
906 : {
907 : libspdm_context_t *context;
908 :
909 0 : LIBSPDM_ASSERT(spdm_context != NULL);
910 :
911 0 : context = spdm_context;
912 0 : context->spdm_connection_state_callback = (void *)spdm_connection_state_callback;
913 0 : }
914 :
915 0 : void libspdm_register_key_update_callback_func(
916 : void *spdm_context, libspdm_key_update_callback_func spdm_key_update_callback)
917 : {
918 : libspdm_context_t *context;
919 :
920 0 : LIBSPDM_ASSERT(spdm_context != NULL);
921 :
922 0 : context = spdm_context;
923 0 : context->spdm_key_update_callback = (void *)spdm_key_update_callback;
924 0 : }
925 :
926 : #if (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) && (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP) && \
927 : (LIBSPDM_SEND_GET_CERTIFICATE_SUPPORT)
928 109 : void libspdm_register_cert_chain_buffer(
929 : void *spdm_context, void *cert_chain_buffer, size_t cert_chain_buffer_max_size)
930 : {
931 : libspdm_context_t *context;
932 :
933 109 : LIBSPDM_ASSERT(spdm_context != NULL);
934 :
935 109 : context = spdm_context;
936 109 : context->mut_auth_cert_chain_buffer = cert_chain_buffer;
937 109 : context->mut_auth_cert_chain_buffer_max_size = cert_chain_buffer_max_size;
938 109 : context->mut_auth_cert_chain_buffer_size = 0;
939 109 : }
940 : #endif
|