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