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