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_requester_lib.h"
8 : : #include "internal/libspdm_secured_message_lib.h"
9 : :
10 : : #if LIBSPDM_ENABLE_CAPABILITY_PSK_CAP
11 : :
12 : : #pragma pack(1)
13 : : typedef struct {
14 : : spdm_message_header_t header;
15 : : uint16_t opaque_length;
16 : : uint8_t opaque_data[SPDM_MAX_OPAQUE_DATA_SIZE];
17 : : uint8_t verify_data[LIBSPDM_MAX_HASH_SIZE];
18 : : } libspdm_psk_finish_request_mine_t;
19 : :
20 : : typedef struct {
21 : : spdm_message_header_t header;
22 : : uint16_t opaque_length;
23 : : uint8_t opaque_data[SPDM_MAX_OPAQUE_DATA_SIZE];
24 : : } libspdm_psk_finish_response_max_t;
25 : : #pragma pack()
26 : :
27 : : /**
28 : : * This function generates the PSK finish HMAC based upon TH.
29 : : *
30 : : * @param spdm_context A pointer to the SPDM context.
31 : : * @param session_info The session info of an SPDM session.
32 : : * @param hmac The buffer to store the finish HMAC.
33 : : *
34 : : * @retval true PSK finish HMAC is generated.
35 : : * @retval false PSK finish HMAC is not generated.
36 : : **/
37 : 40 : bool libspdm_generate_psk_exchange_req_hmac(libspdm_context_t *spdm_context,
38 : : libspdm_session_info_t *session_info,
39 : : void *hmac)
40 : : {
41 : : size_t hash_size;
42 : : uint8_t calc_hmac_data[LIBSPDM_MAX_HASH_SIZE];
43 : : bool result;
44 : : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
45 : : uint8_t *th_curr_data;
46 : : size_t th_curr_data_size;
47 : : libspdm_th_managed_buffer_t th_curr;
48 : : uint8_t hash_data[LIBSPDM_MAX_HASH_SIZE];
49 : : #endif
50 : :
51 : 40 : hash_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
52 : :
53 : : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
54 : : result = libspdm_calculate_th_for_finish(spdm_context, session_info, NULL,
55 : : 0, NULL, 0, &th_curr);
56 : : if (!result) {
57 : : return false;
58 : : }
59 : : th_curr_data = libspdm_get_managed_buffer(&th_curr);
60 : : th_curr_data_size = libspdm_get_managed_buffer_size(&th_curr);
61 : :
62 : : result = libspdm_hash_all (spdm_context->connection_info.algorithm.base_hash_algo,
63 : : th_curr_data, th_curr_data_size, hash_data);
64 : : if (!result) {
65 : : return false;
66 : : }
67 : :
68 : : result = libspdm_hmac_all_with_request_finished_key(
69 : : session_info->secured_message_context, hash_data,
70 : : hash_size, calc_hmac_data);
71 : : if (!result) {
72 : : return false;
73 : : }
74 : : #else
75 : 40 : result = libspdm_calculate_th_hmac_for_finish_req(
76 : : spdm_context, session_info, &hash_size, calc_hmac_data);
77 [ - + ]: 40 : if (!result) {
78 : 0 : return false;
79 : : }
80 : : #endif
81 : 40 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "th_curr hmac - "));
82 : 40 : LIBSPDM_INTERNAL_DUMP_DATA(calc_hmac_data, hash_size);
83 : 40 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
84 : :
85 : 40 : libspdm_copy_mem(hmac, hash_size, calc_hmac_data, hash_size);
86 : :
87 : 40 : return true;
88 : : }
89 : :
90 : : /**
91 : : * This function sends PSK_FINISH and receives PSK_FINISH_RSP for SPDM PSK finish.
92 : : *
93 : : * @param spdm_context A pointer to the SPDM context.
94 : : * @param session_id session_id to the PSK_FINISH request.
95 : : **/
96 : 44 : static libspdm_return_t libspdm_try_send_receive_psk_finish(
97 : : libspdm_context_t *spdm_context,
98 : : uint32_t session_id,
99 : : const void *requester_opaque_data,
100 : : size_t requester_opaque_data_size,
101 : : void *responder_opaque_data,
102 : : size_t *responder_opaque_data_size)
103 : : {
104 : : libspdm_return_t status;
105 : : libspdm_psk_finish_request_mine_t *spdm_request;
106 : : size_t spdm_request_size;
107 : : size_t hmac_size;
108 : : libspdm_psk_finish_response_max_t *spdm_response;
109 : : size_t spdm_response_size;
110 : : libspdm_session_info_t *session_info;
111 : : uint8_t th2_hash_data[LIBSPDM_MAX_HASH_SIZE];
112 : : libspdm_session_state_t session_state;
113 : : bool result;
114 : : uint8_t *message;
115 : : size_t message_size;
116 : : size_t transport_header_size;
117 : : uint8_t *ptr;
118 : : size_t opaque_data_entry_size;
119 : : size_t opaque_data_size;
120 : :
121 [ - + ]: 44 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
122 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
123 : : }
124 : :
125 [ + + ]: 44 : if (!libspdm_is_capabilities_flag_supported(
126 : : spdm_context, true,
127 : : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PSK_CAP,
128 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP_RESPONDER_WITH_CONTEXT)) {
129 : 2 : status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
130 : 2 : goto error;
131 : : }
132 : :
133 [ + + ]: 42 : if (spdm_context->connection_info.connection_state <
134 : : LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
135 : 1 : status = LIBSPDM_STATUS_INVALID_STATE_LOCAL;
136 : 1 : goto error;
137 : : }
138 : :
139 : : session_info =
140 : 41 : libspdm_get_session_info_via_session_id(spdm_context, session_id);
141 [ - + ]: 41 : if (session_info == NULL) {
142 : 0 : LIBSPDM_ASSERT(false);
143 : 0 : status = LIBSPDM_STATUS_INVALID_STATE_LOCAL;
144 : 0 : goto error;
145 : : }
146 : 41 : session_state = libspdm_secured_message_get_session_state(
147 : : session_info->secured_message_context);
148 [ + + ]: 41 : if (session_state != LIBSPDM_SESSION_STATE_HANDSHAKING) {
149 : 1 : status = LIBSPDM_STATUS_INVALID_STATE_LOCAL;
150 : 1 : goto error;
151 : : }
152 : :
153 : 40 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
154 : 40 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
155 [ - + ]: 40 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
156 : 0 : return status;
157 : : }
158 [ - + ]: 40 : LIBSPDM_ASSERT (message_size >= transport_header_size +
159 : : spdm_context->local_context.capability.transport_tail_size);
160 : 40 : spdm_request = (void *)(message + transport_header_size);
161 : 40 : spdm_request_size = message_size - transport_header_size -
162 : 40 : spdm_context->local_context.capability.transport_tail_size;
163 : :
164 [ - + ]: 40 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_request->header));
165 : 40 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
166 : 40 : spdm_request->header.request_response_code = SPDM_PSK_FINISH;
167 : 40 : spdm_request->header.param1 = 0;
168 : 40 : spdm_request->header.param2 = 0;
169 : :
170 : 40 : ptr = (uint8_t *)spdm_request + sizeof(spdm_psk_finish_request_t);
171 [ + + ]: 40 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) {
172 [ + + ]: 4 : if (requester_opaque_data != NULL) {
173 [ - + ]: 2 : LIBSPDM_ASSERT(requester_opaque_data_size <= SPDM_MAX_OPAQUE_DATA_SIZE);
174 [ - + ]: 2 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_psk_finish_request_t) +
175 : : sizeof(uint16_t) + requester_opaque_data_size);
176 : :
177 : 2 : libspdm_write_uint16(ptr, (uint16_t)requester_opaque_data_size);
178 : 2 : ptr += sizeof(uint16_t);
179 : :
180 : 2 : libspdm_copy_mem(ptr,
181 : : (spdm_request_size - (sizeof(spdm_psk_finish_request_t) +
182 : : sizeof(uint16_t))),
183 : : requester_opaque_data, requester_opaque_data_size);
184 : 2 : opaque_data_size = requester_opaque_data_size;
185 : : } else {
186 : 2 : opaque_data_size = 0;
187 [ - + ]: 2 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_psk_finish_request_t) +
188 : : sizeof(uint16_t) + opaque_data_size);
189 : :
190 : 2 : libspdm_write_uint16(ptr, (uint16_t)opaque_data_size);
191 : 2 : ptr += sizeof(uint16_t);
192 : : }
193 : 4 : ptr += opaque_data_size;
194 : 4 : opaque_data_entry_size = sizeof(uint16_t) + opaque_data_size;
195 : : } else {
196 : 36 : opaque_data_entry_size = 0;
197 : : }
198 : :
199 : 40 : hmac_size = libspdm_get_hash_size(
200 : : spdm_context->connection_info.algorithm.base_hash_algo);
201 [ - + ]: 40 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_request->header) +
202 : : opaque_data_entry_size + hmac_size);
203 : 40 : spdm_request_size = sizeof(spdm_psk_finish_request_t) + opaque_data_entry_size + hmac_size;
204 : :
205 : 40 : status = libspdm_append_message_f(spdm_context, session_info, true, (uint8_t *)spdm_request,
206 : : spdm_request_size - hmac_size);
207 [ - + ]: 40 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
208 : 0 : libspdm_release_sender_buffer (spdm_context);
209 : 0 : goto error;
210 : : }
211 : :
212 : 40 : result = libspdm_generate_psk_exchange_req_hmac(spdm_context, session_info,
213 : : ptr);
214 [ - + ]: 40 : if (!result) {
215 : 0 : libspdm_release_sender_buffer (spdm_context);
216 : 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
217 : 0 : goto error;
218 : : }
219 : :
220 : 40 : status = libspdm_append_message_f(spdm_context, session_info, true,
221 : : (uint8_t *)spdm_request +
222 : 40 : spdm_request_size - hmac_size,
223 : : hmac_size);
224 [ - + ]: 40 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
225 : 0 : libspdm_release_sender_buffer (spdm_context);
226 : 0 : goto error;
227 : : }
228 : :
229 : 40 : status = libspdm_send_spdm_request(spdm_context, &session_id,
230 : : spdm_request_size, spdm_request);
231 [ + + ]: 40 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
232 : 1 : libspdm_release_sender_buffer (spdm_context);
233 : 1 : goto error;
234 : : }
235 : :
236 : 39 : libspdm_reset_message_buffer_via_request_code(spdm_context, session_info,
237 : : SPDM_PSK_FINISH);
238 : :
239 : 39 : libspdm_release_sender_buffer (spdm_context);
240 : 39 : spdm_request = (void *)spdm_context->last_spdm_request;
241 : :
242 : : /* receive */
243 : :
244 : 39 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
245 [ - + ]: 39 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
246 : 0 : goto error;
247 : : }
248 [ - + ]: 39 : LIBSPDM_ASSERT (message_size >= transport_header_size);
249 : 39 : spdm_response = (void *)(message);
250 : 39 : spdm_response_size = message_size;
251 : :
252 : 39 : status = libspdm_receive_spdm_response(
253 : : spdm_context, &session_id, &spdm_response_size, (void **)&spdm_response);
254 [ - + ]: 39 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
255 : 0 : goto receive_done;
256 : : }
257 [ - + ]: 39 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
258 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
259 : 0 : goto receive_done;
260 : : }
261 [ + + ]: 39 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
262 [ + + ]: 25 : if (spdm_response->header.param1 == SPDM_ERROR_CODE_DECRYPT_ERROR) {
263 : 2 : status = LIBSPDM_STATUS_SESSION_MSG_ERROR;
264 : 2 : goto receive_done;
265 : : }
266 : 23 : status = libspdm_handle_error_response_main(
267 : : spdm_context, &session_id,
268 : : &spdm_response_size, (void **)&spdm_response,
269 : : SPDM_PSK_FINISH, SPDM_PSK_FINISH_RSP);
270 [ + + ]: 23 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
271 : 22 : goto receive_done;
272 : : }
273 [ + + ]: 14 : } else if (spdm_response->header.request_response_code !=
274 : : SPDM_PSK_FINISH_RSP) {
275 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
276 : 1 : goto receive_done;
277 : : }
278 [ + + ]: 14 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
279 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
280 : 1 : goto receive_done;
281 : : }
282 : :
283 : 13 : ptr = (uint8_t *)spdm_response + sizeof(spdm_psk_finish_response_t);
284 : :
285 [ + + ]: 13 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) {
286 [ - + ]: 4 : if (spdm_response_size < sizeof(spdm_psk_finish_response_t) + sizeof(uint16_t)) {
287 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
288 : 0 : goto receive_done;
289 : : }
290 : 4 : opaque_data_size = libspdm_read_uint16((const uint8_t *)ptr);
291 : 4 : ptr += sizeof(uint16_t);
292 [ + + ]: 4 : if (opaque_data_size > SPDM_MAX_OPAQUE_DATA_SIZE) {
293 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
294 : 1 : goto receive_done;
295 : : }
296 : :
297 : : /* this message can only be in secured session
298 : : * thus don't need to consider transport layer padding, just check its exact size */
299 [ - + ]: 3 : if (spdm_response_size != sizeof(spdm_psk_finish_response_t) + sizeof(uint16_t) +
300 : : opaque_data_size) {
301 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
302 : 0 : goto receive_done;
303 : : }
304 : :
305 [ + + + - ]: 3 : if ((responder_opaque_data != NULL) && (responder_opaque_data_size != NULL)) {
306 [ + + ]: 2 : if (opaque_data_size > *responder_opaque_data_size) {
307 : 1 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
308 : 1 : goto receive_done;
309 : : }
310 : 1 : libspdm_copy_mem(responder_opaque_data, *responder_opaque_data_size,
311 : : ptr, opaque_data_size);
312 : 1 : *responder_opaque_data_size = opaque_data_size;
313 : : }
314 : :
315 : 2 : ptr += opaque_data_size;
316 : 2 : opaque_data_entry_size = sizeof(uint16_t) + opaque_data_size;
317 : : } else {
318 : : /* this message can only be in secured session
319 : : * thus don't need to consider transport layer padding, just check its exact size */
320 [ - + ]: 9 : if (spdm_response_size != sizeof(spdm_psk_finish_response_t)) {
321 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
322 : 0 : goto receive_done;
323 : : }
324 [ + + + - ]: 9 : if ((responder_opaque_data != NULL) && (responder_opaque_data_size != NULL)) {
325 : 1 : *responder_opaque_data_size = 0;
326 : : }
327 : 9 : opaque_data_entry_size = 0;
328 : : }
329 : 11 : spdm_response_size = sizeof(spdm_psk_finish_response_t) + opaque_data_entry_size;
330 : :
331 : 11 : status = libspdm_append_message_f(spdm_context, session_info, true, spdm_response,
332 : : spdm_response_size);
333 [ - + ]: 11 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
334 : 0 : goto receive_done;
335 : : }
336 : :
337 : 11 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "libspdm_generate_session_data_key[%x]\n", session_id));
338 : 11 : result = libspdm_calculate_th2_hash(spdm_context, session_info, true,
339 : : th2_hash_data);
340 [ - + ]: 11 : if (!result) {
341 : 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
342 : 0 : goto receive_done;
343 : : }
344 : 11 : result = libspdm_generate_session_data_key(
345 : : session_info->secured_message_context, th2_hash_data);
346 [ - + ]: 11 : if (!result) {
347 : 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
348 : 0 : goto receive_done;
349 : : }
350 : :
351 : 11 : libspdm_secured_message_set_session_state(
352 : : session_info->secured_message_context,
353 : : LIBSPDM_SESSION_STATE_ESTABLISHED);
354 : :
355 : : /* -=[Log Message Phase]=- */
356 : : #if LIBSPDM_ENABLE_MSG_LOG
357 : 11 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
358 : : #endif /* LIBSPDM_ENABLE_MSG_LOG */
359 : :
360 : 11 : libspdm_release_receiver_buffer (spdm_context);
361 : 11 : return LIBSPDM_STATUS_SUCCESS;
362 : :
363 : 28 : receive_done:
364 : 28 : libspdm_release_receiver_buffer (spdm_context);
365 : 33 : error:
366 [ + + ]: 33 : if (LIBSPDM_STATUS_BUSY_PEER != status) {
367 : 31 : libspdm_free_session_id(spdm_context, session_id);
368 : : }
369 : 33 : return status;
370 : : }
371 : :
372 : 38 : libspdm_return_t libspdm_send_receive_psk_finish(libspdm_context_t *spdm_context,
373 : : uint32_t session_id)
374 : : {
375 : : size_t retry;
376 : : uint64_t retry_delay_time;
377 : : libspdm_return_t status;
378 : :
379 : 38 : spdm_context->crypto_request = true;
380 : 38 : retry = spdm_context->retry_times;
381 : 38 : retry_delay_time = spdm_context->retry_delay_time;
382 : : do {
383 : 39 : status = libspdm_try_send_receive_psk_finish(spdm_context,
384 : : session_id,
385 : : NULL, 0, NULL, NULL);
386 [ + + ]: 39 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
387 : 37 : return status;
388 : : }
389 : :
390 : 2 : libspdm_sleep(retry_delay_time);
391 [ + + ]: 2 : } while (retry-- != 0);
392 : :
393 : 1 : return status;
394 : : }
395 : :
396 : 5 : libspdm_return_t libspdm_send_receive_psk_finish_ex(
397 : : libspdm_context_t *spdm_context,
398 : : uint32_t session_id,
399 : : const void *requester_opaque_data,
400 : : size_t requester_opaque_data_size,
401 : : void *responder_opaque_data,
402 : : size_t *responder_opaque_data_size)
403 : : {
404 : : size_t retry;
405 : : uint64_t retry_delay_time;
406 : : libspdm_return_t status;
407 : :
408 : 5 : spdm_context->crypto_request = true;
409 : 5 : retry = spdm_context->retry_times;
410 : 5 : retry_delay_time = spdm_context->retry_delay_time;
411 : : do {
412 : 5 : status = libspdm_try_send_receive_psk_finish(spdm_context,
413 : : session_id,
414 : : requester_opaque_data,
415 : : requester_opaque_data_size,
416 : : responder_opaque_data,
417 : : responder_opaque_data_size);
418 [ + - ]: 5 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
419 : 5 : return status;
420 : : }
421 : :
422 : 0 : libspdm_sleep(retry_delay_time);
423 [ # # ]: 0 : } while (retry-- != 0);
424 : :
425 : 0 : return status;
426 : : }
427 : :
428 : : #endif /* LIBSPDM_ENABLE_CAPABILITY_PSK_CAP*/
|