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 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 : 21 : 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 : 21 : hash_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
53 [ - + ]: 21 : 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 : 21 : result = libspdm_calculate_th_hmac_for_exchange_rsp(
78 : : spdm_context, session_info, &hash_size, calc_hmac_data);
79 [ - + ]: 21 : if (!result) {
80 : 0 : return false;
81 : : }
82 : : #endif
83 : 21 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "th_curr hmac - "));
84 : 21 : LIBSPDM_INTERNAL_DUMP_DATA(calc_hmac_data, hash_size);
85 : 21 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
86 : :
87 [ + + ]: 21 : 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 : 20 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "!!! verify_psk_exchange_rsp_hmac - PASS !!!\n"));
92 : :
93 : 20 : 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 responder_context buffer.
114 : : * On output, the size of data returned in responder_context buffer.
115 : : * It could be 0 if device does not support context.
116 : : * @param responder_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 : 77 : 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 : 77 : uint8_t peer_aead_limit_exponent = SECURED_MESSAGE_AEAD_LIMIT_EXPONENT_DEFAULT;
163 : :
164 [ + + + + : 77 : 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 [ + + ]: 77 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
169 : 1 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
170 : : }
171 : :
172 : : /* Check capabilities even if GET_CAPABILITIES is not sent.
173 : : * Assuming capabilities are provisioned.*/
174 [ + + ]: 76 : 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 : 3 : 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 [ + + ]: 73 : 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 : 5 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
189 : : }
190 : :
191 [ + + ]: 68 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
192 : 1 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
193 : : }
194 [ + + ]: 67 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
195 [ + + ]: 8 : if ((spdm_context->connection_info.algorithm.other_params_support &
196 : : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) != SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1) {
197 : 1 : return LIBSPDM_STATUS_INVALID_STATE_PEER;
198 : : }
199 : : }
200 : :
201 : 66 : req_session_id = libspdm_allocate_req_session_id(spdm_context, true);
202 [ + + ]: 66 : if (req_session_id == (INVALID_SESSION_ID & 0xFFFF)) {
203 : 1 : return LIBSPDM_STATUS_SESSION_NUMBER_EXCEED;
204 : : }
205 : :
206 : 65 : libspdm_reset_message_buffer_via_request_code(spdm_context, NULL, SPDM_PSK_EXCHANGE);
207 : : {
208 : : /* Double check if algorithm has been provisioned, because NEGOTIATE_ALGORITHMS might be skipped.*/
209 [ + + ]: 65 : if (libspdm_is_capabilities_flag_supported(
210 : : spdm_context, true, 0,
211 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP)) {
212 : 17 : if (spdm_context->connection_info.algorithm
213 [ + + ]: 17 : .measurement_spec !=
214 : : SPDM_MEASUREMENT_SPECIFICATION_DMTF) {
215 : 1 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
216 : : }
217 : 16 : algo_size = libspdm_get_measurement_hash_size(
218 : : spdm_context->connection_info.algorithm.measurement_hash_algo);
219 [ + + ]: 16 : if (algo_size == 0) {
220 : 1 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
221 : : }
222 : : }
223 : 63 : algo_size = libspdm_get_hash_size(
224 : : spdm_context->connection_info.algorithm.base_hash_algo);
225 [ + + ]: 63 : if (algo_size == 0) {
226 : 1 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
227 : : }
228 [ + + ]: 62 : if (spdm_context->connection_info.algorithm.key_schedule !=
229 : : SPDM_ALGORITHMS_KEY_SCHEDULE_SPDM) {
230 : 1 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
231 : : }
232 : : }
233 : :
234 : 61 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
235 : 61 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
236 [ + + ]: 61 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
237 : 1 : return status;
238 : : }
239 [ - + ]: 60 : LIBSPDM_ASSERT (message_size >= transport_header_size +
240 : : spdm_context->local_context.capability.transport_tail_size);
241 : 60 : spdm_request = (void *)(message + transport_header_size);
242 : 60 : spdm_request_size = message_size - transport_header_size -
243 : 60 : spdm_context->local_context.capability.transport_tail_size;
244 : :
245 [ - + ]: 60 : LIBSPDM_ASSERT(spdm_request_size >= sizeof(spdm_psk_exchange_request_t) + psk_hint_size);
246 : 60 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
247 : 60 : spdm_request->header.request_response_code = SPDM_PSK_EXCHANGE;
248 : 60 : spdm_request->header.param1 = measurement_hash_type;
249 [ + + ]: 60 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
250 : 7 : spdm_request->header.param2 = session_policy;
251 : : } else {
252 : 53 : spdm_request->header.param2 = 0;
253 : : }
254 : 60 : spdm_request->psk_hint_length = psk_hint_size;
255 [ + + ]: 60 : if (requester_context_in == NULL) {
256 : 59 : spdm_request->context_length = LIBSPDM_PSK_CONTEXT_LENGTH;
257 : : } else {
258 [ - + ]: 1 : LIBSPDM_ASSERT (requester_context_in_size <= LIBSPDM_PSK_CONTEXT_LENGTH);
259 : 1 : 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 : 60 : local_max_secured_version = libspdm_local_max_secured_message_version(spdm_context);
265 : :
266 [ + + ]: 60 : if (requester_opaque_data != NULL) {
267 [ - + ]: 1 : LIBSPDM_ASSERT(requester_opaque_data_size <= SPDM_MAX_OPAQUE_DATA_SIZE);
268 : :
269 : 1 : 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 : 59 : opaque_psk_exchange_req_size =
273 : 118 : libspdm_get_opaque_data_supported_version_data_size(spdm_context) +
274 : 59 : libspdm_get_opaque_data_aead_limit_element_size(spdm_context,
275 : : local_max_secured_version);
276 : : }
277 : :
278 [ - + ]: 60 : 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 : 60 : spdm_request->opaque_length = (uint16_t)opaque_psk_exchange_req_size;
281 : :
282 : 60 : spdm_request->req_session_id = req_session_id;
283 : :
284 : 60 : ptr = spdm_request->psk_hint;
285 [ + + + - ]: 60 : if ((psk_hint != NULL) && (psk_hint_size > 0)) {
286 : 59 : libspdm_copy_mem(ptr, sizeof(spdm_request->psk_hint),
287 : : psk_hint,
288 : : psk_hint_size);
289 : : }
290 : 60 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "psk_hint (0x%x) - ", spdm_request->psk_hint_length));
291 : 60 : LIBSPDM_INTERNAL_DUMP_DATA(ptr, spdm_request->psk_hint_length);
292 : 60 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
293 : 60 : ptr += spdm_request->psk_hint_length;
294 : :
295 [ + + ]: 60 : if (requester_context_in == NULL) {
296 [ - + ]: 59 : 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 : 1 : libspdm_copy_mem(ptr, sizeof(spdm_request->context),
302 : 1 : requester_context_in, spdm_request->context_length);
303 : : }
304 : 60 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "RequesterContextData (0x%x) - ",
305 : : spdm_request->context_length));
306 : 60 : LIBSPDM_INTERNAL_DUMP_DATA(ptr, spdm_request->context_length);
307 : 60 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
308 [ + + ]: 60 : if (requester_context != NULL) {
309 [ + - ]: 1 : if (*requester_context_size > spdm_request->context_length) {
310 : 1 : *requester_context_size = spdm_request->context_length;
311 : : }
312 : 1 : libspdm_copy_mem(requester_context, *requester_context_size,
313 : : ptr, *requester_context_size);
314 : : }
315 : 60 : ptr += spdm_request->context_length;
316 : :
317 [ + + ]: 60 : if (requester_opaque_data != NULL) {
318 : 1 : libspdm_copy_mem(ptr, opaque_psk_exchange_req_size,
319 : : requester_opaque_data, opaque_psk_exchange_req_size);
320 : : } else {
321 : 59 : size_t supported_version_size =
322 : 59 : libspdm_get_opaque_data_supported_version_data_size(spdm_context);
323 : 59 : 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 : 59 : libspdm_build_opaque_data_aead_limit_element(
328 : : spdm_context, local_max_secured_version, &opaque_psk_exchange_req_size, ptr);
329 : : }
330 : 60 : ptr += opaque_psk_exchange_req_size;
331 : :
332 : 60 : spdm_request_size = (size_t)ptr - (size_t)spdm_request;
333 : 60 : status = libspdm_send_spdm_request(spdm_context, NULL, spdm_request_size,
334 : : spdm_request);
335 [ + + ]: 60 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
336 : 1 : libspdm_release_sender_buffer (spdm_context);
337 : 1 : return status;
338 : : }
339 : 59 : libspdm_release_sender_buffer (spdm_context);
340 : 59 : spdm_request = (void *)spdm_context->last_spdm_request;
341 : :
342 : : /* receive */
343 : :
344 : 59 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
345 [ + + ]: 59 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
346 : 1 : return status;
347 : : }
348 [ - + ]: 58 : LIBSPDM_ASSERT (message_size >= transport_header_size);
349 : 58 : spdm_response = (void *)(message);
350 : 58 : spdm_response_size = message_size;
351 : :
352 : 58 : status = libspdm_receive_spdm_response(
353 : : spdm_context, NULL, &spdm_response_size, (void **)&spdm_response);
354 [ + + ]: 58 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
355 : 1 : goto receive_done;
356 : : }
357 [ - + ]: 57 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
358 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
359 : 0 : goto receive_done;
360 : : }
361 [ + + ]: 57 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
362 : 26 : 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 [ + + ]: 26 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
367 : 25 : goto receive_done;
368 : : }
369 [ + + ]: 31 : } else if (spdm_response->header.request_response_code != SPDM_PSK_EXCHANGE_RSP) {
370 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
371 : 1 : goto receive_done;
372 : : }
373 [ + + ]: 31 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
374 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
375 : 1 : goto receive_done;
376 : : }
377 [ + + ]: 30 : if (spdm_response_size < sizeof(spdm_psk_exchange_response_t)) {
378 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
379 : 1 : goto receive_done;
380 : : }
381 : :
382 [ + + ]: 29 : 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 [ + + ]: 27 : if (spdm_response->header.param1 != 0) {
387 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
388 : 1 : goto receive_done;
389 : : }
390 : : }
391 [ + - ]: 28 : if (heartbeat_period != NULL) {
392 : 28 : *heartbeat_period = spdm_response->header.param1;
393 : : }
394 : :
395 : 28 : measurement_summary_hash_size = libspdm_get_measurement_summary_hash_size(
396 : : spdm_context, true, measurement_hash_type);
397 : 28 : hmac_size = libspdm_get_hash_size(
398 : : spdm_context->connection_info.algorithm.base_hash_algo);
399 : :
400 : 28 : if (spdm_response_size <
401 : : sizeof(spdm_psk_exchange_response_t) +
402 : 28 : spdm_response->context_length + spdm_response->opaque_length +
403 [ + + ]: 28 : measurement_summary_hash_size + hmac_size) {
404 : 2 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
405 : 2 : goto receive_done;
406 : : }
407 : :
408 : 26 : ptr = (uint8_t *)spdm_response + sizeof(spdm_psk_exchange_response_t) +
409 : 26 : measurement_summary_hash_size + spdm_response->context_length;
410 : 26 : secured_message_version = 0;
411 [ + + ]: 26 : if (spdm_response->opaque_length != 0) {
412 : 23 : result = libspdm_process_general_opaque_data_check(spdm_context,
413 : 23 : spdm_response->opaque_length, ptr);
414 [ + + ]: 23 : if (!result) {
415 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
416 : 1 : goto receive_done;
417 : : }
418 : 22 : status = libspdm_process_opaque_data_version_selection_data(
419 : 22 : spdm_context, spdm_response->opaque_length, ptr, &secured_message_version);
420 [ + + ]: 22 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
421 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
422 : 1 : goto receive_done;
423 : : }
424 : : /* DSP0277 1.3: read the Responder's AEAD limit (absent -> default 64). */
425 : 21 : status = libspdm_process_opaque_data_aead_limit(
426 : 21 : spdm_context, secured_message_version, spdm_response->opaque_length, ptr,
427 : : &peer_aead_limit_exponent);
428 [ - + ]: 21 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
429 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
430 : 0 : goto receive_done;
431 : : }
432 : : }
433 : :
434 : 24 : spdm_response_size = sizeof(spdm_psk_exchange_response_t) +
435 : 24 : spdm_response->context_length +
436 : 24 : spdm_response->opaque_length +
437 : 24 : measurement_summary_hash_size + hmac_size;
438 : :
439 : 24 : ptr = (uint8_t *)(spdm_response->measurement_summary_hash);
440 : 24 : measurement_summary_hash = ptr;
441 : 24 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "measurement_summary_hash (0x%x) - ",
442 : : measurement_summary_hash_size));
443 : 24 : LIBSPDM_INTERNAL_DUMP_DATA(measurement_summary_hash,
444 : : measurement_summary_hash_size);
445 : 24 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
446 : :
447 : 24 : ptr += measurement_summary_hash_size;
448 : :
449 [ - + ]: 24 : if (spdm_response->opaque_length > SPDM_MAX_OPAQUE_DATA_SIZE) {
450 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
451 : 0 : goto receive_done;
452 : : }
453 : :
454 [ + + ]: 24 : if (libspdm_is_capabilities_flag_supported(
455 : : spdm_context, true, 0,
456 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP_RESPONDER)) {
457 [ + + ]: 4 : if (spdm_response->context_length != 0) {
458 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
459 : 1 : goto receive_done;
460 : : }
461 : : } else {
462 [ + + ]: 20 : if (spdm_response->context_length == 0) {
463 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
464 : 1 : goto receive_done;
465 : : }
466 : : }
467 : :
468 : 22 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "ResponderContextData (0x%x) - ",
469 : : spdm_response->context_length));
470 : 22 : LIBSPDM_INTERNAL_DUMP_DATA(ptr, spdm_response->context_length);
471 : 22 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
472 [ + + ]: 22 : if (responder_context != NULL) {
473 [ + - ]: 1 : if (*responder_context_size > spdm_response->context_length) {
474 : 1 : *responder_context_size = spdm_response->context_length;
475 : : }
476 : 1 : libspdm_copy_mem(responder_context, *responder_context_size,
477 : : ptr, *responder_context_size);
478 : : }
479 : :
480 : 22 : ptr += spdm_response->context_length;
481 : :
482 [ + + + - ]: 22 : if ((responder_opaque_data != NULL) && (responder_opaque_data_size != NULL)) {
483 [ + + ]: 2 : if (spdm_response->opaque_length >= *responder_opaque_data_size) {
484 : 1 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
485 : 1 : goto receive_done;
486 : : }
487 : 1 : libspdm_copy_mem(responder_opaque_data, *responder_opaque_data_size,
488 : 1 : ptr, spdm_response->opaque_length);
489 : 1 : *responder_opaque_data_size = spdm_response->opaque_length;
490 : : }
491 : :
492 : 21 : ptr += spdm_response->opaque_length;
493 : :
494 : 21 : rsp_session_id = spdm_response->rsp_session_id;
495 : 21 : *session_id = libspdm_generate_session_id(req_session_id, rsp_session_id);
496 : 21 : session_info = libspdm_assign_session_id(spdm_context, *session_id, secured_message_version,
497 : : true);
498 [ - + ]: 21 : if (session_info == NULL) {
499 : 0 : status = LIBSPDM_STATUS_SESSION_NUMBER_EXCEED;
500 : 0 : goto receive_done;
501 : : }
502 : 21 : libspdm_session_info_set_psk_hint(session_info,
503 : : psk_hint,
504 : : psk_hint_size);
505 : :
506 : : /* DSP0277 1.3: program the session's AEAD limit (min of local and peer) when secured message
507 : : * version 1.3 was negotiated. */
508 [ - + ]: 21 : if (libspdm_get_version_from_version_number(secured_message_version) >=
509 : : SECURED_SPDM_VERSION_13) {
510 : 0 : libspdm_apply_aead_limit_to_session(spdm_context, session_info,
511 : : peer_aead_limit_exponent);
512 : : }
513 : :
514 : : /* Cache session data*/
515 : :
516 : 21 : status = libspdm_append_message_k(spdm_context, session_info, true, spdm_request,
517 : : spdm_request_size);
518 [ - + ]: 21 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
519 : 0 : libspdm_free_session_id(spdm_context, *session_id);
520 : 0 : goto receive_done;
521 : : }
522 : :
523 : 21 : status = libspdm_append_message_k(spdm_context, session_info, true, spdm_response,
524 : : spdm_response_size - hmac_size);
525 [ - + ]: 21 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
526 : 0 : libspdm_free_session_id(spdm_context, *session_id);
527 : 0 : goto receive_done;
528 : : }
529 : :
530 : 21 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "libspdm_generate_session_handshake_key[%x]\n",
531 : : *session_id));
532 : 21 : result = libspdm_calculate_th1_hash(spdm_context, session_info, true,
533 : : th1_hash_data);
534 [ - + ]: 21 : if (!result) {
535 : 0 : libspdm_free_session_id(spdm_context, *session_id);
536 : 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
537 : 0 : goto receive_done;
538 : : }
539 : 21 : result = libspdm_generate_session_handshake_key(
540 : : session_info->secured_message_context, th1_hash_data);
541 [ - + ]: 21 : if (!result) {
542 : 0 : libspdm_free_session_id(spdm_context, *session_id);
543 : 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
544 : 0 : goto receive_done;
545 : : }
546 : :
547 : 21 : verify_data = ptr;
548 : 21 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "verify_data (0x%x):\n", hmac_size));
549 : 21 : LIBSPDM_INTERNAL_DUMP_HEX(verify_data, hmac_size);
550 : 21 : result = libspdm_verify_psk_exchange_rsp_hmac(spdm_context, session_info,
551 : : verify_data, hmac_size);
552 [ + + ]: 21 : if (!result) {
553 : 1 : libspdm_free_session_id(spdm_context, *session_id);
554 : 1 : status = LIBSPDM_STATUS_VERIF_FAIL;
555 : 1 : goto receive_done;
556 : : }
557 : :
558 : 20 : status = libspdm_append_message_k(spdm_context, session_info, true, verify_data, hmac_size);
559 [ - + ]: 20 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
560 : 0 : libspdm_free_session_id(spdm_context, *session_id);
561 : 0 : goto receive_done;
562 : : }
563 : :
564 [ + - ]: 20 : if (measurement_hash != NULL) {
565 : 20 : libspdm_copy_mem(measurement_hash, measurement_summary_hash_size,
566 : : measurement_summary_hash, measurement_summary_hash_size);
567 : : }
568 : :
569 : 20 : session_info->session_policy = session_policy;
570 : :
571 : 20 : libspdm_secured_message_set_session_state(
572 : : session_info->secured_message_context,
573 : : LIBSPDM_SESSION_STATE_HANDSHAKING);
574 : :
575 [ + + ]: 20 : if (!libspdm_is_capabilities_flag_supported(
576 : : spdm_context, true, 0,
577 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP_RESPONDER_WITH_CONTEXT)) {
578 : : /* No need to send PSK_FINISH, enter application phase directly.*/
579 : :
580 : 3 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "libspdm_generate_session_data_key[%x]\n",
581 : : *session_id));
582 : 3 : result = libspdm_calculate_th2_hash(spdm_context, session_info,
583 : : true, th2_hash_data);
584 [ - + ]: 3 : if (!result) {
585 : 0 : libspdm_free_session_id(spdm_context, *session_id);
586 : 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
587 : 0 : goto receive_done;
588 : : }
589 : 3 : result = libspdm_generate_session_data_key(
590 : : session_info->secured_message_context, th2_hash_data);
591 [ - + ]: 3 : if (!result) {
592 : 0 : libspdm_free_session_id(spdm_context, *session_id);
593 : 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
594 : 0 : goto receive_done;
595 : : }
596 : :
597 : 3 : libspdm_secured_message_set_session_state(
598 : : session_info->secured_message_context,
599 : : LIBSPDM_SESSION_STATE_ESTABLISHED);
600 : : }
601 : :
602 : 20 : session_info->heartbeat_period = spdm_response->header.param1;
603 : :
604 : : /* -=[Log Message Phase]=- */
605 : : #if LIBSPDM_ENABLE_MSG_LOG
606 : 20 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
607 : : #endif /* LIBSPDM_ENABLE_MSG_LOG */
608 : :
609 : 20 : status = LIBSPDM_STATUS_SUCCESS;
610 : :
611 : 58 : receive_done:
612 : 58 : libspdm_release_receiver_buffer (spdm_context);
613 : 58 : return status;
614 : : }
615 : :
616 : 68 : libspdm_return_t libspdm_send_receive_psk_exchange(libspdm_context_t *spdm_context,
617 : : const void *psk_hint,
618 : : uint16_t psk_hint_size,
619 : : uint8_t measurement_hash_type,
620 : : uint8_t session_policy,
621 : : uint32_t *session_id,
622 : : uint8_t *heartbeat_period,
623 : : void *measurement_hash)
624 : : {
625 : : size_t retry;
626 : : uint64_t retry_delay_time;
627 : : libspdm_return_t status;
628 : :
629 : 68 : spdm_context->crypto_request = true;
630 : 68 : retry = spdm_context->retry_times;
631 : 68 : retry_delay_time = spdm_context->retry_delay_time;
632 : : do {
633 : 69 : status = libspdm_try_send_receive_psk_exchange(
634 : : spdm_context, psk_hint, psk_hint_size,
635 : : measurement_hash_type, session_policy, session_id,
636 : : heartbeat_period, measurement_hash,
637 : : NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL);
638 [ + + ]: 69 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
639 : 67 : return status;
640 : : }
641 : :
642 : 2 : libspdm_sleep(retry_delay_time);
643 [ + + ]: 2 : } while (retry-- != 0);
644 : :
645 : 1 : return status;
646 : : }
647 : :
648 : 7 : libspdm_return_t libspdm_send_receive_psk_exchange_ex(libspdm_context_t *spdm_context,
649 : : const void *psk_hint,
650 : : uint16_t psk_hint_size,
651 : : uint8_t measurement_hash_type,
652 : : uint8_t session_policy,
653 : : uint32_t *session_id,
654 : : uint8_t *heartbeat_period,
655 : : void *measurement_hash,
656 : : const void *requester_context_in,
657 : : size_t requester_context_in_size,
658 : : void *requester_context,
659 : : size_t *requester_context_size,
660 : : void *responder_context,
661 : : size_t *responder_context_size,
662 : : const void *requester_opaque_data,
663 : : size_t requester_opaque_data_size,
664 : : void *responder_opaque_data,
665 : : size_t *responder_opaque_data_size)
666 : : {
667 : : size_t retry;
668 : : uint64_t retry_delay_time;
669 : : libspdm_return_t status;
670 : :
671 : 7 : spdm_context->crypto_request = true;
672 : 7 : retry = spdm_context->retry_times;
673 : 7 : retry_delay_time = spdm_context->retry_delay_time;
674 : : do {
675 : 8 : status = libspdm_try_send_receive_psk_exchange(
676 : : spdm_context, psk_hint, psk_hint_size,
677 : : measurement_hash_type, session_policy, session_id,
678 : : heartbeat_period, measurement_hash,
679 : : requester_context_in, requester_context_in_size,
680 : : requester_context, requester_context_size,
681 : : responder_context, responder_context_size,
682 : : requester_opaque_data, requester_opaque_data_size,
683 : : responder_opaque_data, responder_opaque_data_size);
684 [ + + ]: 8 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
685 : 6 : return status;
686 : : }
687 : :
688 : 2 : libspdm_sleep(retry_delay_time);
689 [ + + ]: 2 : } while (retry-- != 0);
690 : :
691 : 1 : return status;
692 : : }
693 : :
694 : : #endif /* LIBSPDM_ENABLE_CAPABILITY_PSK_CAP*/
|