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