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