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 
9 #pragma pack(1)
10 typedef struct {
11     spdm_message_header_t header;
12     uint16_t length;
13     uint8_t measurement_specification;
14     uint8_t other_params_support;
15     uint32_t base_asym_algo;
16     uint32_t base_hash_algo;
17     uint8_t reserved2[12];
18     uint8_t ext_asym_count;
19     uint8_t ext_hash_count;
20     uint16_t reserved3;
21     spdm_negotiate_algorithms_common_struct_table_t struct_table[
22         SPDM_NEGOTIATE_ALGORITHMS_MAX_NUM_STRUCT_TABLE_ALG];
23 } libspdm_negotiate_algorithms_request_mine_t;
24 
25 typedef struct {
26     spdm_message_header_t header;
27     uint16_t length;
28     uint8_t measurement_specification_sel;
29     uint8_t other_params_selection;
30     uint32_t measurement_hash_algo;
31     uint32_t base_asym_sel;
32     uint32_t base_hash_sel;
33     uint8_t reserved2[12];
34     uint8_t ext_asym_sel_count;
35     uint8_t ext_hash_sel_count;
36     uint16_t reserved3;
37     uint32_t ext_asym_sel;
38     uint32_t ext_hash_sel;
39     spdm_negotiate_algorithms_common_struct_table_t struct_table[
40         SPDM_NEGOTIATE_ALGORITHMS_MAX_NUM_STRUCT_TABLE_ALG];
41 } libspdm_algorithms_response_max_t;
42 #pragma pack()
43 
44 /**
45  * This function sends NEGOTIATE_ALGORITHMS and receives ALGORITHMS.
46  *
47  * @param  spdm_context A pointer to the SPDM context.
48  *
49  * @retval LIBSPDM_STATUS_SUCCESS
50  *         NEGOTIATE_ALGORITHMS was sent and ALGORITHMS was received.
51  * @retval LIBSPDM_STATUS_INVALID_STATE_LOCAL
52  *         Cannot send NEGOTIATE_ALGORITHMS due to Requester's state.
53  * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE
54  *         The size of the ALGORITHMS response is invalid.
55  * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD
56  *         The ALGORITHMS response contains one or more invalid fields.
57  * @retval LIBSPDM_STATUS_ERROR_PEER
58  *         The Responder returned an unexpected error.
59  * @retval LIBSPDM_STATUS_BUSY_PEER
60  *         The Responder continually returned Busy error messages.
61  * @retval LIBSPDM_STATUS_RESYNCH_PEER
62  *         The Responder returned a RequestResynch error message.
63  * @retval LIBSPDM_STATUS_BUFFER_FULL
64  *         The buffer used to store transcripts is exhausted.
65  * @retval LIBSPDM_STATUS_NEGOTIATION_FAIL
66  *         The Requester and Responder could not agree on mutual algorithms.
67  *         Note: This return value may be removed in the future.
68  **/
libspdm_try_negotiate_algorithms(libspdm_context_t * spdm_context)69 static libspdm_return_t libspdm_try_negotiate_algorithms(libspdm_context_t *spdm_context)
70 {
71     libspdm_return_t status;
72     libspdm_negotiate_algorithms_request_mine_t *spdm_request;
73     size_t spdm_request_size;
74     libspdm_algorithms_response_max_t *spdm_response;
75     size_t spdm_response_size;
76     uint32_t algo_size;
77     size_t index = 0;
78     spdm_negotiate_algorithms_common_struct_table_t *struct_table;
79     uint8_t fixed_alg_size;
80     uint8_t ext_alg_count;
81     uint8_t *message;
82     size_t message_size;
83     size_t transport_header_size;
84     uint8_t alg_type_pre;
85     uint8_t req_param1 = 0;
86 
87     /* -=[Verify State Phase]=- */
88     if (spdm_context->connection_info.connection_state !=
89         LIBSPDM_CONNECTION_STATE_AFTER_CAPABILITIES) {
90         return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
91     }
92 
93     libspdm_reset_message_buffer_via_request_code(spdm_context, NULL, SPDM_NEGOTIATE_ALGORITHMS);
94 
95     /* -=[Construct Request Phase]=- */
96     transport_header_size = spdm_context->local_context.capability.transport_header_size;
97     status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
98     if (LIBSPDM_STATUS_IS_ERROR(status)) {
99         return status;
100     }
101     LIBSPDM_ASSERT (message_size >= transport_header_size +
102                     spdm_context->local_context.capability.transport_tail_size);
103     spdm_request = (void *)(message + transport_header_size);
104     spdm_request_size = message_size - transport_header_size -
105                         spdm_context->local_context.capability.transport_tail_size;
106 
107     libspdm_zero_mem(spdm_request, sizeof(libspdm_negotiate_algorithms_request_mine_t));
108     spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
109     if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
110         /* Number of Algorithms Structure Tables based on supported algorithms */
111         if (spdm_context->local_context.algorithm.dhe_named_group) {
112             req_param1++;
113         }
114         if (spdm_context->local_context.algorithm.aead_cipher_suite) {
115             req_param1++;
116         }
117         if (spdm_context->local_context.algorithm.req_base_asym_alg) {
118             req_param1++;
119         }
120         if (spdm_context->local_context.algorithm.key_schedule) {
121             req_param1++;
122         }
123         LIBSPDM_ASSERT(req_param1 <=
124                        SPDM_NEGOTIATE_ALGORITHMS_MAX_NUM_STRUCT_TABLE_ALG);
125         spdm_request->header.param1 = req_param1;
126         spdm_request->length = sizeof(libspdm_negotiate_algorithms_request_mine_t) -
127                                ((SPDM_NEGOTIATE_ALGORITHMS_MAX_NUM_STRUCT_TABLE_ALG  -
128                                  req_param1) *
129                                 sizeof(spdm_negotiate_algorithms_common_struct_table_t));
130     } else {
131         spdm_request->length = sizeof(libspdm_negotiate_algorithms_request_mine_t) -
132                                sizeof(spdm_request->struct_table);
133         spdm_request->header.param1 = 0;
134     }
135     spdm_request->header.request_response_code = SPDM_NEGOTIATE_ALGORITHMS;
136     spdm_request->header.param2 = 0;
137     spdm_request->measurement_specification =
138         spdm_context->local_context.algorithm.measurement_spec;
139     if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
140         spdm_request->other_params_support =
141             spdm_context->local_context.algorithm.other_params_support;
142     }
143     spdm_request->base_asym_algo = spdm_context->local_context.algorithm.base_asym_algo;
144     spdm_request->base_hash_algo = spdm_context->local_context.algorithm.base_hash_algo;
145     spdm_request->ext_asym_count = 0;
146     spdm_request->ext_hash_count = 0;
147     if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
148         /* ReqAlgStruct order based on by AlgType */
149         if (spdm_context->local_context.algorithm.dhe_named_group) {
150             spdm_request->struct_table[index].alg_type =
151                 SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_DHE;
152             spdm_request->struct_table[index].alg_count = 0x20;
153             spdm_request->struct_table[index].alg_supported =
154                 spdm_context->local_context.algorithm.dhe_named_group;
155             index++;
156         }
157         if (spdm_context->local_context.algorithm.aead_cipher_suite) {
158             spdm_request->struct_table[index].alg_type =
159                 SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_AEAD;
160             spdm_request->struct_table[index].alg_count = 0x20;
161             spdm_request->struct_table[index].alg_supported =
162                 spdm_context->local_context.algorithm.aead_cipher_suite;
163             index++;
164         }
165         if (spdm_context->local_context.algorithm.req_base_asym_alg) {
166             spdm_request->struct_table[index].alg_type =
167                 SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_REQ_BASE_ASYM_ALG;
168             spdm_request->struct_table[index].alg_count = 0x20;
169             spdm_request->struct_table[index].alg_supported =
170                 spdm_context->local_context.algorithm.req_base_asym_alg;
171             index++;
172         }
173         if (spdm_context->local_context.algorithm.key_schedule) {
174             spdm_request->struct_table[index].alg_type =
175                 SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_KEY_SCHEDULE;
176             spdm_request->struct_table[index].alg_count = 0x20;
177             spdm_request->struct_table[index].alg_supported =
178                 spdm_context->local_context.algorithm.key_schedule;
179             index++;
180         }
181         LIBSPDM_ASSERT(index == spdm_request->header.param1);
182     }
183     spdm_request_size = spdm_request->length;
184 
185     /* -=[Send Request Phase]=- */
186     status = libspdm_send_spdm_request(spdm_context, NULL, spdm_request_size, spdm_request);
187     if (LIBSPDM_STATUS_IS_ERROR(status)) {
188         libspdm_release_sender_buffer (spdm_context);
189         return status;
190     }
191     libspdm_release_sender_buffer (spdm_context);
192     spdm_request = (void *)spdm_context->last_spdm_request;
193 
194     /* -=[Receive Response Phase]=- */
195     status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
196     if (LIBSPDM_STATUS_IS_ERROR(status)) {
197         return status;
198     }
199     LIBSPDM_ASSERT (message_size >= transport_header_size);
200     spdm_response = (void *)(message);
201     spdm_response_size = message_size;
202 
203     libspdm_zero_mem(spdm_response, spdm_response_size);
204     status = libspdm_receive_spdm_response(spdm_context, NULL, &spdm_response_size,
205                                            (void **)&spdm_response);
206     if (LIBSPDM_STATUS_IS_ERROR(status)) {
207         goto receive_done;
208     }
209 
210     /* -=[Validate Response Phase]=- */
211     if (spdm_response_size < sizeof(spdm_message_header_t)) {
212         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
213         goto receive_done;
214     }
215     if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
216         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
217         goto receive_done;
218     }
219     if (spdm_response->header.request_response_code == SPDM_ERROR) {
220         status = libspdm_handle_simple_error_response(spdm_context, spdm_response->header.param1);
221         if (LIBSPDM_STATUS_IS_ERROR(status)) {
222             goto receive_done;
223         }
224     } else if (spdm_response->header.request_response_code != SPDM_ALGORITHMS) {
225         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
226         goto receive_done;
227     }
228     if (spdm_response_size < sizeof(spdm_algorithms_response_t)) {
229         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
230         goto receive_done;
231     }
232     if (!libspdm_onehot0(spdm_response->measurement_specification_sel)) {
233         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
234         goto receive_done;
235     }
236     if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
237         if (!libspdm_onehot0(spdm_response->other_params_selection &
238                              SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK)) {
239             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
240             goto receive_done;
241         }
242     }
243     if (!libspdm_onehot0(spdm_response->measurement_hash_algo)) {
244         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
245         goto receive_done;
246     }
247     if (!libspdm_onehot0(spdm_response->base_asym_sel)) {
248         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
249         goto receive_done;
250     }
251     if (!libspdm_onehot0(spdm_response->base_hash_sel)) {
252         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
253         goto receive_done;
254     }
255     if (spdm_response->ext_asym_sel_count > 0) {
256         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
257         goto receive_done;
258     }
259     if (spdm_response->ext_hash_sel_count > 0) {
260         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
261         goto receive_done;
262     }
263     if (spdm_response_size <
264         sizeof(spdm_algorithms_response_t) +
265         sizeof(uint32_t) * spdm_response->ext_asym_sel_count +
266         sizeof(uint32_t) * spdm_response->ext_hash_sel_count +
267         sizeof(spdm_negotiate_algorithms_common_struct_table_t) * spdm_response->header.param1) {
268         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
269         goto receive_done;
270     }
271     struct_table =
272         (void *)((size_t)spdm_response +
273                  sizeof(spdm_algorithms_response_t) +
274                  sizeof(uint32_t) * spdm_response->ext_asym_sel_count +
275                  sizeof(uint32_t) * spdm_response->ext_hash_sel_count);
276     if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
277         alg_type_pre = struct_table->alg_type;
278         /* header.param1 is implictly checked through spdm_response_size. */
279         for (index = 0; index < spdm_response->header.param1; index++) {
280             if ((size_t)spdm_response + spdm_response_size < (size_t)struct_table) {
281                 status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
282                 goto receive_done;
283             }
284             if ((size_t)spdm_response + spdm_response_size - (size_t)struct_table <
285                 sizeof(spdm_negotiate_algorithms_common_struct_table_t)) {
286                 status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
287                 goto receive_done;
288             }
289             if ((struct_table->alg_type < SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_DHE) ||
290                 (struct_table->alg_type >
291                  SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_KEY_SCHEDULE)) {
292                 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
293                 goto receive_done;
294             }
295             /* AlgType shall monotonically increase for subsequent entries. */
296             if ((index != 0) && (struct_table->alg_type <= alg_type_pre)) {
297                 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
298                 goto receive_done;
299             }
300             alg_type_pre = struct_table->alg_type;
301             fixed_alg_size = (struct_table->alg_count >> 4) & 0xF;
302             ext_alg_count = struct_table->alg_count & 0xF;
303             if (fixed_alg_size != 2) {
304                 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
305                 goto receive_done;
306             }
307             if (ext_alg_count > 0) {
308                 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
309                 goto receive_done;
310             }
311             if (!libspdm_onehot0(struct_table->alg_supported)) {
312                 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
313                 goto receive_done;
314             }
315             if ((size_t)spdm_response + spdm_response_size -
316                 (size_t)struct_table - sizeof(spdm_negotiate_algorithms_common_struct_table_t) <
317                 sizeof(uint32_t) * ext_alg_count) {
318                 status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
319                 goto receive_done;
320             }
321             struct_table =
322                 (void *)((size_t)struct_table +
323                          sizeof(spdm_negotiate_algorithms_common_struct_table_t) +
324                          sizeof(uint32_t) * ext_alg_count);
325         }
326     }
327 
328     spdm_response_size = (size_t)struct_table - (size_t)spdm_response;
329     if (spdm_response_size != spdm_response->length) {
330         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
331         goto receive_done;
332     }
333 
334     /* -=[Process Response Phase]=- */
335     status = libspdm_append_message_a(spdm_context, spdm_request, spdm_request_size);
336     if (LIBSPDM_STATUS_IS_ERROR(status)) {
337         goto receive_done;
338     }
339 
340     status = libspdm_append_message_a(spdm_context, spdm_response, spdm_response_size);
341     if (LIBSPDM_STATUS_IS_ERROR(status)) {
342         goto receive_done;
343     }
344 
345     spdm_context->connection_info.algorithm.measurement_spec =
346         spdm_response->measurement_specification_sel;
347     if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
348         spdm_context->connection_info.algorithm.other_params_support =
349             spdm_response->other_params_selection;
350     }
351     spdm_context->connection_info.algorithm.measurement_hash_algo =
352         spdm_response->measurement_hash_algo;
353     spdm_context->connection_info.algorithm.base_asym_algo = spdm_response->base_asym_sel;
354     spdm_context->connection_info.algorithm.base_hash_algo = spdm_response->base_hash_sel;
355 
356     if (libspdm_is_capabilities_flag_supported(
357             spdm_context, true, 0,
358             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP) &&
359         (spdm_request->measurement_specification != 0)) {
360         if (spdm_context->connection_info.algorithm.measurement_spec !=
361             SPDM_MEASUREMENT_SPECIFICATION_DMTF) {
362             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
363             goto receive_done;
364         }
365         algo_size = libspdm_get_measurement_hash_size(
366             spdm_context->connection_info.algorithm.measurement_hash_algo);
367         if (algo_size == 0) {
368             status = LIBSPDM_STATUS_NEGOTIATION_FAIL;
369             goto receive_done;
370         }
371     }
372 
373     if (libspdm_is_capabilities_flag_supported(
374             spdm_context, true, 0,
375             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP) ||
376         libspdm_is_capabilities_flag_supported(
377             spdm_context, true, 0,
378             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHAL_CAP) ||
379         libspdm_is_capabilities_flag_supported(
380             spdm_context, true, 0,
381             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP_SIG) ||
382         libspdm_is_capabilities_flag_supported(
383             spdm_context, true,
384             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_EX_CAP,
385             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP) ||
386         libspdm_is_capabilities_flag_supported(
387             spdm_context, true,
388             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PSK_CAP,
389             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP)) {
390         algo_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
391         if (algo_size == 0) {
392             status = LIBSPDM_STATUS_NEGOTIATION_FAIL;
393             goto receive_done;
394         }
395         if ((spdm_context->connection_info.algorithm.base_hash_algo &
396              spdm_context->local_context.algorithm.base_hash_algo) == 0) {
397             status = LIBSPDM_STATUS_NEGOTIATION_FAIL;
398             goto receive_done;
399         }
400     }
401 
402     if (libspdm_is_capabilities_flag_supported(
403             spdm_context, true, 0,
404             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP) ||
405         libspdm_is_capabilities_flag_supported(
406             spdm_context, true, 0,
407             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHAL_CAP) ||
408         libspdm_is_capabilities_flag_supported(
409             spdm_context, true, 0,
410             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP_SIG) ||
411         libspdm_is_capabilities_flag_supported(
412             spdm_context, true,
413             SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_EX_CAP,
414             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP)) {
415         algo_size = libspdm_get_asym_signature_size(
416             spdm_context->connection_info.algorithm.base_asym_algo);
417         if (algo_size == 0) {
418             status = LIBSPDM_STATUS_NEGOTIATION_FAIL;
419             goto receive_done;
420         }
421         if ((spdm_context->connection_info.algorithm.base_asym_algo &
422              spdm_context->local_context.algorithm.base_asym_algo) == 0) {
423             status = LIBSPDM_STATUS_NEGOTIATION_FAIL;
424             goto receive_done;
425         }
426     }
427 
428     if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
429         struct_table =
430             (void *)((size_t)spdm_response +
431                      sizeof(spdm_algorithms_response_t) +
432                      sizeof(uint32_t) * spdm_response->ext_asym_sel_count +
433                      sizeof(uint32_t) * spdm_response->ext_hash_sel_count);
434         for (index = 0; index < spdm_response->header.param1; index++) {
435             switch (struct_table->alg_type) {
436             case SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_DHE:
437                 spdm_context->connection_info.algorithm.dhe_named_group =
438                     struct_table->alg_supported;
439                 break;
440             case SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_AEAD:
441                 spdm_context->connection_info.algorithm.aead_cipher_suite =
442                     struct_table->alg_supported;
443                 break;
444             case SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_REQ_BASE_ASYM_ALG:
445                 spdm_context->connection_info.algorithm.req_base_asym_alg =
446                     struct_table->alg_supported;
447                 break;
448             case SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_KEY_SCHEDULE:
449                 spdm_context->connection_info.algorithm.key_schedule =
450                     struct_table->alg_supported;
451                 break;
452             }
453             ext_alg_count = struct_table->alg_count & 0xF;
454             struct_table =
455                 (void *)((size_t)struct_table +
456                          sizeof(spdm_negotiate_algorithms_common_struct_table_t) +
457                          sizeof(uint32_t) * ext_alg_count);
458         }
459 
460         if (libspdm_is_capabilities_flag_supported(
461                 spdm_context, true,
462                 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_EX_CAP,
463                 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP)) {
464             algo_size = libspdm_get_dhe_pub_key_size(
465                 spdm_context->connection_info.algorithm.dhe_named_group);
466             if (algo_size == 0) {
467                 status = LIBSPDM_STATUS_NEGOTIATION_FAIL;
468                 goto receive_done;
469             }
470             if ((spdm_context->connection_info.algorithm.dhe_named_group &
471                  spdm_context->local_context.algorithm.dhe_named_group) == 0) {
472                 status = LIBSPDM_STATUS_NEGOTIATION_FAIL;
473                 goto receive_done;
474             }
475         }
476         if (libspdm_is_capabilities_flag_supported(
477                 spdm_context, true,
478                 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_ENCRYPT_CAP,
479                 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ENCRYPT_CAP) ||
480             libspdm_is_capabilities_flag_supported(
481                 spdm_context, true,
482                 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MAC_CAP,
483                 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MAC_CAP)) {
484             algo_size = libspdm_get_aead_key_size(
485                 spdm_context->connection_info.algorithm.aead_cipher_suite);
486             if (algo_size == 0) {
487                 status = LIBSPDM_STATUS_NEGOTIATION_FAIL;
488                 goto receive_done;
489             }
490             if ((spdm_context->connection_info.algorithm.aead_cipher_suite &
491                  spdm_context->local_context.algorithm.aead_cipher_suite) == 0) {
492                 status = LIBSPDM_STATUS_NEGOTIATION_FAIL;
493                 goto receive_done;
494             }
495         }
496         if (libspdm_is_capabilities_flag_supported(
497                 spdm_context, true,
498                 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MUT_AUTH_CAP,
499                 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MUT_AUTH_CAP)) {
500             algo_size = libspdm_get_req_asym_signature_size(
501                 spdm_context->connection_info.algorithm.req_base_asym_alg);
502             if (algo_size == 0) {
503                 status = LIBSPDM_STATUS_NEGOTIATION_FAIL;
504                 goto receive_done;
505             }
506             if ((spdm_context->connection_info.algorithm.req_base_asym_alg &
507                  spdm_context->local_context.algorithm.req_base_asym_alg) == 0) {
508                 status = LIBSPDM_STATUS_NEGOTIATION_FAIL;
509                 goto receive_done;
510             }
511         }
512         if (libspdm_is_capabilities_flag_supported(
513                 spdm_context, true,
514                 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_EX_CAP,
515                 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP) ||
516             libspdm_is_capabilities_flag_supported(
517                 spdm_context, true,
518                 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PSK_CAP,
519                 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP)) {
520             if (spdm_context->connection_info.algorithm.key_schedule !=
521                 SPDM_ALGORITHMS_KEY_SCHEDULE_HMAC_HASH) {
522                 status = LIBSPDM_STATUS_NEGOTIATION_FAIL;
523                 goto receive_done;
524             }
525             if ((spdm_context->connection_info.algorithm.key_schedule &
526                  spdm_context->local_context.algorithm.key_schedule) == 0) {
527                 status = LIBSPDM_STATUS_NEGOTIATION_FAIL;
528                 goto receive_done;
529             }
530             if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
531                 if ((spdm_context->connection_info.algorithm.other_params_support &
532                      SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) !=
533                     SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1) {
534                     status = LIBSPDM_STATUS_NEGOTIATION_FAIL;
535                     goto receive_done;
536                 }
537             }
538         }
539     } else {
540         spdm_context->connection_info.algorithm.dhe_named_group = 0;
541         spdm_context->connection_info.algorithm.aead_cipher_suite = 0;
542         spdm_context->connection_info.algorithm.req_base_asym_alg = 0;
543         spdm_context->connection_info.algorithm.key_schedule = 0;
544         spdm_context->connection_info.algorithm.other_params_support = 0;
545     }
546 
547     /* -=[Update State Phase]=- */
548     spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_NEGOTIATED;
549 
550     /* -=[Log Message Phase]=- */
551     #if LIBSPDM_ENABLE_MSG_LOG
552     libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
553     #endif /* LIBSPDM_ENABLE_MSG_LOG */
554 
555     status = LIBSPDM_STATUS_SUCCESS;
556 
557 receive_done:
558     libspdm_release_receiver_buffer (spdm_context);
559     return status;
560 }
561 
libspdm_negotiate_algorithms(libspdm_context_t * spdm_context)562 libspdm_return_t libspdm_negotiate_algorithms(libspdm_context_t *spdm_context)
563 {
564     size_t retry;
565     uint64_t retry_delay_time;
566     libspdm_return_t status;
567 
568     spdm_context->crypto_request = false;
569     retry = spdm_context->retry_times;
570     retry_delay_time = spdm_context->retry_delay_time;
571     do {
572         status = libspdm_try_negotiate_algorithms(spdm_context);
573         if ((status != LIBSPDM_STATUS_BUSY_PEER) || (retry == 0)) {
574             return status;
575         }
576 
577         libspdm_sleep(retry_delay_time);
578     } while (retry-- != 0);
579 
580     return status;
581 }
582