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