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