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 req_session_id;
16 : uint16_t psk_hint_length;
17 : uint16_t context_length;
18 : uint16_t opaque_length;
19 : uint8_t psk_hint[LIBSPDM_PSK_MAX_HINT_LENGTH];
20 : uint8_t context[LIBSPDM_PSK_CONTEXT_LENGTH];
21 : uint8_t opaque_data[SPDM_MAX_OPAQUE_DATA_SIZE];
22 : } libspdm_psk_exchange_request_mine_t;
23 :
24 : typedef struct {
25 : spdm_message_header_t header;
26 : uint16_t rsp_session_id;
27 : uint16_t reserved;
28 : uint16_t context_length;
29 : uint16_t opaque_length;
30 : uint8_t measurement_summary_hash[LIBSPDM_MAX_HASH_SIZE];
31 : uint8_t context[LIBSPDM_PSK_CONTEXT_LENGTH];
32 : uint8_t opaque_data[SPDM_MAX_OPAQUE_DATA_SIZE];
33 : uint8_t verify_data[LIBSPDM_MAX_HASH_SIZE];
34 : } libspdm_psk_exchange_response_max_t;
35 : #pragma pack()
36 :
37 16 : bool libspdm_verify_psk_exchange_rsp_hmac(libspdm_context_t *spdm_context,
38 : libspdm_session_info_t *session_info,
39 : const void *hmac_data,
40 : size_t hmac_data_size)
41 : {
42 : size_t hash_size;
43 : uint8_t calc_hmac_data[LIBSPDM_MAX_HASH_SIZE];
44 : bool result;
45 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
46 : uint8_t *th_curr_data;
47 : size_t th_curr_data_size;
48 : libspdm_th_managed_buffer_t th_curr;
49 : uint8_t hash_data[LIBSPDM_MAX_HASH_SIZE];
50 : #endif
51 :
52 16 : hash_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
53 16 : LIBSPDM_ASSERT(hash_size == hmac_data_size);
54 :
55 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
56 : result = libspdm_calculate_th_for_exchange(spdm_context, session_info,
57 : NULL, 0, &th_curr);
58 : if (!result) {
59 : return false;
60 : }
61 : th_curr_data = libspdm_get_managed_buffer(&th_curr);
62 : th_curr_data_size = libspdm_get_managed_buffer_size(&th_curr);
63 :
64 : result = libspdm_hash_all (spdm_context->connection_info.algorithm.base_hash_algo,
65 : th_curr_data, th_curr_data_size, hash_data);
66 : if (!result) {
67 : return false;
68 : }
69 :
70 : result = libspdm_hmac_all_with_response_finished_key(
71 : session_info->secured_message_context, hash_data,
72 : hash_size, calc_hmac_data);
73 : if (!result) {
74 : return false;
75 : }
76 : #else
77 16 : result = libspdm_calculate_th_hmac_for_exchange_rsp(
78 : spdm_context, session_info, &hash_size, calc_hmac_data);
79 16 : if (!result) {
80 0 : return false;
81 : }
82 : #endif
83 16 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "th_curr hmac - "));
84 16 : LIBSPDM_INTERNAL_DUMP_DATA(calc_hmac_data, hash_size);
85 16 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
86 :
87 16 : if (!libspdm_consttime_is_mem_equal(calc_hmac_data, hmac_data, hash_size)) {
88 1 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "!!! verify_psk_exchange_rsp_hmac - FAIL !!!\n"));
89 1 : return false;
90 : }
91 15 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "!!! verify_psk_exchange_rsp_hmac - PASS !!!\n"));
92 :
93 15 : return true;
94 : }
95 :
96 : /**
97 : * This function sends PSK_EXCHANGE and receives PSK_EXCHANGE_RSP for SPDM PSK exchange.
98 : *
99 : * @param spdm_context A pointer to the SPDM context.
100 : * @param measurement_hash_type measurement_hash_type to the PSK_EXCHANGE request.
101 : * @param session_policy The policy for the session.
102 : * @param session_id session_id from the PSK_EXCHANGE_RSP response.
103 : * @param heartbeat_period heartbeat_period from the PSK_EXCHANGE_RSP response.
104 : * @param measurement_hash measurement_hash from the PSK_EXCHANGE_RSP response.
105 : * @param requester_context_in A buffer to hold the requester context as input, if not NULL.
106 : * @param requester_context_in_size The size of requester_context_in.
107 : * It must be 32 bytes at least, but not exceed LIBSPDM_PSK_CONTEXT_LENGTH.
108 : * @param requester_context A buffer to hold the requester context, if not NULL.
109 : * @param requester_context_size On input, the size of requester_context buffer.
110 : * On output, the size of data returned in requester_context buffer.
111 : * It must be 32 bytes at least.
112 : * @param responder_context A buffer to hold the responder context, if not NULL.
113 : * @param responder_context_size On input, the size of requester_context buffer.
114 : * On output, the size of data returned in requester_context buffer.
115 : * It could be 0 if device does not support context.
116 : * @param opaque_data A buffer to hold the responder opaque data, if not NULL.
117 : * @param responder_opaque_data_size On input, the size of the opaque data buffer.
118 : * Responder opaque data should be less than 1024 bytes.
119 : * On output, the size of the opaque data.
120 : **/
121 45 : static libspdm_return_t libspdm_try_send_receive_psk_exchange(
122 : libspdm_context_t *spdm_context,
123 : const void *psk_hint, uint16_t psk_hint_size,
124 : uint8_t measurement_hash_type,
125 : uint8_t session_policy,
126 : uint32_t *session_id, uint8_t *heartbeat_period,
127 : void *measurement_hash,
128 : const void *requester_context_in,
129 : size_t requester_context_in_size,
130 : void *requester_context,
131 : size_t *requester_context_size,
132 : void *responder_context,
133 : size_t *responder_context_size,
134 : const void *requester_opaque_data,
135 : size_t requester_opaque_data_size,
136 : void *responder_opaque_data,
137 : size_t *responder_opaque_data_size)
138 : {
139 : bool result;
140 : libspdm_return_t status;
141 : libspdm_psk_exchange_request_mine_t *spdm_request;
142 : size_t spdm_request_size;
143 : libspdm_psk_exchange_response_max_t *spdm_response;
144 : size_t spdm_response_size;
145 : uint32_t measurement_summary_hash_size;
146 : uint32_t hmac_size;
147 : uint8_t *ptr;
148 : void *measurement_summary_hash;
149 : uint8_t *verify_data;
150 : uint16_t req_session_id;
151 : uint16_t rsp_session_id;
152 : libspdm_session_info_t *session_info;
153 : size_t opaque_psk_exchange_req_size;
154 : uint8_t th1_hash_data[LIBSPDM_MAX_HASH_SIZE];
155 : uint8_t th2_hash_data[LIBSPDM_MAX_HASH_SIZE];
156 : uint32_t algo_size;
157 : uint8_t *message;
158 : size_t message_size;
159 : size_t transport_header_size;
160 : spdm_version_number_t secured_message_version;
161 : spdm_version_number_t local_max_secured_version;
162 45 : uint8_t peer_aead_limit_exponent = SECURED_MESSAGE_AEAD_LIMIT_EXPONENT_DEFAULT;
163 :
164 45 : LIBSPDM_ASSERT(measurement_hash_type == SPDM_PSK_EXCHANGE_REQUEST_NO_MEASUREMENT_SUMMARY_HASH ||
165 : measurement_hash_type == SPDM_PSK_EXCHANGE_REQUEST_TCB_COMPONENT_MEASUREMENT_HASH ||
166 : measurement_hash_type == SPDM_PSK_EXCHANGE_REQUEST_ALL_MEASUREMENTS_HASH);
167 :
168 45 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
169 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
170 : }
171 :
172 : /* Check capabilities even if GET_CAPABILITIES is not sent.
173 : * Assuming capabilities are provisioned.*/
174 45 : if (!libspdm_is_capabilities_flag_supported(
175 : spdm_context, true,
176 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PSK_CAP,
177 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP)) {
178 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
179 : }
180 :
181 : /* While clearing MAC_CAP and setting ENCRYPT_CAP is legal according to DSP0274, libspdm
182 : * also implements DSP0277 secure messages, which requires at least MAC_CAP to be set.
183 : */
184 45 : if (!libspdm_is_capabilities_flag_supported(
185 : spdm_context, true,
186 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MAC_CAP,
187 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MAC_CAP)) {
188 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
189 : }
190 :
191 45 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
192 1 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
193 : }
194 44 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
195 2 : if ((spdm_context->connection_info.algorithm.other_params_support &
196 : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) != SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1) {
197 0 : return LIBSPDM_STATUS_INVALID_STATE_PEER;
198 : }
199 : }
200 :
201 44 : req_session_id = libspdm_allocate_req_session_id(spdm_context, true);
202 44 : if (req_session_id == (INVALID_SESSION_ID & 0xFFFF)) {
203 0 : return LIBSPDM_STATUS_SESSION_NUMBER_EXCEED;
204 : }
205 :
206 44 : libspdm_reset_message_buffer_via_request_code(spdm_context, NULL, SPDM_PSK_EXCHANGE);
207 : {
208 : /* Double check if algorithm has been provisioned, because ALGORITHM might be skipped.*/
209 44 : if (libspdm_is_capabilities_flag_supported(
210 : spdm_context, true, 0,
211 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP)) {
212 14 : if (spdm_context->connection_info.algorithm
213 14 : .measurement_spec !=
214 : SPDM_MEASUREMENT_SPECIFICATION_DMTF) {
215 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
216 : }
217 14 : algo_size = libspdm_get_measurement_hash_size(
218 : spdm_context->connection_info.algorithm.measurement_hash_algo);
219 14 : if (algo_size == 0) {
220 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
221 : }
222 : }
223 44 : algo_size = libspdm_get_hash_size(
224 : spdm_context->connection_info.algorithm.base_hash_algo);
225 44 : if (algo_size == 0) {
226 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
227 : }
228 44 : if (spdm_context->connection_info.algorithm.key_schedule !=
229 : SPDM_ALGORITHMS_KEY_SCHEDULE_SPDM) {
230 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
231 : }
232 : }
233 :
234 44 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
235 44 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
236 44 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
237 0 : return status;
238 : }
239 44 : LIBSPDM_ASSERT (message_size >= transport_header_size +
240 : spdm_context->local_context.capability.transport_tail_size);
241 44 : spdm_request = (void *)(message + transport_header_size);
242 44 : spdm_request_size = message_size - transport_header_size -
243 44 : spdm_context->local_context.capability.transport_tail_size;
244 :
245 44 : LIBSPDM_ASSERT(spdm_request_size >= sizeof(spdm_psk_exchange_request_t) + psk_hint_size);
246 44 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
247 44 : spdm_request->header.request_response_code = SPDM_PSK_EXCHANGE;
248 44 : spdm_request->header.param1 = measurement_hash_type;
249 44 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
250 2 : spdm_request->header.param2 = session_policy;
251 : } else {
252 42 : spdm_request->header.param2 = 0;
253 : }
254 44 : spdm_request->psk_hint_length = psk_hint_size;
255 44 : if (requester_context_in == NULL) {
256 44 : spdm_request->context_length = LIBSPDM_PSK_CONTEXT_LENGTH;
257 : } else {
258 0 : LIBSPDM_ASSERT (requester_context_in_size <= LIBSPDM_PSK_CONTEXT_LENGTH);
259 0 : spdm_request->context_length = (uint16_t)requester_context_in_size;
260 : }
261 :
262 : /* No secured message version is negotiated yet at request time, so the AEADlimitOE element is
263 : * gated on the highest secured message version this endpoint offers. */
264 44 : local_max_secured_version = libspdm_local_max_secured_message_version(spdm_context);
265 :
266 44 : if (requester_opaque_data != NULL) {
267 0 : LIBSPDM_ASSERT(requester_opaque_data_size <= SPDM_MAX_OPAQUE_DATA_SIZE);
268 :
269 0 : opaque_psk_exchange_req_size = (uint16_t)requester_opaque_data_size;
270 : } else {
271 : /* DSP0277 1.3: also advertise this endpoint's AEAD limit in the request opaque data. */
272 44 : opaque_psk_exchange_req_size =
273 88 : libspdm_get_opaque_data_supported_version_data_size(spdm_context) +
274 44 : libspdm_get_opaque_data_aead_limit_element_size(spdm_context,
275 : local_max_secured_version);
276 : }
277 :
278 44 : LIBSPDM_ASSERT(spdm_request_size >= sizeof(spdm_psk_exchange_request_t) + psk_hint_size +
279 : spdm_request->context_length + opaque_psk_exchange_req_size);
280 44 : spdm_request->opaque_length = (uint16_t)opaque_psk_exchange_req_size;
281 :
282 44 : spdm_request->req_session_id = req_session_id;
283 :
284 44 : ptr = spdm_request->psk_hint;
285 44 : if ((psk_hint != NULL) && (psk_hint_size > 0)) {
286 43 : libspdm_copy_mem(ptr, sizeof(spdm_request->psk_hint),
287 : psk_hint,
288 : psk_hint_size);
289 : }
290 44 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "psk_hint (0x%x) - ", spdm_request->psk_hint_length));
291 44 : LIBSPDM_INTERNAL_DUMP_DATA(ptr, spdm_request->psk_hint_length);
292 44 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
293 44 : ptr += spdm_request->psk_hint_length;
294 :
295 44 : if (requester_context_in == NULL) {
296 44 : if (!libspdm_get_random_number(LIBSPDM_PSK_CONTEXT_LENGTH, ptr)) {
297 0 : libspdm_release_sender_buffer (spdm_context);
298 0 : return LIBSPDM_STATUS_LOW_ENTROPY;
299 : }
300 : } else {
301 0 : libspdm_copy_mem(ptr, sizeof(spdm_request->context),
302 0 : requester_context_in, spdm_request->context_length);
303 : }
304 44 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "RequesterContextData (0x%x) - ",
305 : spdm_request->context_length));
306 44 : LIBSPDM_INTERNAL_DUMP_DATA(ptr, spdm_request->context_length);
307 44 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
308 44 : if (requester_context != NULL) {
309 0 : if (*requester_context_size > spdm_request->context_length) {
310 0 : *requester_context_size = spdm_request->context_length;
311 : }
312 0 : libspdm_copy_mem(requester_context, *requester_context_size,
313 : ptr, *requester_context_size);
314 : }
315 44 : ptr += spdm_request->context_length;
316 :
317 44 : if (requester_opaque_data != NULL) {
318 0 : libspdm_copy_mem(ptr, opaque_psk_exchange_req_size,
319 : requester_opaque_data, opaque_psk_exchange_req_size);
320 : } else {
321 44 : size_t supported_version_size =
322 44 : libspdm_get_opaque_data_supported_version_data_size(spdm_context);
323 44 : libspdm_build_opaque_data_supported_version_data(
324 : spdm_context, &supported_version_size, ptr);
325 : /* opaque_psk_exchange_req_size holds the reserved opaque data capacity (supported version +
326 : * AEAD limit); it is the capacity passed to the append below. */
327 44 : libspdm_build_opaque_data_aead_limit_element(
328 : spdm_context, local_max_secured_version, &opaque_psk_exchange_req_size, ptr);
329 : }
330 44 : ptr += opaque_psk_exchange_req_size;
331 :
332 44 : spdm_request_size = (size_t)ptr - (size_t)spdm_request;
333 44 : status = libspdm_send_spdm_request(spdm_context, NULL, spdm_request_size,
334 : spdm_request);
335 44 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
336 1 : libspdm_release_sender_buffer (spdm_context);
337 1 : return status;
338 : }
339 43 : libspdm_release_sender_buffer (spdm_context);
340 43 : spdm_request = (void *)spdm_context->last_spdm_request;
341 :
342 : /* receive */
343 :
344 43 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
345 43 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
346 0 : return status;
347 : }
348 43 : LIBSPDM_ASSERT (message_size >= transport_header_size);
349 43 : spdm_response = (void *)(message);
350 43 : spdm_response_size = message_size;
351 :
352 43 : status = libspdm_receive_spdm_response(
353 : spdm_context, NULL, &spdm_response_size, (void **)&spdm_response);
354 43 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
355 0 : goto receive_done;
356 : }
357 43 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
358 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
359 0 : goto receive_done;
360 : }
361 43 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
362 24 : status = libspdm_handle_error_response_main(
363 : spdm_context, NULL, &spdm_response_size,
364 : (void **)&spdm_response, SPDM_PSK_EXCHANGE,
365 : SPDM_PSK_EXCHANGE_RSP);
366 24 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
367 23 : goto receive_done;
368 : }
369 19 : } else if (spdm_response->header.request_response_code != SPDM_PSK_EXCHANGE_RSP) {
370 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
371 0 : goto receive_done;
372 : }
373 20 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
374 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
375 0 : goto receive_done;
376 : }
377 20 : if (spdm_response_size < sizeof(spdm_psk_exchange_response_t)) {
378 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
379 0 : goto receive_done;
380 : }
381 :
382 20 : if (!libspdm_is_capabilities_flag_supported(
383 : spdm_context, true,
384 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP,
385 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP)) {
386 18 : if (spdm_response->header.param1 != 0) {
387 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
388 1 : goto receive_done;
389 : }
390 : }
391 19 : if (heartbeat_period != NULL) {
392 19 : *heartbeat_period = spdm_response->header.param1;
393 : }
394 :
395 19 : measurement_summary_hash_size = libspdm_get_measurement_summary_hash_size(
396 : spdm_context, true, measurement_hash_type);
397 19 : hmac_size = libspdm_get_hash_size(
398 : spdm_context->connection_info.algorithm.base_hash_algo);
399 :
400 19 : if (spdm_response_size <
401 : sizeof(spdm_psk_exchange_response_t) +
402 19 : spdm_response->context_length + spdm_response->opaque_length +
403 19 : measurement_summary_hash_size + hmac_size) {
404 2 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
405 2 : goto receive_done;
406 : }
407 :
408 17 : ptr = (uint8_t *)spdm_response + sizeof(spdm_psk_exchange_response_t) +
409 17 : measurement_summary_hash_size + spdm_response->context_length;
410 17 : if (spdm_response->opaque_length != 0) {
411 15 : result = libspdm_process_general_opaque_data_check(spdm_context,
412 15 : spdm_response->opaque_length, ptr);
413 15 : if (!result) {
414 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
415 0 : goto receive_done;
416 : }
417 15 : status = libspdm_process_opaque_data_version_selection_data(
418 15 : spdm_context, spdm_response->opaque_length, ptr, &secured_message_version);
419 15 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
420 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
421 1 : goto receive_done;
422 : }
423 : /* DSP0277 1.3: read the Responder's AEAD limit (absent -> default 64). */
424 14 : status = libspdm_process_opaque_data_aead_limit(
425 14 : spdm_context, secured_message_version, spdm_response->opaque_length, ptr,
426 : &peer_aead_limit_exponent);
427 14 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
428 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
429 0 : goto receive_done;
430 : }
431 : }
432 :
433 16 : spdm_response_size = sizeof(spdm_psk_exchange_response_t) +
434 16 : spdm_response->context_length +
435 16 : spdm_response->opaque_length +
436 16 : measurement_summary_hash_size + hmac_size;
437 :
438 16 : ptr = (uint8_t *)(spdm_response->measurement_summary_hash);
439 16 : measurement_summary_hash = ptr;
440 16 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "measurement_summary_hash (0x%x) - ",
441 : measurement_summary_hash_size));
442 16 : LIBSPDM_INTERNAL_DUMP_DATA(measurement_summary_hash,
443 : measurement_summary_hash_size);
444 16 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
445 :
446 16 : ptr += measurement_summary_hash_size;
447 :
448 16 : if (spdm_response->opaque_length > SPDM_MAX_OPAQUE_DATA_SIZE) {
449 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
450 0 : goto receive_done;
451 : }
452 :
453 16 : if (libspdm_is_capabilities_flag_supported(
454 : spdm_context, true, 0,
455 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP_RESPONDER)) {
456 2 : if (spdm_response->context_length != 0) {
457 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
458 0 : goto receive_done;
459 : }
460 : } else {
461 14 : if (spdm_response->context_length == 0) {
462 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
463 0 : goto receive_done;
464 : }
465 : }
466 :
467 16 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "ResponderContextData (0x%x) - ",
468 : spdm_response->context_length));
469 16 : LIBSPDM_INTERNAL_DUMP_DATA(ptr, spdm_response->context_length);
470 16 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
471 16 : if (responder_context != NULL) {
472 0 : if (*responder_context_size > spdm_response->context_length) {
473 0 : *responder_context_size = spdm_response->context_length;
474 : }
475 0 : libspdm_copy_mem(responder_context, *responder_context_size,
476 : ptr, *responder_context_size);
477 : }
478 :
479 16 : ptr += spdm_response->context_length;
480 :
481 16 : if ((responder_opaque_data != NULL) && (responder_opaque_data_size != NULL)) {
482 0 : if (spdm_response->opaque_length >= *responder_opaque_data_size) {
483 0 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
484 0 : goto receive_done;
485 : }
486 0 : libspdm_copy_mem(responder_opaque_data, *responder_opaque_data_size,
487 0 : ptr, spdm_response->opaque_length);
488 0 : *responder_opaque_data_size = spdm_response->opaque_length;
489 : }
490 :
491 16 : ptr += spdm_response->opaque_length;
492 :
493 16 : rsp_session_id = spdm_response->rsp_session_id;
494 16 : *session_id = libspdm_generate_session_id(req_session_id, rsp_session_id);
495 16 : session_info = libspdm_assign_session_id(spdm_context, *session_id, secured_message_version,
496 : true);
497 16 : if (session_info == NULL) {
498 0 : status = LIBSPDM_STATUS_SESSION_NUMBER_EXCEED;
499 0 : goto receive_done;
500 : }
501 16 : libspdm_session_info_set_psk_hint(session_info,
502 : psk_hint,
503 : psk_hint_size);
504 :
505 : /* DSP0277 1.3: program the session's AEAD limit (min of local and peer) when secured message
506 : * version 1.3 was negotiated. */
507 16 : if (libspdm_get_version_from_version_number(secured_message_version) >=
508 : SECURED_SPDM_VERSION_13) {
509 0 : libspdm_apply_aead_limit_to_session(spdm_context, session_info,
510 : peer_aead_limit_exponent);
511 : }
512 :
513 : /* Cache session data*/
514 :
515 16 : status = libspdm_append_message_k(spdm_context, session_info, true, spdm_request,
516 : spdm_request_size);
517 16 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
518 0 : libspdm_free_session_id(spdm_context, *session_id);
519 0 : goto receive_done;
520 : }
521 :
522 16 : status = libspdm_append_message_k(spdm_context, session_info, true, spdm_response,
523 : spdm_response_size - hmac_size);
524 16 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
525 0 : libspdm_free_session_id(spdm_context, *session_id);
526 0 : goto receive_done;
527 : }
528 :
529 16 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "libspdm_generate_session_handshake_key[%x]\n",
530 : *session_id));
531 16 : result = libspdm_calculate_th1_hash(spdm_context, session_info, true,
532 : th1_hash_data);
533 16 : if (!result) {
534 0 : libspdm_free_session_id(spdm_context, *session_id);
535 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
536 0 : goto receive_done;
537 : }
538 16 : result = libspdm_generate_session_handshake_key(
539 : session_info->secured_message_context, th1_hash_data);
540 16 : if (!result) {
541 0 : libspdm_free_session_id(spdm_context, *session_id);
542 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
543 0 : goto receive_done;
544 : }
545 :
546 16 : verify_data = ptr;
547 16 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "verify_data (0x%x):\n", hmac_size));
548 16 : LIBSPDM_INTERNAL_DUMP_HEX(verify_data, hmac_size);
549 16 : result = libspdm_verify_psk_exchange_rsp_hmac(spdm_context, session_info,
550 : verify_data, hmac_size);
551 16 : if (!result) {
552 1 : libspdm_free_session_id(spdm_context, *session_id);
553 1 : status = LIBSPDM_STATUS_VERIF_FAIL;
554 1 : goto receive_done;
555 : }
556 :
557 15 : status = libspdm_append_message_k(spdm_context, session_info, true, verify_data, hmac_size);
558 15 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
559 0 : libspdm_free_session_id(spdm_context, *session_id);
560 0 : goto receive_done;
561 : }
562 :
563 15 : if (measurement_hash != NULL) {
564 15 : libspdm_copy_mem(measurement_hash, measurement_summary_hash_size,
565 : measurement_summary_hash, measurement_summary_hash_size);
566 : }
567 :
568 15 : session_info->session_policy = session_policy;
569 :
570 15 : libspdm_secured_message_set_session_state(
571 : session_info->secured_message_context,
572 : LIBSPDM_SESSION_STATE_HANDSHAKING);
573 :
574 15 : if (!libspdm_is_capabilities_flag_supported(
575 : spdm_context, true, 0,
576 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP_RESPONDER_WITH_CONTEXT)) {
577 : /* No need to send PSK_FINISH, enter application phase directly.*/
578 :
579 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "libspdm_generate_session_data_key[%x]\n",
580 : *session_id));
581 2 : result = libspdm_calculate_th2_hash(spdm_context, session_info,
582 : true, th2_hash_data);
583 2 : if (!result) {
584 0 : libspdm_free_session_id(spdm_context, *session_id);
585 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
586 0 : goto receive_done;
587 : }
588 2 : result = libspdm_generate_session_data_key(
589 : session_info->secured_message_context, th2_hash_data);
590 2 : if (!result) {
591 0 : libspdm_free_session_id(spdm_context, *session_id);
592 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
593 0 : goto receive_done;
594 : }
595 :
596 2 : libspdm_secured_message_set_session_state(
597 : session_info->secured_message_context,
598 : LIBSPDM_SESSION_STATE_ESTABLISHED);
599 : }
600 :
601 15 : session_info->heartbeat_period = spdm_response->header.param1;
602 :
603 : /* -=[Log Message Phase]=- */
604 : #if LIBSPDM_ENABLE_MSG_LOG
605 15 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
606 : #endif /* LIBSPDM_ENABLE_MSG_LOG */
607 :
608 15 : status = LIBSPDM_STATUS_SUCCESS;
609 :
610 43 : receive_done:
611 43 : libspdm_release_receiver_buffer (spdm_context);
612 43 : return status;
613 : }
614 :
615 44 : libspdm_return_t libspdm_send_receive_psk_exchange(libspdm_context_t *spdm_context,
616 : const void *psk_hint,
617 : uint16_t psk_hint_size,
618 : uint8_t measurement_hash_type,
619 : uint8_t session_policy,
620 : uint32_t *session_id,
621 : uint8_t *heartbeat_period,
622 : void *measurement_hash)
623 : {
624 : size_t retry;
625 : uint64_t retry_delay_time;
626 : libspdm_return_t status;
627 :
628 44 : spdm_context->crypto_request = true;
629 44 : retry = spdm_context->retry_times;
630 44 : retry_delay_time = spdm_context->retry_delay_time;
631 : do {
632 45 : status = libspdm_try_send_receive_psk_exchange(
633 : spdm_context, psk_hint, psk_hint_size,
634 : measurement_hash_type, session_policy, session_id,
635 : heartbeat_period, measurement_hash,
636 : NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL);
637 45 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
638 43 : return status;
639 : }
640 :
641 2 : libspdm_sleep(retry_delay_time);
642 2 : } while (retry-- != 0);
643 :
644 1 : return status;
645 : }
646 :
647 0 : libspdm_return_t libspdm_send_receive_psk_exchange_ex(libspdm_context_t *spdm_context,
648 : const void *psk_hint,
649 : uint16_t psk_hint_size,
650 : uint8_t measurement_hash_type,
651 : uint8_t session_policy,
652 : uint32_t *session_id,
653 : uint8_t *heartbeat_period,
654 : void *measurement_hash,
655 : const void *requester_context_in,
656 : size_t requester_context_in_size,
657 : void *requester_context,
658 : size_t *requester_context_size,
659 : void *responder_context,
660 : size_t *responder_context_size,
661 : const void *requester_opaque_data,
662 : size_t requester_opaque_data_size,
663 : void *responder_opaque_data,
664 : size_t *responder_opaque_data_size)
665 : {
666 : size_t retry;
667 : uint64_t retry_delay_time;
668 : libspdm_return_t status;
669 :
670 0 : spdm_context->crypto_request = true;
671 0 : retry = spdm_context->retry_times;
672 0 : retry_delay_time = spdm_context->retry_delay_time;
673 : do {
674 0 : status = libspdm_try_send_receive_psk_exchange(
675 : spdm_context, psk_hint, psk_hint_size,
676 : measurement_hash_type, session_policy, session_id,
677 : heartbeat_period, measurement_hash,
678 : requester_context_in, requester_context_in_size,
679 : requester_context, requester_context_size,
680 : responder_context, responder_context_size,
681 : requester_opaque_data, requester_opaque_data_size,
682 : responder_opaque_data, responder_opaque_data_size);
683 0 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
684 0 : return status;
685 : }
686 :
687 0 : libspdm_sleep(retry_delay_time);
688 0 : } while (retry-- != 0);
689 :
690 0 : return status;
691 : }
692 :
693 : #endif /* LIBSPDM_ENABLE_CAPABILITY_PSK_CAP*/
|