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_KEY_EX_CAP
11 :
12 : #pragma pack(1)
13 : typedef struct {
14 : spdm_message_header_t header;
15 : uint16_t req_session_id;
16 : uint8_t session_policy;
17 : uint8_t reserved;
18 : uint8_t random_data[SPDM_RANDOM_DATA_SIZE];
19 : uint8_t exchange_data[LIBSPDM_MAX_DHE_KEY_SIZE];
20 : uint16_t opaque_length;
21 : uint8_t opaque_data[SPDM_MAX_OPAQUE_DATA_SIZE];
22 : } libspdm_key_exchange_request_mine_t;
23 :
24 : typedef struct {
25 : spdm_message_header_t header;
26 : uint16_t rsp_session_id;
27 : uint8_t mut_auth_requested;
28 : uint8_t req_slot_id_param;
29 : uint8_t random_data[SPDM_RANDOM_DATA_SIZE];
30 : uint8_t exchange_data[LIBSPDM_MAX_DHE_KEY_SIZE];
31 : uint8_t measurement_summary_hash[LIBSPDM_MAX_HASH_SIZE];
32 : uint16_t opaque_length;
33 : uint8_t opaque_data[SPDM_MAX_OPAQUE_DATA_SIZE];
34 : uint8_t signature[LIBSPDM_MAX_ASYM_KEY_SIZE];
35 : uint8_t verify_data[LIBSPDM_MAX_HASH_SIZE];
36 : } libspdm_key_exchange_response_max_t;
37 : #pragma pack()
38 :
39 19 : bool libspdm_verify_key_exchange_rsp_hmac(libspdm_context_t *spdm_context,
40 : libspdm_session_info_t *session_info,
41 : const void *hmac_data,
42 : size_t hmac_data_size)
43 : {
44 : size_t hash_size;
45 : uint8_t calc_hmac_data[LIBSPDM_MAX_HASH_SIZE];
46 : bool result;
47 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
48 : uint8_t slot_id;
49 : uint8_t *cert_chain_buffer;
50 : size_t cert_chain_buffer_size;
51 : uint8_t *th_curr_data;
52 : size_t th_curr_data_size;
53 : libspdm_th_managed_buffer_t th_curr;
54 : uint8_t hash_data[LIBSPDM_MAX_HASH_SIZE];
55 : #endif
56 :
57 19 : hash_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
58 19 : LIBSPDM_ASSERT(hash_size == hmac_data_size);
59 :
60 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
61 : slot_id = spdm_context->connection_info.peer_used_cert_chain_slot_id;
62 : LIBSPDM_ASSERT((slot_id < SPDM_MAX_SLOT_COUNT) || (slot_id == 0xFF));
63 : if (slot_id == 0xFF) {
64 : result = libspdm_get_peer_public_key_buffer(
65 : spdm_context, (const void **)&cert_chain_buffer, &cert_chain_buffer_size);
66 : } else {
67 : result = libspdm_get_peer_cert_chain_buffer(
68 : spdm_context, (const void **)&cert_chain_buffer, &cert_chain_buffer_size);
69 : }
70 : if (!result) {
71 : return false;
72 : }
73 :
74 : result = libspdm_calculate_th_for_exchange(
75 : spdm_context, session_info, cert_chain_buffer,
76 : cert_chain_buffer_size, &th_curr);
77 : if (!result) {
78 : return false;
79 : }
80 : th_curr_data = libspdm_get_managed_buffer(&th_curr);
81 : th_curr_data_size = libspdm_get_managed_buffer_size(&th_curr);
82 :
83 : result = libspdm_hash_all (spdm_context->connection_info.algorithm.base_hash_algo,
84 : th_curr_data, th_curr_data_size, hash_data);
85 : if (!result) {
86 : return false;
87 : }
88 :
89 : result = libspdm_hmac_all_with_response_finished_key(
90 : session_info->secured_message_context, hash_data,
91 : hash_size, calc_hmac_data);
92 : if (!result) {
93 : return false;
94 : }
95 : #else
96 19 : result = libspdm_calculate_th_hmac_for_exchange_rsp(
97 : spdm_context, session_info, true, &hash_size, calc_hmac_data);
98 19 : if (!result) {
99 0 : return false;
100 : }
101 : #endif
102 19 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "th_curr hmac - "));
103 19 : LIBSPDM_INTERNAL_DUMP_DATA(calc_hmac_data, hash_size);
104 19 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
105 :
106 19 : if (!libspdm_consttime_is_mem_equal(calc_hmac_data, hmac_data, hash_size)) {
107 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "!!! verify_key_exchange_hmac - FAIL !!!\n"));
108 0 : return false;
109 : }
110 19 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "!!! verify_key_exchange_hmac - PASS !!!\n"));
111 :
112 19 : return true;
113 : }
114 :
115 22 : bool libspdm_verify_key_exchange_rsp_signature(
116 : libspdm_context_t *spdm_context, libspdm_session_info_t *session_info,
117 : const void *sign_data, const size_t sign_data_size)
118 : {
119 : bool result;
120 : void *context;
121 : uint8_t slot_id;
122 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
123 : uint8_t *cert_chain_buffer;
124 : size_t cert_chain_buffer_size;
125 : uint8_t *th_curr_data;
126 : size_t th_curr_data_size;
127 : libspdm_th_managed_buffer_t th_curr;
128 : const uint8_t *cert_chain_data;
129 : size_t cert_chain_data_size;
130 : const uint8_t *cert_buffer;
131 : size_t cert_buffer_size;
132 : #endif
133 : #if !(LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT) || (LIBSPDM_DEBUG_PRINT_ENABLE)
134 : size_t hash_size;
135 : uint8_t hash_data[LIBSPDM_MAX_HASH_SIZE];
136 :
137 22 : hash_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
138 : #endif
139 :
140 22 : slot_id = spdm_context->connection_info.peer_used_cert_chain_slot_id;
141 22 : LIBSPDM_ASSERT((slot_id < SPDM_MAX_SLOT_COUNT) || (slot_id == 0xFF));
142 :
143 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
144 : if (slot_id == 0xFF) {
145 : result = libspdm_get_peer_public_key_buffer(
146 : spdm_context, (const void **)&cert_chain_buffer, &cert_chain_buffer_size);
147 : } else {
148 : result = libspdm_get_peer_cert_chain_buffer(
149 : spdm_context, (const void **)&cert_chain_buffer, &cert_chain_buffer_size);
150 : }
151 : if (!result) {
152 : return false;
153 : }
154 :
155 : result = libspdm_calculate_th_for_exchange(
156 : spdm_context, session_info, cert_chain_buffer,
157 : cert_chain_buffer_size, &th_curr);
158 : if (!result) {
159 : return false;
160 : }
161 : th_curr_data = libspdm_get_managed_buffer(&th_curr);
162 : th_curr_data_size = libspdm_get_managed_buffer_size(&th_curr);
163 :
164 : /* Debug code only - required for debug print of th_curr hash below*/
165 : LIBSPDM_DEBUG_CODE(
166 : if (!libspdm_hash_all(
167 : spdm_context->connection_info.algorithm.base_hash_algo,
168 : th_curr_data, th_curr_data_size, hash_data)) {
169 : return false;
170 : }
171 : );
172 : #else
173 22 : result = libspdm_calculate_th_hash_for_exchange(
174 : spdm_context, session_info, &hash_size, hash_data);
175 22 : if (!result) {
176 0 : return false;
177 : }
178 : #endif
179 22 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "th_curr hash - "));
180 22 : LIBSPDM_INTERNAL_DUMP_DATA(hash_data, hash_size);
181 22 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
182 :
183 22 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "signature - "));
184 22 : LIBSPDM_INTERNAL_DUMP_DATA(sign_data, sign_data_size);
185 22 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
186 :
187 22 : if (slot_id == 0xFF) {
188 1 : result = libspdm_asym_get_public_key_from_der(
189 : spdm_context->connection_info.algorithm.base_asym_algo,
190 1 : spdm_context->local_context.peer_public_key_provision,
191 : spdm_context->local_context.peer_public_key_provision_size,
192 : &context);
193 1 : if (!result) {
194 0 : return false;
195 : }
196 : } else {
197 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
198 : /* Get leaf cert from cert chain*/
199 : result = libspdm_get_peer_cert_chain_data(
200 : spdm_context, (const void **)&cert_chain_data, &cert_chain_data_size);
201 : if (!result) {
202 : return false;
203 : }
204 : result = libspdm_x509_get_cert_from_cert_chain(
205 : cert_chain_data, cert_chain_data_size, -1, &cert_buffer, &cert_buffer_size);
206 : if (!result) {
207 : return false;
208 : }
209 :
210 : result = libspdm_asym_get_public_key_from_x509(
211 : spdm_context->connection_info.algorithm.base_asym_algo,
212 : cert_buffer, cert_buffer_size, &context);
213 : if (!result) {
214 : return false;
215 : }
216 : #else
217 21 : context = spdm_context->connection_info.peer_used_cert_chain[slot_id].leaf_cert_public_key;
218 21 : LIBSPDM_ASSERT(context != NULL);
219 : #endif
220 : }
221 :
222 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
223 : result = libspdm_asym_verify_ex(
224 : spdm_context->connection_info.version, SPDM_KEY_EXCHANGE_RSP,
225 : spdm_context->connection_info.algorithm.base_asym_algo,
226 : spdm_context->connection_info.algorithm.base_hash_algo,
227 : context, th_curr_data, th_curr_data_size, sign_data, sign_data_size,
228 : &spdm_context->spdm_10_11_verify_signature_endian);
229 : libspdm_asym_free(spdm_context->connection_info.algorithm.base_asym_algo, context);
230 : #else
231 22 : result = libspdm_asym_verify_hash_ex(
232 22 : spdm_context->connection_info.version, SPDM_KEY_EXCHANGE_RSP,
233 : spdm_context->connection_info.algorithm.base_asym_algo,
234 : spdm_context->connection_info.algorithm.base_hash_algo,
235 : context, hash_data, hash_size, sign_data, sign_data_size,
236 : &spdm_context->spdm_10_11_verify_signature_endian);
237 22 : if (slot_id == 0xFF) {
238 1 : libspdm_asym_free(spdm_context->connection_info.algorithm.base_asym_algo, context);
239 : }
240 : #endif
241 22 : if (!result) {
242 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "!!! verify_key_exchange_signature - FAIL !!!\n"));
243 2 : return false;
244 : }
245 20 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "!!! verify_key_exchange_signature - PASS !!!\n"));
246 :
247 20 : return true;
248 : }
249 :
250 : /**
251 : * This function sends KEY_EXCHANGE and receives KEY_EXCHANGE_RSP for SPDM key exchange.
252 : *
253 : * @param spdm_context A pointer to the SPDM context.
254 : * @param measurement_hash_type Measurement_hash_type to the KEY_EXCHANGE request.
255 : * @param slot_id slot_id to the KEY_EXCHANGE request.
256 : * @param session_policy The policy for the session.
257 : * @param session_id session_id from the KEY_EXCHANGE_RSP response.
258 : * @param heartbeat_period Heartbeat_period from the KEY_EXCHANGE_RSP response.
259 : * @param req_slot_id_param req_slot_id_param from the KEY_EXCHANGE_RSP response.
260 : * @param measurement_hash Measurement_hash from the KEY_EXCHANGE_RSP response.
261 : * @param requester_nonce_in If not NULL, a buffer that holds the requester nonce (32 bytes)
262 : * @param requester_nonce If not NULL, a buffer to hold the requester nonce (32 bytes).
263 : * @param responder_nonce If not NULL, a buffer to hold the responder nonce (32 bytes).
264 : **/
265 95 : static libspdm_return_t libspdm_try_send_receive_key_exchange(
266 : libspdm_context_t *spdm_context, uint8_t measurement_hash_type,
267 : uint8_t slot_id, uint8_t session_policy, uint32_t *session_id,
268 : uint8_t *heartbeat_period,
269 : uint8_t *req_slot_id_param, void *measurement_hash,
270 : const void *requester_random_in,
271 : void *requester_random, void *responder_random,
272 : const void *requester_opaque_data, size_t requester_opaque_data_size,
273 : void *responder_opaque_data, size_t *responder_opaque_data_size)
274 : {
275 : bool result;
276 : libspdm_return_t status;
277 : libspdm_key_exchange_request_mine_t *spdm_request;
278 : size_t spdm_request_size;
279 : libspdm_key_exchange_response_max_t *spdm_response;
280 : size_t spdm_response_size;
281 : size_t dhe_key_size;
282 : uint32_t measurement_summary_hash_size;
283 : uint32_t signature_size;
284 : uint32_t hmac_size;
285 : uint8_t *ptr;
286 : void *measurement_summary_hash;
287 : uint16_t opaque_length;
288 : uint8_t *signature;
289 : uint8_t *verify_data;
290 : void *dhe_context;
291 : uint16_t req_session_id;
292 : uint16_t rsp_session_id;
293 : libspdm_session_info_t *session_info;
294 : size_t opaque_key_exchange_req_size;
295 : uint8_t th1_hash_data[LIBSPDM_MAX_HASH_SIZE];
296 : uint8_t *message;
297 : size_t message_size;
298 : size_t transport_header_size;
299 : uint8_t mut_auth_requested;
300 :
301 : /* -=[Check Parameters Phase]=- */
302 95 : LIBSPDM_ASSERT((slot_id < SPDM_MAX_SLOT_COUNT) || (slot_id == 0xff));
303 95 : LIBSPDM_ASSERT((slot_id != 0xff) ||
304 : (spdm_context->local_context.peer_public_key_provision_size != 0));
305 95 : LIBSPDM_ASSERT(measurement_hash_type == SPDM_KEY_EXCHANGE_REQUEST_NO_MEASUREMENT_SUMMARY_HASH ||
306 : measurement_hash_type == SPDM_KEY_EXCHANGE_REQUEST_TCB_COMPONENT_MEASUREMENT_HASH ||
307 : measurement_hash_type == SPDM_KEY_EXCHANGE_REQUEST_ALL_MEASUREMENTS_HASH);
308 95 : LIBSPDM_ASSERT((libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_13) ||
309 : ((session_policy & SPDM_KEY_EXCHANGE_REQUEST_SESSION_POLICY_EVENT_ALL_POLICY)
310 : == 0) ||
311 : libspdm_is_capabilities_flag_supported(
312 : spdm_context, true, 0, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_EVENT_CAP));
313 :
314 : /* -=[Verify State Phase]=- */
315 95 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
316 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
317 : }
318 :
319 95 : if (!libspdm_is_capabilities_flag_supported(
320 : spdm_context, true,
321 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_EX_CAP,
322 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP)) {
323 1 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
324 : }
325 :
326 : /* While clearing MAC_CAP and setting ENCRYPT_CAP is legal according to DSP0274, libspdm
327 : * also implements DSP0277 secure messages, which requires at least MAC_CAP to be set.
328 : */
329 94 : if (!libspdm_is_capabilities_flag_supported(
330 : spdm_context, true,
331 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MAC_CAP,
332 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MAC_CAP)) {
333 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
334 : }
335 :
336 94 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
337 2 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
338 : }
339 :
340 92 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
341 3 : if ((spdm_context->connection_info.algorithm.other_params_support &
342 : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) != SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1) {
343 0 : return LIBSPDM_STATUS_INVALID_STATE_PEER;
344 : }
345 : }
346 :
347 92 : req_session_id = libspdm_allocate_req_session_id(spdm_context, false);
348 92 : if (req_session_id == (INVALID_SESSION_ID & 0xFFFF)) {
349 0 : return LIBSPDM_STATUS_SESSION_NUMBER_EXCEED;
350 : }
351 :
352 92 : libspdm_reset_message_buffer_via_request_code(spdm_context, NULL, SPDM_KEY_EXCHANGE);
353 :
354 : /* -=[Construct Request Phase]=- */
355 92 : spdm_context->connection_info.peer_used_cert_chain_slot_id = slot_id;
356 92 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
357 92 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
358 92 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
359 1 : return status;
360 : }
361 91 : LIBSPDM_ASSERT (message_size >= transport_header_size +
362 : spdm_context->local_context.capability.transport_tail_size);
363 91 : spdm_request = (void *)(message + transport_header_size);
364 91 : spdm_request_size = message_size - transport_header_size -
365 91 : spdm_context->local_context.capability.transport_tail_size;
366 :
367 91 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_key_exchange_request_t));
368 91 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
369 91 : spdm_request->header.request_response_code = SPDM_KEY_EXCHANGE;
370 91 : spdm_request->header.param1 = measurement_hash_type;
371 91 : spdm_request->header.param2 = slot_id;
372 91 : if (requester_random_in == NULL) {
373 90 : if(!libspdm_get_random_number(SPDM_RANDOM_DATA_SIZE, spdm_request->random_data)) {
374 0 : libspdm_release_sender_buffer (spdm_context);
375 0 : return LIBSPDM_STATUS_LOW_ENTROPY;
376 : }
377 : } else {
378 1 : libspdm_copy_mem(spdm_request->random_data, sizeof(spdm_request->random_data),
379 : requester_random_in, SPDM_RANDOM_DATA_SIZE);
380 : }
381 91 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "RequesterRandomData (0x%x) - ",
382 : SPDM_RANDOM_DATA_SIZE));
383 91 : LIBSPDM_INTERNAL_DUMP_DATA(spdm_request->random_data, SPDM_RANDOM_DATA_SIZE);
384 91 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
385 91 : if (requester_random != NULL) {
386 1 : libspdm_copy_mem(requester_random, SPDM_RANDOM_DATA_SIZE,
387 1 : spdm_request->random_data, SPDM_RANDOM_DATA_SIZE);
388 : }
389 :
390 91 : spdm_request->req_session_id = req_session_id;
391 91 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
392 3 : spdm_request->session_policy = session_policy;
393 : } else {
394 88 : spdm_request->session_policy = 0;
395 : }
396 91 : spdm_request->reserved = 0;
397 :
398 91 : ptr = spdm_request->exchange_data;
399 182 : dhe_key_size = libspdm_get_dhe_pub_key_size(
400 91 : spdm_context->connection_info.algorithm.dhe_named_group);
401 91 : dhe_context = libspdm_secured_message_dhe_new(
402 91 : spdm_context->connection_info.version,
403 91 : spdm_context->connection_info.algorithm.dhe_named_group, true);
404 91 : if (dhe_context == NULL) {
405 0 : libspdm_release_sender_buffer (spdm_context);
406 0 : return LIBSPDM_STATUS_CRYPTO_ERROR;
407 : }
408 :
409 91 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_key_exchange_request_t) + dhe_key_size);
410 91 : result = libspdm_secured_message_dhe_generate_key(
411 91 : spdm_context->connection_info.algorithm.dhe_named_group,
412 : dhe_context, ptr, &dhe_key_size);
413 91 : if (!result) {
414 0 : libspdm_secured_message_dhe_free(
415 0 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
416 0 : libspdm_release_sender_buffer (spdm_context);
417 0 : return LIBSPDM_STATUS_CRYPTO_ERROR;
418 : }
419 91 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "RequesterKey (0x%zx):\n", dhe_key_size));
420 91 : LIBSPDM_INTERNAL_DUMP_HEX(ptr, dhe_key_size);
421 91 : ptr += dhe_key_size;
422 :
423 91 : if (requester_opaque_data != NULL) {
424 1 : LIBSPDM_ASSERT(requester_opaque_data_size <= SPDM_MAX_OPAQUE_DATA_SIZE);
425 :
426 1 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_key_exchange_request_t) + dhe_key_size +
427 : sizeof(uint16_t) + requester_opaque_data_size);
428 :
429 1 : libspdm_write_uint16(ptr, (uint16_t)requester_opaque_data_size);
430 1 : ptr += sizeof(uint16_t);
431 :
432 1 : libspdm_copy_mem(ptr,
433 1 : (spdm_request_size - (sizeof(spdm_key_exchange_request_t) + dhe_key_size)),
434 : requester_opaque_data, requester_opaque_data_size);
435 1 : opaque_key_exchange_req_size = requester_opaque_data_size;
436 : } else {
437 90 : opaque_key_exchange_req_size =
438 90 : libspdm_get_opaque_data_supported_version_data_size(spdm_context);
439 90 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_key_exchange_request_t) + dhe_key_size +
440 : sizeof(uint16_t) + opaque_key_exchange_req_size);
441 :
442 90 : libspdm_write_uint16(ptr, (uint16_t)opaque_key_exchange_req_size);
443 90 : ptr += sizeof(uint16_t);
444 :
445 90 : libspdm_build_opaque_data_supported_version_data(
446 : spdm_context, &opaque_key_exchange_req_size, ptr);
447 : }
448 91 : ptr += opaque_key_exchange_req_size;
449 :
450 91 : spdm_request_size = (size_t)ptr - (size_t)spdm_request;
451 :
452 : /* -=[Send Request Phase]=- */
453 91 : status = libspdm_send_spdm_request(spdm_context, NULL, spdm_request_size, spdm_request);
454 91 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
455 2 : libspdm_secured_message_dhe_free(
456 2 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
457 2 : libspdm_release_sender_buffer (spdm_context);
458 2 : return status;
459 : }
460 89 : libspdm_release_sender_buffer (spdm_context);
461 89 : spdm_request = (void *)spdm_context->last_spdm_request;
462 :
463 : /* -=[Receive Response Phase]=- */
464 89 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
465 89 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
466 1 : libspdm_secured_message_dhe_free(
467 1 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
468 1 : return status;
469 : }
470 88 : LIBSPDM_ASSERT (message_size >= transport_header_size);
471 88 : spdm_response = (void *)(message);
472 88 : spdm_response_size = message_size;
473 :
474 88 : status = libspdm_receive_spdm_response(
475 : spdm_context, NULL, &spdm_response_size, (void **)&spdm_response);
476 88 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
477 0 : libspdm_secured_message_dhe_free(
478 0 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
479 0 : goto receive_done;
480 : }
481 :
482 : /* -=[Validate Response Phase]=- */
483 88 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
484 0 : libspdm_secured_message_dhe_free(
485 0 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
486 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
487 0 : goto receive_done;
488 : }
489 88 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
490 1 : libspdm_secured_message_dhe_free(
491 1 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
492 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
493 1 : goto receive_done;
494 : }
495 87 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
496 46 : status = libspdm_handle_error_response_main(
497 : spdm_context, NULL, &spdm_response_size,
498 : (void **)&spdm_response, SPDM_KEY_EXCHANGE,
499 : SPDM_KEY_EXCHANGE_RSP);
500 46 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
501 45 : libspdm_secured_message_dhe_free(
502 45 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
503 45 : goto receive_done;
504 : }
505 41 : } else if (spdm_response->header.request_response_code != SPDM_KEY_EXCHANGE_RSP) {
506 1 : libspdm_secured_message_dhe_free(
507 1 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
508 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
509 1 : goto receive_done;
510 : }
511 41 : if (spdm_response_size < sizeof(spdm_key_exchange_response_t)) {
512 0 : libspdm_secured_message_dhe_free(
513 0 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
514 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
515 0 : goto receive_done;
516 : }
517 :
518 41 : if (!libspdm_is_capabilities_flag_supported(
519 : spdm_context, true,
520 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP,
521 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP)) {
522 39 : if (spdm_response->header.param1 != 0) {
523 2 : libspdm_secured_message_dhe_free(
524 2 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
525 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
526 2 : goto receive_done;
527 : }
528 : }
529 39 : if (heartbeat_period != NULL) {
530 35 : *heartbeat_period = spdm_response->header.param1;
531 : }
532 :
533 39 : *req_slot_id_param = spdm_response->req_slot_id_param & 0xf;
534 39 : mut_auth_requested = spdm_response->mut_auth_requested & 0x7;
535 :
536 39 : if (mut_auth_requested != 0) {
537 13 : const bool mut_auth_cap_both = libspdm_is_capabilities_flag_supported(
538 : spdm_context, true,
539 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MUT_AUTH_CAP,
540 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MUT_AUTH_CAP);
541 13 : const bool cert_cap = libspdm_is_capabilities_flag_supported(
542 : spdm_context, true,
543 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CERT_CAP,
544 : 0);
545 13 : const bool pub_key_id_cap = libspdm_is_capabilities_flag_supported(
546 : spdm_context, true,
547 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PUB_KEY_ID_CAP,
548 : 0);
549 :
550 13 : if (!mut_auth_cap_both) {
551 1 : libspdm_secured_message_dhe_free(
552 1 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
553 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
554 1 : goto receive_done;
555 : }
556 12 : if ((mut_auth_requested != SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED) &&
557 : (mut_auth_requested !=
558 7 : SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_ENCAP_REQUEST) &&
559 : (mut_auth_requested !=
560 : SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_GET_DIGESTS)) {
561 6 : libspdm_secured_message_dhe_free(
562 6 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
563 6 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
564 6 : goto receive_done;
565 : }
566 :
567 6 : if (mut_auth_requested == SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED) {
568 : /* Non-encapsulated flow.
569 : * Requester has either CERT_CAP or PUB_KEY_ID_CAP set. */
570 :
571 2 : if ((cert_cap && (*req_slot_id_param >= SPDM_MAX_SLOT_COUNT)) ||
572 0 : (pub_key_id_cap && (*req_slot_id_param != 0xf))) {
573 1 : libspdm_secured_message_dhe_free(
574 1 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
575 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
576 1 : goto receive_done;
577 : }
578 1 : if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) &&
579 0 : spdm_context->connection_info.multi_key_conn_req &&
580 0 : (*req_slot_id_param != 0xf)) {
581 0 : if ((spdm_context->local_context.local_key_usage_bit_mask[*req_slot_id_param] &
582 : SPDM_KEY_USAGE_BIT_MASK_KEY_EX_USE) == 0) {
583 0 : libspdm_secured_message_dhe_free(
584 0 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
585 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
586 0 : goto receive_done;
587 : }
588 : }
589 : } else {
590 : /* Encapsulated flow. */
591 :
592 : /* If Responder has Requester's public key then it cannot use the encapsulated flow. */
593 4 : if (pub_key_id_cap) {
594 1 : libspdm_secured_message_dhe_free(
595 1 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
596 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
597 1 : goto receive_done;
598 : }
599 : /* Encapsulated flow requires support for encapsulated messages by both endpoints. */
600 3 : if (!libspdm_is_encap_supported(spdm_context)) {
601 1 : libspdm_secured_message_dhe_free(
602 1 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
603 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
604 1 : goto receive_done;
605 : }
606 : }
607 : }
608 :
609 29 : signature_size = libspdm_get_asym_signature_size(
610 : spdm_context->connection_info.algorithm.base_asym_algo);
611 29 : measurement_summary_hash_size = libspdm_get_measurement_summary_hash_size(
612 : spdm_context, true, measurement_hash_type);
613 29 : hmac_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
614 :
615 29 : if (libspdm_is_capabilities_flag_supported(
616 : spdm_context, true,
617 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
618 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
619 1 : hmac_size = 0;
620 : }
621 :
622 29 : if (spdm_response_size <
623 29 : sizeof(spdm_key_exchange_response_t) + dhe_key_size +
624 29 : measurement_summary_hash_size + sizeof(uint16_t) + signature_size + hmac_size) {
625 4 : libspdm_secured_message_dhe_free(
626 4 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
627 4 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
628 4 : goto receive_done;
629 : }
630 :
631 25 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "ResponderRandomData (0x%x) - ", SPDM_RANDOM_DATA_SIZE));
632 25 : LIBSPDM_INTERNAL_DUMP_DATA(spdm_response->random_data, SPDM_RANDOM_DATA_SIZE);
633 25 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
634 25 : if (responder_random != NULL) {
635 1 : libspdm_copy_mem(responder_random, SPDM_RANDOM_DATA_SIZE,
636 1 : spdm_response->random_data, SPDM_RANDOM_DATA_SIZE);
637 : }
638 :
639 25 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "ResponderKey (0x%zx):\n", dhe_key_size));
640 25 : LIBSPDM_INTERNAL_DUMP_HEX(spdm_response->exchange_data, dhe_key_size);
641 :
642 25 : ptr = spdm_response->exchange_data;
643 25 : ptr += dhe_key_size;
644 :
645 25 : measurement_summary_hash = ptr;
646 25 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "measurement_summary_hash (0x%x) - ",
647 : measurement_summary_hash_size));
648 25 : LIBSPDM_INTERNAL_DUMP_DATA(measurement_summary_hash, measurement_summary_hash_size);
649 25 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
650 :
651 25 : ptr += measurement_summary_hash_size;
652 :
653 25 : opaque_length = libspdm_read_uint16((const uint8_t *)ptr);
654 25 : if (opaque_length > SPDM_MAX_OPAQUE_DATA_SIZE) {
655 1 : libspdm_secured_message_dhe_free(
656 1 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
657 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
658 1 : goto receive_done;
659 : }
660 24 : ptr += sizeof(uint16_t);
661 24 : if (spdm_response_size <
662 24 : sizeof(spdm_key_exchange_response_t) + dhe_key_size +
663 24 : measurement_summary_hash_size + sizeof(uint16_t) +
664 24 : opaque_length + signature_size + hmac_size) {
665 2 : libspdm_secured_message_dhe_free(
666 2 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
667 2 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
668 2 : goto receive_done;
669 : }
670 22 : if (opaque_length != 0) {
671 22 : result = libspdm_process_general_opaque_data_check(spdm_context, opaque_length, ptr);
672 22 : if (!result) {
673 0 : libspdm_secured_message_dhe_free(
674 0 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
675 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
676 0 : goto receive_done;
677 : }
678 22 : status = libspdm_process_opaque_data_version_selection_data(
679 : spdm_context, opaque_length, ptr);
680 22 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
681 0 : libspdm_secured_message_dhe_free(
682 0 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
683 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
684 0 : goto receive_done;
685 : }
686 : }
687 :
688 22 : if ((responder_opaque_data != NULL) && (responder_opaque_data_size != NULL)) {
689 1 : if (opaque_length >= *responder_opaque_data_size) {
690 0 : libspdm_secured_message_dhe_free(
691 0 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
692 0 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
693 0 : goto receive_done;
694 : }
695 1 : libspdm_copy_mem(responder_opaque_data, *responder_opaque_data_size, ptr, opaque_length);
696 1 : *responder_opaque_data_size = opaque_length;
697 : }
698 :
699 22 : ptr += opaque_length;
700 :
701 22 : spdm_response_size = sizeof(spdm_key_exchange_response_t) +
702 22 : dhe_key_size + measurement_summary_hash_size +
703 22 : sizeof(uint16_t) + opaque_length + signature_size + hmac_size;
704 :
705 22 : rsp_session_id = spdm_response->rsp_session_id;
706 22 : *session_id = libspdm_generate_session_id(req_session_id, rsp_session_id);
707 22 : session_info = libspdm_assign_session_id(spdm_context, *session_id, false);
708 :
709 22 : if (session_info == NULL) {
710 0 : libspdm_secured_message_dhe_free(
711 0 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
712 0 : status = LIBSPDM_STATUS_SESSION_NUMBER_EXCEED;
713 0 : goto receive_done;
714 : }
715 :
716 : /* -=[Process Response Phase]=- */
717 22 : status = libspdm_append_message_k(spdm_context, session_info, true, spdm_request,
718 : spdm_request_size);
719 22 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
720 0 : libspdm_free_session_id(spdm_context, *session_id);
721 0 : libspdm_secured_message_dhe_free(
722 0 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
723 0 : goto receive_done;
724 : }
725 :
726 22 : status = libspdm_append_message_k(spdm_context, session_info, true, spdm_response,
727 22 : spdm_response_size - signature_size - hmac_size);
728 22 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
729 0 : libspdm_free_session_id(spdm_context, *session_id);
730 0 : libspdm_secured_message_dhe_free(
731 0 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
732 0 : goto receive_done;
733 : }
734 :
735 22 : signature = ptr;
736 22 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "signature (0x%x):\n", signature_size));
737 22 : LIBSPDM_INTERNAL_DUMP_HEX(signature, signature_size);
738 22 : ptr += signature_size;
739 22 : result = libspdm_verify_key_exchange_rsp_signature(
740 : spdm_context, session_info, signature, signature_size);
741 22 : if (!result) {
742 2 : libspdm_free_session_id(spdm_context, *session_id);
743 2 : libspdm_secured_message_dhe_free(
744 2 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
745 2 : status = LIBSPDM_STATUS_VERIF_FAIL;
746 2 : goto receive_done;
747 : }
748 :
749 20 : status = libspdm_append_message_k(spdm_context, session_info, true, signature, signature_size);
750 20 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
751 0 : libspdm_free_session_id(spdm_context, *session_id);
752 0 : libspdm_secured_message_dhe_free(
753 0 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
754 0 : goto receive_done;
755 : }
756 :
757 20 : result = libspdm_secured_message_dhe_compute_key(
758 20 : spdm_context->connection_info.algorithm.dhe_named_group,
759 20 : dhe_context, spdm_response->exchange_data, dhe_key_size,
760 : session_info->secured_message_context);
761 20 : libspdm_secured_message_dhe_free(
762 20 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
763 20 : if (!result) {
764 0 : libspdm_free_session_id(spdm_context, *session_id);
765 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
766 0 : goto receive_done;
767 : }
768 :
769 20 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "libspdm_generate_session_handshake_key[%x]\n",
770 : *session_id));
771 20 : result = libspdm_calculate_th1_hash(spdm_context, session_info, true, th1_hash_data);
772 20 : if (!result) {
773 0 : libspdm_free_session_id(spdm_context, *session_id);
774 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
775 0 : goto receive_done;
776 : }
777 20 : result = libspdm_generate_session_handshake_key(
778 : session_info->secured_message_context, th1_hash_data);
779 20 : if (!result) {
780 0 : libspdm_free_session_id(spdm_context, *session_id);
781 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
782 0 : goto receive_done;
783 : }
784 :
785 20 : if (!libspdm_is_capabilities_flag_supported(
786 : spdm_context, true,
787 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
788 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
789 19 : verify_data = ptr;
790 19 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "verify_data (0x%x):\n", hmac_size));
791 19 : LIBSPDM_INTERNAL_DUMP_HEX(verify_data, hmac_size);
792 19 : result = libspdm_verify_key_exchange_rsp_hmac(
793 : spdm_context, session_info, verify_data, hmac_size);
794 19 : if (!result) {
795 0 : libspdm_free_session_id(spdm_context, *session_id);
796 0 : status = LIBSPDM_STATUS_VERIF_FAIL;
797 0 : goto receive_done;
798 : }
799 19 : ptr += hmac_size;
800 :
801 19 : status = libspdm_append_message_k(spdm_context, session_info, true, verify_data, hmac_size);
802 19 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
803 0 : libspdm_free_session_id(spdm_context, *session_id);
804 0 : goto receive_done;
805 : }
806 : }
807 :
808 20 : if (measurement_hash != NULL) {
809 20 : libspdm_copy_mem(measurement_hash, measurement_summary_hash_size,
810 : measurement_summary_hash, measurement_summary_hash_size);
811 : }
812 20 : session_info->heartbeat_period = spdm_response->header.param1;
813 20 : session_info->mut_auth_requested = mut_auth_requested;
814 20 : session_info->session_policy = session_policy;
815 :
816 : /* -=[Update State Phase]=- */
817 20 : libspdm_secured_message_set_session_state(
818 : session_info->secured_message_context, LIBSPDM_SESSION_STATE_HANDSHAKING);
819 :
820 : /* -=[Log Message Phase]=- */
821 : #if LIBSPDM_ENABLE_MSG_LOG
822 20 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
823 : #endif /* LIBSPDM_ENABLE_MSG_LOG */
824 :
825 20 : status = LIBSPDM_STATUS_SUCCESS;
826 :
827 88 : receive_done:
828 88 : libspdm_release_receiver_buffer (spdm_context);
829 88 : return status;
830 : }
831 :
832 93 : libspdm_return_t libspdm_send_receive_key_exchange(
833 : libspdm_context_t *spdm_context, uint8_t measurement_hash_type,
834 : uint8_t slot_id, uint8_t session_policy, uint32_t *session_id,
835 : uint8_t *heartbeat_period,
836 : uint8_t *req_slot_id_param, void *measurement_hash)
837 : {
838 : size_t retry;
839 : uint64_t retry_delay_time;
840 : libspdm_return_t status;
841 :
842 93 : spdm_context->crypto_request = true;
843 93 : retry = spdm_context->retry_times;
844 93 : retry_delay_time = spdm_context->retry_delay_time;
845 : do {
846 94 : status = libspdm_try_send_receive_key_exchange(
847 : spdm_context, measurement_hash_type, slot_id, session_policy,
848 : session_id, heartbeat_period, req_slot_id_param,
849 : measurement_hash,
850 : NULL, NULL, NULL, NULL, 0, NULL, NULL);
851 94 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
852 91 : return status;
853 : }
854 :
855 3 : libspdm_sleep(retry_delay_time);
856 3 : } while (retry-- != 0);
857 :
858 2 : return status;
859 : }
860 :
861 1 : libspdm_return_t libspdm_send_receive_key_exchange_ex(
862 : libspdm_context_t *spdm_context, uint8_t measurement_hash_type,
863 : uint8_t slot_id, uint8_t session_policy, uint32_t *session_id,
864 : uint8_t *heartbeat_period,
865 : uint8_t *req_slot_id_param, void *measurement_hash,
866 : const void *requester_random_in,
867 : void *requester_random, void *responder_random,
868 : const void *requester_opaque_data,
869 : size_t requester_opaque_data_size,
870 : void *responder_opaque_data,
871 : size_t *responder_opaque_data_size)
872 : {
873 : size_t retry;
874 : uint64_t retry_delay_time;
875 : libspdm_return_t status;
876 :
877 1 : spdm_context->crypto_request = true;
878 1 : retry = spdm_context->retry_times;
879 1 : retry_delay_time = spdm_context->retry_delay_time;
880 : do {
881 1 : status = libspdm_try_send_receive_key_exchange(
882 : spdm_context, measurement_hash_type, slot_id, session_policy,
883 : session_id, heartbeat_period, req_slot_id_param,
884 : measurement_hash, requester_random_in,
885 : requester_random, responder_random,
886 : requester_opaque_data, requester_opaque_data_size,
887 : responder_opaque_data, responder_opaque_data_size);
888 1 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
889 1 : return status;
890 : }
891 :
892 0 : libspdm_sleep(retry_delay_time);
893 0 : } while (retry-- != 0);
894 :
895 0 : return status;
896 : }
897 :
898 : #endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP */
|