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     uint8_t signature[LIBSPDM_MAX_ASYM_KEY_SIZE];
16     uint8_t verify_data[LIBSPDM_MAX_HASH_SIZE];
17 } libspdm_finish_request_mine_t;
18 
19 typedef struct {
20     spdm_message_header_t header;
21     uint8_t verify_data[LIBSPDM_MAX_HASH_SIZE];
22 } libspdm_finish_response_mine_t;
23 #pragma pack()
24 
libspdm_verify_finish_rsp_hmac(libspdm_context_t * spdm_context,libspdm_session_info_t * session_info,const void * hmac_data,size_t hmac_data_size)25 bool libspdm_verify_finish_rsp_hmac(libspdm_context_t *spdm_context,
26                                     libspdm_session_info_t *session_info,
27                                     const void *hmac_data, size_t hmac_data_size)
28 {
29     size_t hash_size;
30     uint8_t calc_hmac_data[LIBSPDM_MAX_HASH_SIZE];
31     bool result;
32 #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
33     uint8_t slot_id;
34     uint8_t *cert_chain_buffer;
35     size_t cert_chain_buffer_size;
36     uint8_t *mut_cert_chain_buffer;
37     size_t mut_cert_chain_buffer_size;
38     uint8_t *th_curr_data;
39     size_t th_curr_data_size;
40     libspdm_th_managed_buffer_t th_curr;
41     uint8_t hash_data[LIBSPDM_MAX_HASH_SIZE];
42 #endif
43 
44     hash_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
45     LIBSPDM_ASSERT(hash_size == hmac_data_size);
46 
47 #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
48     slot_id = spdm_context->connection_info.peer_used_cert_chain_slot_id;
49     LIBSPDM_ASSERT((slot_id < SPDM_MAX_SLOT_COUNT) || (slot_id == 0xFF));
50     if (slot_id == 0xFF) {
51         result = libspdm_get_peer_public_key_buffer(
52             spdm_context, (const void **)&cert_chain_buffer, &cert_chain_buffer_size);
53     } else {
54         result = libspdm_get_peer_cert_chain_buffer(
55             spdm_context, (const void **)&cert_chain_buffer, &cert_chain_buffer_size);
56     }
57     if (!result) {
58         return false;
59     }
60 
61     if (session_info->mut_auth_requested) {
62         slot_id = spdm_context->connection_info.local_used_cert_chain_slot_id;
63         LIBSPDM_ASSERT((slot_id < SPDM_MAX_SLOT_COUNT) || (slot_id == 0xFF));
64         if (slot_id == 0xFF) {
65             result = libspdm_get_local_public_key_buffer(
66                 spdm_context, (const void **)&mut_cert_chain_buffer, &mut_cert_chain_buffer_size);
67         } else {
68             result = libspdm_get_local_cert_chain_buffer(
69                 spdm_context, (const void **)&mut_cert_chain_buffer, &mut_cert_chain_buffer_size);
70         }
71         if (!result) {
72             return false;
73         }
74     } else {
75         mut_cert_chain_buffer = NULL;
76         mut_cert_chain_buffer_size = 0;
77     }
78 
79     result = libspdm_calculate_th_for_finish(
80         spdm_context, session_info, cert_chain_buffer,
81         cert_chain_buffer_size, mut_cert_chain_buffer,
82         mut_cert_chain_buffer_size, &th_curr);
83     if (!result) {
84         return false;
85     }
86     th_curr_data = libspdm_get_managed_buffer(&th_curr);
87     th_curr_data_size = libspdm_get_managed_buffer_size(&th_curr);
88 
89     result = libspdm_hash_all (spdm_context->connection_info.algorithm.base_hash_algo,
90                                th_curr_data, th_curr_data_size, hash_data);
91     if (!result) {
92         return false;
93     }
94 
95     result = libspdm_hmac_all_with_response_finished_key(
96         session_info->secured_message_context, hash_data,
97         hash_size, calc_hmac_data);
98     if (!result) {
99         return false;
100     }
101 #else
102     result = libspdm_calculate_th_hmac_for_finish_rsp(
103         spdm_context, session_info, &hash_size, calc_hmac_data);
104     if (!result) {
105         return false;
106     }
107 #endif
108     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "th_curr hmac - "));
109     LIBSPDM_INTERNAL_DUMP_DATA(calc_hmac_data, hash_size);
110     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
111 
112     if (!libspdm_consttime_is_mem_equal(calc_hmac_data, hmac_data, hash_size)) {
113         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "!!! verify_finish_rsp_hmac - FAIL !!!\n"));
114         return false;
115     }
116     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "!!! verify_finish_rsp_hmac - PASS !!!\n"));
117 
118     return true;
119 }
120 
libspdm_generate_finish_req_hmac(libspdm_context_t * spdm_context,libspdm_session_info_t * session_info,void * hmac)121 bool libspdm_generate_finish_req_hmac(libspdm_context_t *spdm_context,
122                                       libspdm_session_info_t *session_info,
123                                       void *hmac)
124 {
125     size_t hash_size;
126     uint8_t calc_hmac_data[LIBSPDM_MAX_HASH_SIZE];
127     bool result;
128 #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
129     uint8_t slot_id;
130     uint8_t *cert_chain_buffer;
131     size_t cert_chain_buffer_size;
132     uint8_t *mut_cert_chain_buffer;
133     size_t mut_cert_chain_buffer_size;
134     uint8_t *th_curr_data;
135     size_t th_curr_data_size;
136     libspdm_th_managed_buffer_t th_curr;
137     uint8_t hash_data[LIBSPDM_MAX_HASH_SIZE];
138 #endif
139 
140     hash_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
141 
142 #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
143     slot_id = spdm_context->connection_info.peer_used_cert_chain_slot_id;
144     LIBSPDM_ASSERT((slot_id < SPDM_MAX_SLOT_COUNT) || (slot_id == 0xFF));
145     if (slot_id == 0xFF) {
146         result = libspdm_get_peer_public_key_buffer(
147             spdm_context, (const void **)&cert_chain_buffer, &cert_chain_buffer_size);
148     } else {
149         result = libspdm_get_peer_cert_chain_buffer(
150             spdm_context, (const void **)&cert_chain_buffer, &cert_chain_buffer_size);
151     }
152     if (!result) {
153         return false;
154     }
155 
156     if (session_info->mut_auth_requested) {
157         slot_id = spdm_context->connection_info.local_used_cert_chain_slot_id;
158         LIBSPDM_ASSERT((slot_id < SPDM_MAX_SLOT_COUNT) || (slot_id == 0xFF));
159         if (slot_id == 0xFF) {
160             result = libspdm_get_local_public_key_buffer(
161                 spdm_context, (const void **)&mut_cert_chain_buffer, &mut_cert_chain_buffer_size);
162         } else {
163             result = libspdm_get_local_cert_chain_buffer(
164                 spdm_context, (const void **)&mut_cert_chain_buffer, &mut_cert_chain_buffer_size);
165         }
166         if (!result) {
167             return false;
168         }
169     } else {
170         mut_cert_chain_buffer = NULL;
171         mut_cert_chain_buffer_size = 0;
172     }
173 
174     result = libspdm_calculate_th_for_finish(
175         spdm_context, session_info, cert_chain_buffer,
176         cert_chain_buffer_size, mut_cert_chain_buffer,
177         mut_cert_chain_buffer_size, &th_curr);
178     if (!result) {
179         return false;
180     }
181     th_curr_data = libspdm_get_managed_buffer(&th_curr);
182     th_curr_data_size = libspdm_get_managed_buffer_size(&th_curr);
183 
184     result = libspdm_hash_all (spdm_context->connection_info.algorithm.base_hash_algo,
185                                th_curr_data, th_curr_data_size, hash_data);
186     if (!result) {
187         return false;
188     }
189 
190     result = libspdm_hmac_all_with_request_finished_key(
191         session_info->secured_message_context, hash_data,
192         hash_size, calc_hmac_data);
193     if (!result) {
194         return false;
195     }
196 #else
197     result = libspdm_calculate_th_hmac_for_finish_req(
198         spdm_context, session_info, &hash_size, calc_hmac_data);
199     if (!result) {
200         return false;
201     }
202 #endif
203     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "th_curr hmac - "));
204     LIBSPDM_INTERNAL_DUMP_DATA(calc_hmac_data, hash_size);
205     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
206 
207     libspdm_copy_mem(hmac, hash_size, calc_hmac_data, hash_size);
208 
209     return true;
210 }
211 
212 #if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP
213 
libspdm_generate_finish_req_signature(libspdm_context_t * spdm_context,libspdm_session_info_t * session_info,uint8_t * signature)214 bool libspdm_generate_finish_req_signature(libspdm_context_t *spdm_context,
215                                            libspdm_session_info_t *session_info,
216                                            uint8_t *signature)
217 {
218     bool result;
219     size_t signature_size;
220 #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
221     uint8_t slot_id;
222     uint8_t *cert_chain_buffer;
223     size_t cert_chain_buffer_size;
224     uint8_t *mut_cert_chain_buffer;
225     size_t mut_cert_chain_buffer_size;
226     uint8_t *th_curr_data;
227     size_t th_curr_data_size;
228     libspdm_th_managed_buffer_t th_curr;
229 #endif
230 #if !(LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT) || (LIBSPDM_DEBUG_PRINT_ENABLE)
231     size_t hash_size;
232 #endif
233 #if ((LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT) && (LIBSPDM_DEBUG_BLOCK_ENABLE)) || \
234     !(LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT)
235     uint8_t hash_data[LIBSPDM_MAX_HASH_SIZE];
236 #endif
237 
238     signature_size = libspdm_get_req_asym_signature_size(
239         spdm_context->connection_info.algorithm.req_base_asym_alg);
240 
241 #if !(LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT) || (LIBSPDM_DEBUG_PRINT_ENABLE)
242     hash_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
243 #endif
244 
245 #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
246     slot_id = spdm_context->connection_info.peer_used_cert_chain_slot_id;
247     LIBSPDM_ASSERT((slot_id < SPDM_MAX_SLOT_COUNT) || (slot_id == 0xFF));
248     if (slot_id == 0xFF) {
249         result = libspdm_get_peer_public_key_buffer(
250             spdm_context, (const void **)&cert_chain_buffer, &cert_chain_buffer_size);
251     } else {
252         result = libspdm_get_peer_cert_chain_buffer(
253             spdm_context, (const void **)&cert_chain_buffer, &cert_chain_buffer_size);
254     }
255     if (!result) {
256         return false;
257     }
258 
259     slot_id = spdm_context->connection_info.local_used_cert_chain_slot_id;
260     LIBSPDM_ASSERT((slot_id < SPDM_MAX_SLOT_COUNT) || (slot_id == 0xFF));
261     if (slot_id == 0xFF) {
262         result = libspdm_get_local_public_key_buffer(
263             spdm_context, (const void **)&mut_cert_chain_buffer, &mut_cert_chain_buffer_size);
264     } else {
265         result = libspdm_get_local_cert_chain_buffer(
266             spdm_context, (const void **)&mut_cert_chain_buffer, &mut_cert_chain_buffer_size);
267     }
268     if (!result) {
269         return false;
270     }
271 
272     result = libspdm_calculate_th_for_finish(
273         spdm_context, session_info, cert_chain_buffer,
274         cert_chain_buffer_size, mut_cert_chain_buffer,
275         mut_cert_chain_buffer_size, &th_curr);
276     if (!result) {
277         return false;
278     }
279     th_curr_data = libspdm_get_managed_buffer(&th_curr);
280     th_curr_data_size = libspdm_get_managed_buffer_size(&th_curr);
281 
282     /* Debug code only - required for debug print of th_curr below*/
283     LIBSPDM_DEBUG_CODE(
284         if (!libspdm_hash_all(
285                 spdm_context->connection_info.algorithm.base_hash_algo,
286                 th_curr_data, th_curr_data_size, hash_data)) {
287         return false;
288     }
289         );
290 #else
291     result = libspdm_calculate_th_hash_for_finish(
292         spdm_context, session_info, &hash_size, hash_data);
293     if (!result) {
294         return false;
295     }
296 #endif
297     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "th_curr hash - "));
298     LIBSPDM_INTERNAL_DUMP_DATA(hash_data, hash_size);
299     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
300 
301 #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
302     result = libspdm_requester_data_sign(
303         spdm_context->connection_info.version, SPDM_FINISH,
304         spdm_context->connection_info.algorithm.req_base_asym_alg,
305         spdm_context->connection_info.algorithm.base_hash_algo,
306         false, th_curr_data, th_curr_data_size, signature, &signature_size);
307 #else
308     result = libspdm_requester_data_sign(
309         spdm_context->connection_info.version, SPDM_FINISH,
310         spdm_context->connection_info.algorithm.req_base_asym_alg,
311         spdm_context->connection_info.algorithm.base_hash_algo,
312         true, hash_data, hash_size, signature, &signature_size);
313 #endif
314     if (result) {
315         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "signature - "));
316         LIBSPDM_INTERNAL_DUMP_DATA(signature, signature_size);
317         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
318     }
319 
320     return result;
321 }
322 #endif /* LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP */
323 
324 /**
325  * This function sends FINISH and receives FINISH_RSP for SPDM finish.
326  *
327  * @param  spdm_context       A pointer to the SPDM context.
328  * @param  session_id         session_id to the FINISH request.
329  * @param  req_slot_id_param  req_slot_id_param to the FINISH request.
330  *
331  * @retval RETURN_SUCCESS               The FINISH is sent and the FINISH_RSP is received.
332  * @retval RETURN_DEVICE_ERROR          A device error occurs when communicates with the device.
333  **/
libspdm_try_send_receive_finish(libspdm_context_t * spdm_context,uint32_t session_id,uint8_t req_slot_id_param)334 static libspdm_return_t libspdm_try_send_receive_finish(libspdm_context_t *spdm_context,
335                                                         uint32_t session_id,
336                                                         uint8_t req_slot_id_param)
337 {
338     libspdm_return_t status;
339     libspdm_finish_request_mine_t *spdm_request;
340     size_t spdm_request_size;
341     size_t signature_size;
342     size_t hmac_size;
343     libspdm_finish_response_mine_t *spdm_response;
344     size_t spdm_response_size;
345     libspdm_session_info_t *session_info;
346     uint8_t *ptr;
347     bool result;
348     uint8_t th2_hash_data[LIBSPDM_MAX_HASH_SIZE];
349     libspdm_session_state_t session_state;
350     uint8_t *message;
351     size_t message_size;
352     size_t transport_header_size;
353 
354     /* -=[Check Parameters Phase]=- */
355     if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
356         return LIBSPDM_STATUS_UNSUPPORTED_CAP;
357     }
358 
359     session_info = libspdm_get_session_info_via_session_id(spdm_context, session_id);
360     if (session_info == NULL) {
361         status = LIBSPDM_STATUS_INVALID_PARAMETER;
362         goto error;
363     }
364 
365     /* -=[Verify State Phase]=- */
366     if (!libspdm_is_capabilities_flag_supported(
367             spdm_context, true,
368             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_EX_CAP,
369             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP)) {
370         status = LIBSPDM_STATUS_UNSUPPORTED_CAP;
371         goto error;
372     }
373 
374     if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
375         status = LIBSPDM_STATUS_INVALID_STATE_LOCAL;
376         goto error;
377     }
378 
379     session_state = libspdm_secured_message_get_session_state(
380         session_info->secured_message_context);
381     if (session_state != LIBSPDM_SESSION_STATE_HANDSHAKING) {
382         status = LIBSPDM_STATUS_INVALID_STATE_LOCAL;
383         goto error;
384     }
385     if (session_info->mut_auth_requested != 0) {
386         if ((req_slot_id_param >= SPDM_MAX_SLOT_COUNT) && (req_slot_id_param != 0xFF)) {
387             status = LIBSPDM_STATUS_INVALID_PARAMETER;
388             goto error;
389         }
390     } else {
391         if (req_slot_id_param != 0) {
392             status = LIBSPDM_STATUS_INVALID_PARAMETER;
393             goto error;
394         }
395     }
396 
397     /* -=[Construct Request Phase]=- */
398     transport_header_size = spdm_context->local_context.capability.transport_header_size;
399     status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
400     if (LIBSPDM_STATUS_IS_ERROR(status)) {
401         goto error;
402     }
403     LIBSPDM_ASSERT (message_size >= transport_header_size +
404                     spdm_context->local_context.capability.transport_tail_size);
405     spdm_request = (void *)(message + transport_header_size);
406     spdm_request_size = message_size - transport_header_size -
407                         spdm_context->local_context.capability.transport_tail_size;
408 
409     spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
410     spdm_request->header.request_response_code = SPDM_FINISH;
411     spdm_request->header.param1 = 0;
412     spdm_request->header.param2 = 0;
413     signature_size = 0;
414 #if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP
415     if (session_info->mut_auth_requested) {
416         spdm_request->header.param1 = SPDM_FINISH_REQUEST_ATTRIBUTES_SIGNATURE_INCLUDED;
417         spdm_request->header.param2 = req_slot_id_param;
418         signature_size = libspdm_get_req_asym_signature_size(
419             spdm_context->connection_info.algorithm.req_base_asym_alg);
420     }
421 #endif
422 
423     spdm_context->connection_info.local_used_cert_chain_slot_id = req_slot_id_param;
424     if (session_info->mut_auth_requested && (req_slot_id_param != 0xFF)) {
425         LIBSPDM_ASSERT(req_slot_id_param < SPDM_MAX_SLOT_COUNT);
426         spdm_context->connection_info.local_used_cert_chain_buffer =
427             spdm_context->local_context.local_cert_chain_provision[req_slot_id_param];
428         spdm_context->connection_info.local_used_cert_chain_buffer_size =
429             spdm_context->local_context.local_cert_chain_provision_size[req_slot_id_param];
430     }
431 
432     hmac_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
433     spdm_request_size = sizeof(spdm_finish_request_t) + signature_size + hmac_size;
434     ptr = spdm_request->signature;
435 
436     status = libspdm_append_message_f(spdm_context, session_info, true, (uint8_t *)spdm_request,
437                                       sizeof(spdm_finish_request_t));
438     if (LIBSPDM_STATUS_IS_ERROR(status)) {
439         libspdm_release_sender_buffer (spdm_context);
440         goto error;
441     }
442 #if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP
443     if (session_info->mut_auth_requested) {
444         result = libspdm_generate_finish_req_signature(spdm_context, session_info, ptr);
445         if (!result) {
446             libspdm_release_sender_buffer (spdm_context);
447             status = LIBSPDM_STATUS_CRYPTO_ERROR;
448             goto error;
449         }
450         status = libspdm_append_message_f(spdm_context, session_info, true, ptr, signature_size);
451         if (LIBSPDM_STATUS_IS_ERROR(status)) {
452             libspdm_release_sender_buffer (spdm_context);
453             goto error;
454         }
455         ptr += signature_size;
456     }
457 #endif
458 
459     result = libspdm_generate_finish_req_hmac(spdm_context, session_info, ptr);
460     if (!result) {
461         libspdm_release_sender_buffer (spdm_context);
462         status = LIBSPDM_STATUS_CRYPTO_ERROR;
463         goto error;
464     }
465 
466     status = libspdm_append_message_f(spdm_context, session_info, true, ptr, hmac_size);
467     if (LIBSPDM_STATUS_IS_ERROR(status)) {
468         libspdm_release_sender_buffer (spdm_context);
469         goto error;
470     }
471 
472     /* -=[Send Request Phase]=- */
473     status = libspdm_send_spdm_request(spdm_context, &session_id, spdm_request_size, spdm_request);
474     if (LIBSPDM_STATUS_IS_ERROR(status)) {
475         libspdm_release_sender_buffer (spdm_context);
476         goto error;
477     }
478 
479     libspdm_reset_message_buffer_via_request_code(spdm_context, session_info, SPDM_FINISH);
480 
481     libspdm_release_sender_buffer (spdm_context);
482     spdm_request = (void *)spdm_context->last_spdm_request;
483 
484     /* -=[Receive Response Phase]=- */
485     status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
486     if (LIBSPDM_STATUS_IS_ERROR(status)) {
487         goto error;
488     }
489     LIBSPDM_ASSERT (message_size >= transport_header_size);
490     spdm_response = (void *)(message);
491     spdm_response_size = message_size;
492 
493     libspdm_zero_mem(spdm_response, spdm_response_size);
494     status = libspdm_receive_spdm_response(
495         spdm_context, &session_id, &spdm_response_size, (void **)&spdm_response);
496     if (LIBSPDM_STATUS_IS_ERROR(status)) {
497         goto receive_done;
498     }
499 
500     /* -=[Validate Response Phase]=- */
501     if (spdm_response_size < sizeof(spdm_message_header_t)) {
502         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
503         goto receive_done;
504     }
505     if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
506         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
507         goto receive_done;
508     }
509     if (spdm_response->header.request_response_code == SPDM_ERROR) {
510         if (spdm_response->header.param1 == SPDM_ERROR_CODE_DECRYPT_ERROR) {
511             status = LIBSPDM_STATUS_SESSION_MSG_ERROR;
512             goto receive_done;
513         }
514         if (spdm_response->header.param1 != SPDM_ERROR_CODE_RESPONSE_NOT_READY) {
515             libspdm_reset_message_f (spdm_context, session_info);
516         }
517         status = libspdm_handle_error_response_main(
518             spdm_context, &session_id,
519             &spdm_response_size, (void **)&spdm_response,
520             SPDM_FINISH, SPDM_FINISH_RSP);
521         if (LIBSPDM_STATUS_IS_ERROR(status)) {
522             goto receive_done;
523         }
524     } else if (spdm_response->header.request_response_code != SPDM_FINISH_RSP) {
525         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
526         goto receive_done;
527     }
528 
529     if (!libspdm_is_capabilities_flag_supported(
530             spdm_context, true,
531             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
532             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
533         hmac_size = 0;
534     }
535 
536     if (spdm_response_size < sizeof(spdm_finish_response_t) + hmac_size) {
537         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
538         goto receive_done;
539     }
540 
541     status = libspdm_append_message_f(spdm_context, session_info, true, spdm_response,
542                                       sizeof(spdm_finish_response_t));
543     if (LIBSPDM_STATUS_IS_ERROR(status)) {
544         goto receive_done;
545     }
546 
547     if (libspdm_is_capabilities_flag_supported(
548             spdm_context, true,
549             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
550             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
551         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "verify_data (0x%x):\n", hmac_size));
552         LIBSPDM_INTERNAL_DUMP_HEX(spdm_response->verify_data, hmac_size);
553         result = libspdm_verify_finish_rsp_hmac(spdm_context, session_info,
554                                                 spdm_response->verify_data,
555                                                 hmac_size);
556         if (!result) {
557             status = LIBSPDM_STATUS_VERIF_FAIL;
558             goto receive_done;
559         }
560 
561         status = libspdm_append_message_f(
562             spdm_context, session_info, true,
563             (uint8_t *)spdm_response +
564             sizeof(spdm_finish_response_t),
565             hmac_size);
566         if (LIBSPDM_STATUS_IS_ERROR(status)) {
567             goto receive_done;
568         }
569     }
570 
571     /* -=[Process Response Phase]=- */
572     LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "libspdm_generate_session_data_key[%x]\n", session_id));
573     result = libspdm_calculate_th2_hash(spdm_context, session_info, true, th2_hash_data);
574     if (!result) {
575         status = LIBSPDM_STATUS_CRYPTO_ERROR;
576         goto receive_done;
577     }
578     result = libspdm_generate_session_data_key(
579         session_info->secured_message_context, th2_hash_data);
580     if (!result) {
581         status = LIBSPDM_STATUS_CRYPTO_ERROR;
582         goto receive_done;
583     }
584 
585     /* -=[Update State Phase]=- */
586     libspdm_secured_message_set_session_state(
587         session_info->secured_message_context, LIBSPDM_SESSION_STATE_ESTABLISHED);
588 
589     /* -=[Log Message Phase]=- */
590     #if LIBSPDM_ENABLE_MSG_LOG
591     libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
592     #endif /* LIBSPDM_ENABLE_MSG_LOG */
593 
594     libspdm_release_receiver_buffer (spdm_context);
595 
596     return LIBSPDM_STATUS_SUCCESS;
597 
598 receive_done:
599     libspdm_release_receiver_buffer (spdm_context);
600 error:
601     if (status != LIBSPDM_STATUS_BUSY_PEER) {
602         libspdm_free_session_id(spdm_context, session_id);
603     }
604 
605     return status;
606 }
607 
libspdm_send_receive_finish(libspdm_context_t * spdm_context,uint32_t session_id,uint8_t req_slot_id_param)608 libspdm_return_t libspdm_send_receive_finish(libspdm_context_t *spdm_context,
609                                              uint32_t session_id,
610                                              uint8_t req_slot_id_param)
611 {
612     size_t retry;
613     uint64_t retry_delay_time;
614     libspdm_return_t status;
615 
616     spdm_context->crypto_request = true;
617     retry = spdm_context->retry_times;
618     retry_delay_time = spdm_context->retry_delay_time;
619     do {
620         status = libspdm_try_send_receive_finish(spdm_context, session_id,
621                                                  req_slot_id_param);
622         if ((status != LIBSPDM_STATUS_BUSY_PEER) || (retry == 0)) {
623             return status;
624         }
625 
626         libspdm_sleep(retry_delay_time);
627     } while (retry-- != 0);
628 
629     return status;
630 }
631 
632 #endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP*/
633