1 /**
2 * Copyright Notice:
3 * Copyright 2021-2022 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
libspdm_verify_key_exchange_rsp_hmac(libspdm_context_t * spdm_context,libspdm_session_info_t * session_info,const void * hmac_data,size_t hmac_data_size)39 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 hash_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
58 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 result = libspdm_calculate_th_hmac_for_exchange_rsp(
97 spdm_context, session_info, true, &hash_size, calc_hmac_data);
98 if (!result) {
99 return false;
100 }
101 #endif
102 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "th_curr hmac - "));
103 LIBSPDM_INTERNAL_DUMP_DATA(calc_hmac_data, hash_size);
104 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
105
106 if (!libspdm_consttime_is_mem_equal(calc_hmac_data, hmac_data, hash_size)) {
107 LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "!!! verify_key_exchange_hmac - FAIL !!!\n"));
108 return false;
109 }
110 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "!!! verify_key_exchange_hmac - PASS !!!\n"));
111
112 return true;
113 }
114
libspdm_verify_key_exchange_rsp_signature(libspdm_context_t * spdm_context,libspdm_session_info_t * session_info,const void * sign_data,const size_t sign_data_size)115 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 hash_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
138 #endif
139
140 slot_id = spdm_context->connection_info.peer_used_cert_chain_slot_id;
141 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 result = libspdm_calculate_th_hash_for_exchange(
174 spdm_context, session_info, &hash_size, hash_data);
175 if (!result) {
176 return false;
177 }
178 #endif
179 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "th_curr hash - "));
180 LIBSPDM_INTERNAL_DUMP_DATA(hash_data, hash_size);
181 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
182
183 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "signature - "));
184 LIBSPDM_INTERNAL_DUMP_DATA(sign_data, sign_data_size);
185 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
186
187 if (slot_id == 0xFF) {
188 result = libspdm_asym_get_public_key_from_der(
189 spdm_context->connection_info.algorithm.base_asym_algo,
190 spdm_context->local_context.peer_public_key_provision,
191 spdm_context->local_context.peer_public_key_provision_size,
192 &context);
193 if (!result) {
194 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 context = spdm_context->connection_info.peer_used_cert_chain[slot_id].leaf_cert_public_key;
218 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 result = libspdm_asym_verify_hash_ex(
232 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 if (slot_id == 0xFF) {
238 libspdm_asym_free(spdm_context->connection_info.algorithm.base_asym_algo, context);
239 }
240 #endif
241 if (!result) {
242 LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "!!! verify_key_exchange_signature - FAIL !!!\n"));
243 return false;
244 }
245 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "!!! verify_key_exchange_signature - PASS !!!\n"));
246
247 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 **/
libspdm_try_send_receive_key_exchange(libspdm_context_t * spdm_context,uint8_t measurement_hash_type,uint8_t slot_id,uint8_t session_policy,uint32_t * session_id,uint8_t * heartbeat_period,uint8_t * req_slot_id_param,void * measurement_hash,const void * requester_random_in,void * requester_random,void * responder_random,const void * requester_opaque_data,size_t requester_opaque_data_size,void * responder_opaque_data,size_t * responder_opaque_data_size)265 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 LIBSPDM_ASSERT((slot_id < SPDM_MAX_SLOT_COUNT) || (slot_id == 0xff));
303 LIBSPDM_ASSERT((slot_id != 0xff) ||
304 (spdm_context->local_context.peer_public_key_provision_size != 0));
305 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
309 /* -=[Verify State Phase]=- */
310 if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
311 return LIBSPDM_STATUS_UNSUPPORTED_CAP;
312 }
313
314 if (!libspdm_is_capabilities_flag_supported(
315 spdm_context, true,
316 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_EX_CAP,
317 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP)) {
318 return LIBSPDM_STATUS_UNSUPPORTED_CAP;
319 }
320 if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
321 return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
322 }
323 if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
324 if ((spdm_context->connection_info.algorithm.other_params_support &
325 SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) != SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1) {
326 return LIBSPDM_STATUS_INVALID_STATE_PEER;
327 }
328 }
329
330 req_session_id = libspdm_allocate_req_session_id(spdm_context, false);
331 if (req_session_id == (INVALID_SESSION_ID & 0xFFFF)) {
332 return LIBSPDM_STATUS_SESSION_NUMBER_EXCEED;
333 }
334
335 libspdm_reset_message_buffer_via_request_code(spdm_context, NULL, SPDM_KEY_EXCHANGE);
336
337 /* -=[Construct Request Phase]=- */
338 spdm_context->connection_info.peer_used_cert_chain_slot_id = slot_id;
339 transport_header_size = spdm_context->local_context.capability.transport_header_size;
340 status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
341 if (LIBSPDM_STATUS_IS_ERROR(status)) {
342 return status;
343 }
344 LIBSPDM_ASSERT (message_size >= transport_header_size +
345 spdm_context->local_context.capability.transport_tail_size);
346 spdm_request = (void *)(message + transport_header_size);
347 spdm_request_size = message_size - transport_header_size -
348 spdm_context->local_context.capability.transport_tail_size;
349
350 spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
351 spdm_request->header.request_response_code = SPDM_KEY_EXCHANGE;
352 spdm_request->header.param1 = measurement_hash_type;
353 spdm_request->header.param2 = slot_id;
354 if (requester_random_in == NULL) {
355 if(!libspdm_get_random_number(SPDM_RANDOM_DATA_SIZE, spdm_request->random_data)) {
356 libspdm_release_sender_buffer (spdm_context);
357 return LIBSPDM_STATUS_LOW_ENTROPY;
358 }
359 } else {
360 libspdm_copy_mem(spdm_request->random_data, sizeof(spdm_request->random_data),
361 requester_random_in, SPDM_RANDOM_DATA_SIZE);
362 }
363 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "RequesterRandomData (0x%x) - ",
364 SPDM_RANDOM_DATA_SIZE));
365 LIBSPDM_INTERNAL_DUMP_DATA(spdm_request->random_data, SPDM_RANDOM_DATA_SIZE);
366 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
367 if (requester_random != NULL) {
368 libspdm_copy_mem(requester_random, SPDM_RANDOM_DATA_SIZE,
369 spdm_request->random_data, SPDM_RANDOM_DATA_SIZE);
370 }
371
372 spdm_request->req_session_id = req_session_id;
373 if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
374 spdm_request->session_policy = session_policy;
375 } else {
376 spdm_request->session_policy = 0;
377 }
378 spdm_request->reserved = 0;
379
380 ptr = spdm_request->exchange_data;
381 dhe_key_size = libspdm_get_dhe_pub_key_size(
382 spdm_context->connection_info.algorithm.dhe_named_group);
383 dhe_context = libspdm_secured_message_dhe_new(
384 spdm_context->connection_info.version,
385 spdm_context->connection_info.algorithm.dhe_named_group, true);
386 if (dhe_context == NULL) {
387 libspdm_release_sender_buffer (spdm_context);
388 return LIBSPDM_STATUS_CRYPTO_ERROR;
389 }
390
391 result = libspdm_secured_message_dhe_generate_key(
392 spdm_context->connection_info.algorithm.dhe_named_group,
393 dhe_context, ptr, &dhe_key_size);
394 if (!result) {
395 libspdm_secured_message_dhe_free(
396 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
397 libspdm_release_sender_buffer (spdm_context);
398 return LIBSPDM_STATUS_CRYPTO_ERROR;
399 }
400 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "RequesterKey (0x%x):\n", dhe_key_size));
401 LIBSPDM_INTERNAL_DUMP_HEX(ptr, dhe_key_size);
402 ptr += dhe_key_size;
403
404 if (requester_opaque_data != NULL) {
405 LIBSPDM_ASSERT(requester_opaque_data_size <= SPDM_MAX_OPAQUE_DATA_SIZE);
406
407 libspdm_write_uint16(ptr, (uint16_t)requester_opaque_data_size);
408 ptr += sizeof(uint16_t);
409
410 libspdm_copy_mem(ptr,
411 (spdm_request_size - (sizeof(spdm_key_exchange_request_t) + dhe_key_size)),
412 requester_opaque_data, requester_opaque_data_size);
413 opaque_key_exchange_req_size = requester_opaque_data_size;
414 } else {
415 opaque_key_exchange_req_size =
416 libspdm_get_opaque_data_supported_version_data_size(spdm_context);
417 libspdm_write_uint16(ptr, (uint16_t)opaque_key_exchange_req_size);
418 ptr += sizeof(uint16_t);
419
420 libspdm_build_opaque_data_supported_version_data(
421 spdm_context, &opaque_key_exchange_req_size, ptr);
422 }
423 ptr += opaque_key_exchange_req_size;
424
425 spdm_request_size = (size_t)ptr - (size_t)spdm_request;
426
427 /* -=[Send Request Phase]=- */
428 status = libspdm_send_spdm_request(spdm_context, NULL, spdm_request_size, spdm_request);
429 if (LIBSPDM_STATUS_IS_ERROR(status)) {
430 libspdm_secured_message_dhe_free(
431 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
432 libspdm_release_sender_buffer (spdm_context);
433 return status;
434 }
435 libspdm_release_sender_buffer (spdm_context);
436 spdm_request = (void *)spdm_context->last_spdm_request;
437
438 /* -=[Receive Response Phase]=- */
439 status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
440 if (LIBSPDM_STATUS_IS_ERROR(status)) {
441 libspdm_secured_message_dhe_free(
442 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
443 return status;
444 }
445 LIBSPDM_ASSERT (message_size >= transport_header_size);
446 spdm_response = (void *)(message);
447 spdm_response_size = message_size;
448
449 libspdm_zero_mem(spdm_response, spdm_response_size);
450 status = libspdm_receive_spdm_response(
451 spdm_context, NULL, &spdm_response_size, (void **)&spdm_response);
452 if (LIBSPDM_STATUS_IS_ERROR(status)) {
453 libspdm_secured_message_dhe_free(
454 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
455 goto receive_done;
456 }
457
458 /* -=[Validate Response Phase]=- */
459 if (spdm_response_size < sizeof(spdm_message_header_t)) {
460 libspdm_secured_message_dhe_free(
461 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
462 status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
463 goto receive_done;
464 }
465 if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
466 libspdm_secured_message_dhe_free(
467 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
468 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
469 goto receive_done;
470 }
471 if (spdm_response->header.request_response_code == SPDM_ERROR) {
472 status = libspdm_handle_error_response_main(
473 spdm_context, NULL, &spdm_response_size,
474 (void **)&spdm_response, SPDM_KEY_EXCHANGE,
475 SPDM_KEY_EXCHANGE_RSP);
476 if (LIBSPDM_STATUS_IS_ERROR(status)) {
477 libspdm_secured_message_dhe_free(
478 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
479 goto receive_done;
480 }
481 } else if (spdm_response->header.request_response_code != SPDM_KEY_EXCHANGE_RSP) {
482 libspdm_secured_message_dhe_free(
483 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
484 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
485 goto receive_done;
486 }
487 if (spdm_response_size < sizeof(spdm_key_exchange_response_t)) {
488 libspdm_secured_message_dhe_free(
489 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
490 status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
491 goto receive_done;
492 }
493
494 if (!libspdm_is_capabilities_flag_supported(
495 spdm_context, true,
496 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP,
497 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP)) {
498 if (spdm_response->header.param1 != 0) {
499 libspdm_secured_message_dhe_free(
500 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
501 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
502 goto receive_done;
503 }
504 }
505 if (heartbeat_period != NULL) {
506 *heartbeat_period = spdm_response->header.param1;
507 }
508
509 *req_slot_id_param = spdm_response->req_slot_id_param & 0xf;
510 mut_auth_requested = spdm_response->mut_auth_requested & 0x7;
511
512 if (mut_auth_requested != 0) {
513 if (!libspdm_is_capabilities_flag_supported(
514 spdm_context, true,
515 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MUT_AUTH_CAP,
516 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MUT_AUTH_CAP)) {
517 libspdm_secured_message_dhe_free(
518 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
519 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
520 goto receive_done;
521 }
522 if ((mut_auth_requested != SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED) &&
523 (mut_auth_requested !=
524 SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_ENCAP_REQUEST) &&
525 (mut_auth_requested !=
526 SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_GET_DIGESTS)) {
527 libspdm_secured_message_dhe_free(
528 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
529 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
530 goto receive_done;
531 }
532 if (mut_auth_requested == SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED) {
533 if ((*req_slot_id_param != 0xF) && (*req_slot_id_param >= SPDM_MAX_SLOT_COUNT)) {
534 libspdm_secured_message_dhe_free(
535 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
536 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
537 goto receive_done;
538 }
539 }
540 }
541
542 signature_size = libspdm_get_asym_signature_size(
543 spdm_context->connection_info.algorithm.base_asym_algo);
544 measurement_summary_hash_size = libspdm_get_measurement_summary_hash_size(
545 spdm_context, true, measurement_hash_type);
546 hmac_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
547
548 if (libspdm_is_capabilities_flag_supported(
549 spdm_context, true,
550 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
551 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
552 hmac_size = 0;
553 }
554
555 if (spdm_response_size <
556 sizeof(spdm_key_exchange_response_t) + dhe_key_size +
557 measurement_summary_hash_size + sizeof(uint16_t) + signature_size + hmac_size) {
558 libspdm_secured_message_dhe_free(
559 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
560 status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
561 goto receive_done;
562 }
563
564 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "ResponderRandomData (0x%x) - ", SPDM_RANDOM_DATA_SIZE));
565 LIBSPDM_INTERNAL_DUMP_DATA(spdm_response->random_data, SPDM_RANDOM_DATA_SIZE);
566 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
567 if (responder_random != NULL) {
568 libspdm_copy_mem(responder_random, SPDM_RANDOM_DATA_SIZE,
569 spdm_response->random_data, SPDM_RANDOM_DATA_SIZE);
570 }
571
572 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "ResponderKey (0x%x):\n", dhe_key_size));
573 LIBSPDM_INTERNAL_DUMP_HEX(spdm_response->exchange_data, dhe_key_size);
574
575 ptr = spdm_response->exchange_data;
576 ptr += dhe_key_size;
577
578 measurement_summary_hash = ptr;
579 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "measurement_summary_hash (0x%x) - ",
580 measurement_summary_hash_size));
581 LIBSPDM_INTERNAL_DUMP_DATA(measurement_summary_hash, measurement_summary_hash_size);
582 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
583
584 ptr += measurement_summary_hash_size;
585
586 opaque_length = libspdm_read_uint16((const uint8_t *)ptr);
587 if (opaque_length > SPDM_MAX_OPAQUE_DATA_SIZE) {
588 libspdm_secured_message_dhe_free(
589 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
590 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
591 goto receive_done;
592 }
593 ptr += sizeof(uint16_t);
594 if (spdm_response_size <
595 sizeof(spdm_key_exchange_response_t) + dhe_key_size +
596 measurement_summary_hash_size + sizeof(uint16_t) +
597 opaque_length + signature_size + hmac_size) {
598 libspdm_secured_message_dhe_free(
599 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
600 status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
601 goto receive_done;
602 }
603 if (opaque_length != 0) {
604 result = libspdm_process_general_opaque_data_check(spdm_context, opaque_length, ptr);
605 if (!result) {
606 libspdm_secured_message_dhe_free(
607 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
608 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
609 goto receive_done;
610 }
611 status = libspdm_process_opaque_data_version_selection_data(
612 spdm_context, opaque_length, ptr);
613 if (LIBSPDM_STATUS_IS_ERROR(status)) {
614 libspdm_secured_message_dhe_free(
615 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
616 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
617 goto receive_done;
618 }
619 }
620
621 if ((responder_opaque_data != NULL) && (responder_opaque_data_size != NULL)) {
622 if (opaque_length >= *responder_opaque_data_size) {
623 libspdm_secured_message_dhe_free(
624 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
625 status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
626 goto receive_done;
627 }
628 libspdm_copy_mem(responder_opaque_data, *responder_opaque_data_size, ptr, opaque_length);
629 *responder_opaque_data_size = opaque_length;
630 }
631
632 ptr += opaque_length;
633
634 spdm_response_size = sizeof(spdm_key_exchange_response_t) +
635 dhe_key_size + measurement_summary_hash_size +
636 sizeof(uint16_t) + opaque_length + signature_size + hmac_size;
637
638 rsp_session_id = spdm_response->rsp_session_id;
639 *session_id = libspdm_generate_session_id(req_session_id, rsp_session_id);
640 session_info = libspdm_assign_session_id(spdm_context, *session_id, false);
641
642 if (session_info == NULL) {
643 libspdm_secured_message_dhe_free(
644 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
645 status = LIBSPDM_STATUS_SESSION_NUMBER_EXCEED;
646 goto receive_done;
647 }
648
649 /* -=[Process Response Phase]=- */
650 status = libspdm_append_message_k(spdm_context, session_info, true, spdm_request,
651 spdm_request_size);
652 if (LIBSPDM_STATUS_IS_ERROR(status)) {
653 libspdm_free_session_id(spdm_context, *session_id);
654 libspdm_secured_message_dhe_free(
655 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
656 goto receive_done;
657 }
658
659 status = libspdm_append_message_k(spdm_context, session_info, true, spdm_response,
660 spdm_response_size - signature_size - hmac_size);
661 if (LIBSPDM_STATUS_IS_ERROR(status)) {
662 libspdm_free_session_id(spdm_context, *session_id);
663 libspdm_secured_message_dhe_free(
664 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
665 goto receive_done;
666 }
667
668 signature = ptr;
669 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "signature (0x%x):\n", signature_size));
670 LIBSPDM_INTERNAL_DUMP_HEX(signature, signature_size);
671 ptr += signature_size;
672 result = libspdm_verify_key_exchange_rsp_signature(
673 spdm_context, session_info, signature, signature_size);
674 if (!result) {
675 libspdm_free_session_id(spdm_context, *session_id);
676 libspdm_secured_message_dhe_free(
677 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
678 status = LIBSPDM_STATUS_VERIF_FAIL;
679 goto receive_done;
680 }
681
682 status = libspdm_append_message_k(spdm_context, session_info, true, signature, signature_size);
683 if (LIBSPDM_STATUS_IS_ERROR(status)) {
684 libspdm_free_session_id(spdm_context, *session_id);
685 libspdm_secured_message_dhe_free(
686 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
687 goto receive_done;
688 }
689
690 result = libspdm_secured_message_dhe_compute_key(
691 spdm_context->connection_info.algorithm.dhe_named_group,
692 dhe_context, spdm_response->exchange_data, dhe_key_size,
693 session_info->secured_message_context);
694 libspdm_secured_message_dhe_free(
695 spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
696 if (!result) {
697 libspdm_free_session_id(spdm_context, *session_id);
698 status = LIBSPDM_STATUS_CRYPTO_ERROR;
699 goto receive_done;
700 }
701
702 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "libspdm_generate_session_handshake_key[%x]\n",
703 *session_id));
704 result = libspdm_calculate_th1_hash(spdm_context, session_info, true, th1_hash_data);
705 if (!result) {
706 libspdm_free_session_id(spdm_context, *session_id);
707 status = LIBSPDM_STATUS_CRYPTO_ERROR;
708 goto receive_done;
709 }
710 result = libspdm_generate_session_handshake_key(
711 session_info->secured_message_context, th1_hash_data);
712 if (!result) {
713 libspdm_free_session_id(spdm_context, *session_id);
714 status = LIBSPDM_STATUS_CRYPTO_ERROR;
715 goto receive_done;
716 }
717
718 if (!libspdm_is_capabilities_flag_supported(
719 spdm_context, true,
720 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
721 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
722 verify_data = ptr;
723 LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "verify_data (0x%x):\n", hmac_size));
724 LIBSPDM_INTERNAL_DUMP_HEX(verify_data, hmac_size);
725 result = libspdm_verify_key_exchange_rsp_hmac(
726 spdm_context, session_info, verify_data, hmac_size);
727 if (!result) {
728 libspdm_free_session_id(spdm_context, *session_id);
729 status = LIBSPDM_STATUS_VERIF_FAIL;
730 goto receive_done;
731 }
732 ptr += hmac_size;
733
734 status = libspdm_append_message_k(spdm_context, session_info, true, verify_data, hmac_size);
735 if (LIBSPDM_STATUS_IS_ERROR(status)) {
736 libspdm_free_session_id(spdm_context, *session_id);
737 goto receive_done;
738 }
739 }
740
741 if (measurement_hash != NULL) {
742 libspdm_copy_mem(measurement_hash, measurement_summary_hash_size,
743 measurement_summary_hash, measurement_summary_hash_size);
744 }
745 session_info->heartbeat_period = spdm_response->header.param1;
746 session_info->mut_auth_requested = mut_auth_requested;
747 session_info->session_policy = session_policy;
748
749 /* -=[Update State Phase]=- */
750 libspdm_secured_message_set_session_state(
751 session_info->secured_message_context, LIBSPDM_SESSION_STATE_HANDSHAKING);
752
753 /* -=[Log Message Phase]=- */
754 #if LIBSPDM_ENABLE_MSG_LOG
755 libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
756 #endif /* LIBSPDM_ENABLE_MSG_LOG */
757
758 status = LIBSPDM_STATUS_SUCCESS;
759
760 receive_done:
761 libspdm_release_receiver_buffer (spdm_context);
762 return status;
763 }
764
libspdm_send_receive_key_exchange(libspdm_context_t * spdm_context,uint8_t measurement_hash_type,uint8_t slot_id,uint8_t session_policy,uint32_t * session_id,uint8_t * heartbeat_period,uint8_t * req_slot_id_param,void * measurement_hash)765 libspdm_return_t libspdm_send_receive_key_exchange(
766 libspdm_context_t *spdm_context, uint8_t measurement_hash_type,
767 uint8_t slot_id, uint8_t session_policy, uint32_t *session_id,
768 uint8_t *heartbeat_period,
769 uint8_t *req_slot_id_param, void *measurement_hash)
770 {
771 size_t retry;
772 uint64_t retry_delay_time;
773 libspdm_return_t status;
774
775 spdm_context->crypto_request = true;
776 retry = spdm_context->retry_times;
777 retry_delay_time = spdm_context->retry_delay_time;
778 do {
779 status = libspdm_try_send_receive_key_exchange(
780 spdm_context, measurement_hash_type, slot_id, session_policy,
781 session_id, heartbeat_period, req_slot_id_param,
782 measurement_hash,
783 NULL, NULL, NULL, NULL, 0, NULL, NULL);
784 if ((status != LIBSPDM_STATUS_BUSY_PEER) || (retry == 0)) {
785 return status;
786 }
787
788 libspdm_sleep(retry_delay_time);
789 } while (retry-- != 0);
790
791 return status;
792 }
793
libspdm_send_receive_key_exchange_ex(libspdm_context_t * spdm_context,uint8_t measurement_hash_type,uint8_t slot_id,uint8_t session_policy,uint32_t * session_id,uint8_t * heartbeat_period,uint8_t * req_slot_id_param,void * measurement_hash,const void * requester_random_in,void * requester_random,void * responder_random,const void * requester_opaque_data,size_t requester_opaque_data_size,void * responder_opaque_data,size_t * responder_opaque_data_size)794 libspdm_return_t libspdm_send_receive_key_exchange_ex(
795 libspdm_context_t *spdm_context, uint8_t measurement_hash_type,
796 uint8_t slot_id, uint8_t session_policy, uint32_t *session_id,
797 uint8_t *heartbeat_period,
798 uint8_t *req_slot_id_param, void *measurement_hash,
799 const void *requester_random_in,
800 void *requester_random, void *responder_random,
801 const void *requester_opaque_data,
802 size_t requester_opaque_data_size,
803 void *responder_opaque_data,
804 size_t *responder_opaque_data_size)
805 {
806 size_t retry;
807 uint64_t retry_delay_time;
808 libspdm_return_t status;
809
810 spdm_context->crypto_request = true;
811 retry = spdm_context->retry_times;
812 retry_delay_time = spdm_context->retry_delay_time;
813 do {
814 status = libspdm_try_send_receive_key_exchange(
815 spdm_context, measurement_hash_type, slot_id, session_policy,
816 session_id, heartbeat_period, req_slot_id_param,
817 measurement_hash, requester_random_in,
818 requester_random, responder_random,
819 requester_opaque_data, requester_opaque_data_size,
820 responder_opaque_data, responder_opaque_data_size);
821 if ((status != LIBSPDM_STATUS_BUSY_PEER) || (retry == 0)) {
822 return status;
823 }
824
825 libspdm_sleep(retry_delay_time);
826 } while (retry-- != 0);
827
828 return status;
829 }
830
831 #endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP */
832