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