Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 2021-2025 DMTF. All rights reserved.
4 : * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md
5 : **/
6 :
7 : #include "internal/libspdm_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 32 : 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 32 : 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 32 : result = libspdm_calculate_th_hmac_for_finish_req(
76 : spdm_context, session_info, &hash_size, calc_hmac_data);
77 32 : if (!result) {
78 0 : return false;
79 : }
80 : #endif
81 32 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "th_curr hmac - "));
82 32 : LIBSPDM_INTERNAL_DUMP_DATA(calc_hmac_data, hash_size);
83 32 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
84 :
85 32 : libspdm_copy_mem(hmac, hash_size, calc_hmac_data, hash_size);
86 :
87 32 : 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 35 : 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 35 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
122 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
123 : }
124 :
125 35 : 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 1 : status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
130 1 : goto error;
131 : }
132 :
133 34 : 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 33 : libspdm_get_session_info_via_session_id(spdm_context, session_id);
141 33 : if (session_info == NULL) {
142 0 : LIBSPDM_ASSERT(false);
143 0 : status = LIBSPDM_STATUS_INVALID_STATE_LOCAL;
144 0 : goto error;
145 : }
146 33 : session_state = libspdm_secured_message_get_session_state(
147 : session_info->secured_message_context);
148 33 : if (session_state != LIBSPDM_SESSION_STATE_HANDSHAKING) {
149 1 : status = LIBSPDM_STATUS_INVALID_STATE_LOCAL;
150 1 : goto error;
151 : }
152 :
153 32 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
154 32 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
155 32 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
156 0 : return status;
157 : }
158 32 : LIBSPDM_ASSERT (message_size >= transport_header_size +
159 : spdm_context->local_context.capability.transport_tail_size);
160 32 : spdm_request = (void *)(message + transport_header_size);
161 32 : spdm_request_size = message_size - transport_header_size -
162 32 : spdm_context->local_context.capability.transport_tail_size;
163 :
164 32 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_request->header));
165 32 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
166 32 : spdm_request->header.request_response_code = SPDM_PSK_FINISH;
167 32 : spdm_request->header.param1 = 0;
168 32 : spdm_request->header.param2 = 0;
169 :
170 32 : ptr = (uint8_t *)spdm_request + sizeof(spdm_psk_finish_request_t);
171 32 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) {
172 1 : if (requester_opaque_data != NULL) {
173 0 : LIBSPDM_ASSERT(requester_opaque_data_size <= SPDM_MAX_OPAQUE_DATA_SIZE);
174 0 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_psk_finish_request_t) +
175 : sizeof(uint16_t) + requester_opaque_data_size);
176 :
177 0 : libspdm_write_uint16(ptr, (uint16_t)requester_opaque_data_size);
178 0 : ptr += sizeof(uint16_t);
179 :
180 0 : 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 0 : opaque_data_size = requester_opaque_data_size;
185 : } else {
186 1 : opaque_data_size = 0;
187 1 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_psk_finish_request_t) +
188 : sizeof(uint16_t) + opaque_data_size);
189 :
190 1 : libspdm_write_uint16(ptr, (uint16_t)opaque_data_size);
191 1 : ptr += sizeof(uint16_t);
192 : }
193 1 : ptr += opaque_data_size;
194 1 : opaque_data_entry_size = sizeof(uint16_t) + opaque_data_size;
195 : } else {
196 31 : opaque_data_entry_size = 0;
197 : }
198 :
199 32 : hmac_size = libspdm_get_hash_size(
200 : spdm_context->connection_info.algorithm.base_hash_algo);
201 32 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_request->header) +
202 : opaque_data_entry_size + hmac_size);
203 32 : spdm_request_size = sizeof(spdm_psk_finish_request_t) + opaque_data_entry_size + hmac_size;
204 :
205 32 : status = libspdm_append_message_f(spdm_context, session_info, true, (uint8_t *)spdm_request,
206 : spdm_request_size - hmac_size);
207 32 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
208 0 : libspdm_release_sender_buffer (spdm_context);
209 0 : goto error;
210 : }
211 :
212 32 : result = libspdm_generate_psk_exchange_req_hmac(spdm_context, session_info,
213 : ptr);
214 32 : if (!result) {
215 0 : libspdm_release_sender_buffer (spdm_context);
216 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
217 0 : goto error;
218 : }
219 :
220 32 : status = libspdm_append_message_f(spdm_context, session_info, true,
221 : (uint8_t *)spdm_request +
222 32 : spdm_request_size - hmac_size,
223 : hmac_size);
224 32 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
225 0 : libspdm_release_sender_buffer (spdm_context);
226 0 : goto error;
227 : }
228 :
229 32 : status = libspdm_send_spdm_request(spdm_context, &session_id,
230 : spdm_request_size, spdm_request);
231 32 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
232 1 : libspdm_release_sender_buffer (spdm_context);
233 1 : goto error;
234 : }
235 :
236 31 : libspdm_reset_message_buffer_via_request_code(spdm_context, session_info,
237 : SPDM_PSK_FINISH);
238 :
239 31 : libspdm_release_sender_buffer (spdm_context);
240 31 : spdm_request = (void *)spdm_context->last_spdm_request;
241 :
242 : /* receive */
243 :
244 31 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
245 31 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
246 0 : goto error;
247 : }
248 31 : LIBSPDM_ASSERT (message_size >= transport_header_size);
249 31 : spdm_response = (void *)(message);
250 31 : spdm_response_size = message_size;
251 :
252 31 : status = libspdm_receive_spdm_response(
253 : spdm_context, &session_id, &spdm_response_size, (void **)&spdm_response);
254 31 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
255 0 : goto receive_done;
256 : }
257 31 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
258 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
259 0 : goto receive_done;
260 : }
261 31 : 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 6 : } 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 6 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
279 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
280 0 : goto receive_done;
281 : }
282 :
283 6 : ptr = (uint8_t *)spdm_response + sizeof(spdm_psk_finish_response_t);
284 :
285 6 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) {
286 1 : 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 1 : opaque_data_size = libspdm_read_uint16((const uint8_t *)ptr);
291 1 : ptr += sizeof(uint16_t);
292 1 : if (opaque_data_size > SPDM_MAX_OPAQUE_DATA_SIZE) {
293 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
294 0 : goto receive_done;
295 : }
296 : /* this message can only be in secured session
297 : * thus don't need to consider transport layer padding, just check its exact size */
298 1 : if (spdm_response_size != sizeof(spdm_psk_finish_response_t) + sizeof(uint16_t) +
299 : opaque_data_size) {
300 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
301 0 : goto receive_done;
302 : }
303 :
304 1 : if ((responder_opaque_data != NULL) && (responder_opaque_data_size != NULL)) {
305 0 : if (opaque_data_size >= *responder_opaque_data_size) {
306 0 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
307 0 : goto receive_done;
308 : }
309 0 : libspdm_copy_mem(responder_opaque_data, *responder_opaque_data_size,
310 : ptr, opaque_data_size);
311 0 : *responder_opaque_data_size = opaque_data_size;
312 : }
313 :
314 1 : ptr += opaque_data_size;
315 1 : opaque_data_entry_size = sizeof(uint16_t) + opaque_data_size;
316 : } else {
317 : /* this message can only be in secured session
318 : * thus don't need to consider transport layer padding, just check its exact size */
319 5 : if (spdm_response_size != sizeof(spdm_psk_finish_response_t)) {
320 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
321 0 : goto receive_done;
322 : }
323 5 : if ((responder_opaque_data != NULL) && (responder_opaque_data_size != NULL)) {
324 0 : *responder_opaque_data_size = 0;
325 : }
326 5 : opaque_data_entry_size = 0;
327 : }
328 6 : spdm_response_size = sizeof(spdm_finish_response_t) + opaque_data_entry_size;
329 :
330 6 : status = libspdm_append_message_f(spdm_context, session_info, true, spdm_response,
331 : spdm_response_size);
332 6 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
333 0 : goto receive_done;
334 : }
335 :
336 6 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "libspdm_generate_session_data_key[%x]\n", session_id));
337 6 : result = libspdm_calculate_th2_hash(spdm_context, session_info, true,
338 : th2_hash_data);
339 6 : if (!result) {
340 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
341 0 : goto receive_done;
342 : }
343 6 : result = libspdm_generate_session_data_key(
344 : session_info->secured_message_context, th2_hash_data);
345 6 : if (!result) {
346 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
347 0 : goto receive_done;
348 : }
349 :
350 6 : libspdm_secured_message_set_session_state(
351 : session_info->secured_message_context,
352 : LIBSPDM_SESSION_STATE_ESTABLISHED);
353 :
354 : /* -=[Log Message Phase]=- */
355 : #if LIBSPDM_ENABLE_MSG_LOG
356 6 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
357 : #endif /* LIBSPDM_ENABLE_MSG_LOG */
358 :
359 6 : libspdm_release_receiver_buffer (spdm_context);
360 6 : return LIBSPDM_STATUS_SUCCESS;
361 :
362 25 : receive_done:
363 25 : libspdm_release_receiver_buffer (spdm_context);
364 29 : error:
365 29 : if (LIBSPDM_STATUS_BUSY_PEER != status) {
366 27 : libspdm_free_session_id(spdm_context, session_id);
367 : }
368 29 : return status;
369 : }
370 :
371 34 : libspdm_return_t libspdm_send_receive_psk_finish(libspdm_context_t *spdm_context,
372 : uint32_t session_id)
373 : {
374 : size_t retry;
375 : uint64_t retry_delay_time;
376 : libspdm_return_t status;
377 :
378 34 : spdm_context->crypto_request = true;
379 34 : retry = spdm_context->retry_times;
380 34 : retry_delay_time = spdm_context->retry_delay_time;
381 : do {
382 35 : status = libspdm_try_send_receive_psk_finish(spdm_context,
383 : session_id,
384 : NULL, 0, NULL, NULL);
385 35 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
386 33 : return status;
387 : }
388 :
389 2 : libspdm_sleep(retry_delay_time);
390 2 : } while (retry-- != 0);
391 :
392 1 : return status;
393 : }
394 :
395 0 : libspdm_return_t libspdm_send_receive_psk_finish_ex(
396 : libspdm_context_t *spdm_context,
397 : uint32_t session_id,
398 : const void *requester_opaque_data,
399 : size_t requester_opaque_data_size,
400 : void *responder_opaque_data,
401 : size_t *responder_opaque_data_size)
402 : {
403 : size_t retry;
404 : uint64_t retry_delay_time;
405 : libspdm_return_t status;
406 :
407 0 : spdm_context->crypto_request = true;
408 0 : retry = spdm_context->retry_times;
409 0 : retry_delay_time = spdm_context->retry_delay_time;
410 : do {
411 0 : status = libspdm_try_send_receive_psk_finish(spdm_context,
412 : session_id,
413 : requester_opaque_data,
414 : requester_opaque_data_size,
415 : responder_opaque_data,
416 : responder_opaque_data_size);
417 0 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
418 0 : return status;
419 : }
420 :
421 0 : libspdm_sleep(retry_delay_time);
422 0 : } while (retry-- != 0);
423 :
424 0 : return status;
425 : }
426 :
427 : #endif /* LIBSPDM_ENABLE_CAPABILITY_PSK_CAP*/
|