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_responder_lib.h"
8 : #include <stddef.h>
9 :
10 : /**
11 : * This function checks the compatibility of the received SPDM version,
12 : * if received version is valid, subsequent spdm communication will follow this version.
13 : *
14 : * @param spdm_context A pointer to the SPDM context.
15 : * @param version The SPDM message version.
16 : *
17 : *
18 : * @retval true The received SPDM version is valid.
19 : * @retval false The received SPDM version is invalid.
20 : **/
21 20 : static bool libspdm_check_request_version_compatibility(libspdm_context_t *spdm_context,
22 : uint8_t version)
23 : {
24 : uint8_t local_ver;
25 : size_t index;
26 :
27 45 : for (index = 0; index < spdm_context->local_context.version.spdm_version_count; index++) {
28 45 : local_ver = libspdm_get_version_from_version_number(
29 45 : spdm_context->local_context.version.spdm_version[index]);
30 45 : if (local_ver == version) {
31 20 : spdm_context->connection_info.version = version << SPDM_VERSION_NUMBER_SHIFT_BIT;
32 20 : return true;
33 : }
34 : }
35 0 : return false;
36 : }
37 :
38 : /**
39 : * This function checks the compatibility of the received GET_CAPABILITES flag.
40 : * Some flags are mutually inclusive/exclusive.
41 : *
42 : * @param capabilities_flag The received CAPABILITIES Flag.
43 : * @param version The SPDM message version.
44 : *
45 : *
46 : * @retval true The received Capabilities flag is valid.
47 : * @retval false The received Capabilities flag is invalid.
48 : **/
49 20 : static bool libspdm_check_request_flag_compatibility(uint32_t capabilities_flag, uint8_t version)
50 : {
51 20 : const uint8_t cert_cap = (uint8_t)(capabilities_flag >> 1) & 0x01;
52 20 : const uint8_t chal_cap = (uint8_t)(capabilities_flag >> 2) & 0x01;
53 20 : const uint8_t encrypt_cap = (uint8_t)(capabilities_flag >> 6) & 0x01;
54 20 : const uint8_t mac_cap = (uint8_t)(capabilities_flag >> 7) & 0x01;
55 20 : const uint8_t mut_auth_cap = (uint8_t)(capabilities_flag >> 8) & 0x01;
56 20 : const uint8_t key_ex_cap = (uint8_t)(capabilities_flag >> 9) & 0x01;
57 20 : const uint8_t psk_cap = (uint8_t)(capabilities_flag >> 10) & 0x03;
58 20 : const uint8_t encap_cap = (uint8_t)(capabilities_flag >> 12) & 0x01;
59 20 : const uint8_t hbeat_cap = (uint8_t)(capabilities_flag >> 13) & 0x01;
60 20 : const uint8_t key_upd_cap = (uint8_t)(capabilities_flag >> 14) & 0x01;
61 20 : const uint8_t handshake_in_the_clear_cap = (uint8_t)(capabilities_flag >> 15) & 0x01;
62 20 : const uint8_t pub_key_id_cap = (uint8_t)(capabilities_flag >> 16) & 0x01;
63 20 : const uint8_t ep_info_cap = (uint8_t)(capabilities_flag >> 22) & 0x03;
64 20 : const uint8_t event_cap = (uint8_t)(capabilities_flag >> 25) & 0x01;
65 20 : const uint8_t multi_key_cap = (uint8_t)(capabilities_flag >> 26) & 0x03;
66 :
67 : /* Checks common to 1.1 and higher */
68 20 : if (version >= SPDM_MESSAGE_VERSION_11) {
69 : /* Illegal to return reserved values. */
70 18 : if ((psk_cap == 2) || (psk_cap == 3)) {
71 0 : return false;
72 : }
73 :
74 : /* Checks that originate from key exchange capabilities. */
75 18 : if ((key_ex_cap == 1) || (psk_cap != 0)) {
76 11 : if ((mac_cap == 0) && (encrypt_cap == 0)) {
77 2 : return false;
78 : }
79 : } else {
80 7 : if ((mac_cap == 1) || (encrypt_cap == 1) || (handshake_in_the_clear_cap == 1) ||
81 5 : (hbeat_cap == 1) || (key_upd_cap == 1)) {
82 2 : return false;
83 : }
84 5 : if (version >= SPDM_MESSAGE_VERSION_13) {
85 2 : if (event_cap == 1) {
86 0 : return false;
87 : }
88 : }
89 : }
90 14 : if ((key_ex_cap == 0) && (psk_cap == 1)) {
91 1 : if (handshake_in_the_clear_cap == 1) {
92 1 : return false;
93 : }
94 : }
95 :
96 : /* Checks that originate from certificate or public key capabilities. */
97 13 : if ((cert_cap == 1) || (pub_key_id_cap == 1)) {
98 : /* Certificate capabilities and public key capabilities cannot both be set. */
99 10 : if ((cert_cap == 1) && (pub_key_id_cap == 1)) {
100 2 : return false;
101 : }
102 : /* If certificates or public keys are enabled then at least one of these capabilities
103 : * must be enabled to use the key. */
104 8 : if ((chal_cap == 0) && (key_ex_cap == 0)) {
105 2 : if (version >= SPDM_MESSAGE_VERSION_13) {
106 2 : if ((ep_info_cap == 0) || (ep_info_cap == 1)) {
107 0 : return false;
108 : }
109 : } else {
110 0 : return false;
111 : }
112 : }
113 : } else {
114 : /* If certificates or public keys are not enabled then these capabilities
115 : * cannot be enabled. */
116 3 : if ((chal_cap == 1) || (mut_auth_cap == 1)) {
117 0 : return false;
118 : }
119 3 : if (version >= SPDM_MESSAGE_VERSION_13) {
120 0 : if (ep_info_cap == 2) {
121 0 : return false;
122 : }
123 : }
124 : }
125 :
126 : /* Checks that originate from mutual authentication capabilities. */
127 11 : if (mut_auth_cap == 1) {
128 : /* Mutual authentication with asymmetric keys can only occur through the basic mutual
129 : * authentication flow (CHAL_CAP == 1) or the session-based mutual authentication flow
130 : * (KEY_EX_CAP == 1). */
131 6 : if ((key_ex_cap == 0) && (chal_cap == 0)) {
132 0 : return false;
133 : }
134 : }
135 : }
136 :
137 : /* Checks specific to 1.1. */
138 13 : if (version == SPDM_MESSAGE_VERSION_11) {
139 6 : if ((mut_auth_cap == 1) && (encap_cap == 0)) {
140 1 : return false;
141 : }
142 : }
143 :
144 : /* Checks specific to 1.3 and higher. */
145 12 : if (version >= SPDM_MESSAGE_VERSION_13) {
146 : /* Illegal to return reserved values. */
147 2 : if ((ep_info_cap == 3) || (multi_key_cap == 3)) {
148 0 : return false;
149 : }
150 2 : if ((multi_key_cap != 0) && ((pub_key_id_cap == 1) || (cert_cap == 0))) {
151 0 : return false;
152 : }
153 : }
154 :
155 : /* Checks that are deferred to when a message is received.
156 : *
157 : * If the Requester supports key exchange then MAC_CAP must be set. In addition, if the
158 : * negotiated SPDM version is greater than 1.1 then the negotiated opaque data format must be
159 : * OpaqueDataFmt1.
160 : */
161 :
162 12 : return true;
163 : }
164 :
165 23 : libspdm_return_t libspdm_get_response_capabilities(libspdm_context_t *spdm_context,
166 : size_t request_size,
167 : const void *request,
168 : size_t *response_size,
169 : void *response)
170 : {
171 : const spdm_get_capabilities_request_t *spdm_request;
172 : spdm_capabilities_response_t *spdm_response;
173 : libspdm_return_t status;
174 :
175 23 : spdm_request = request;
176 :
177 : /* -=[Check Parameters Phase]=- */
178 23 : LIBSPDM_ASSERT(spdm_request->header.request_response_code == SPDM_GET_CAPABILITIES);
179 :
180 : /* -=[Verify State Phase]=- */
181 23 : if (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) {
182 2 : return libspdm_responder_handle_response_state(
183 2 : spdm_context, spdm_request->header.request_response_code, response_size, response);
184 : }
185 21 : if (spdm_context->connection_info.connection_state != LIBSPDM_CONNECTION_STATE_AFTER_VERSION) {
186 1 : return libspdm_generate_error_response(spdm_context,
187 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST,
188 : 0, response_size, response);
189 : }
190 :
191 : /* -=[Validate Request Phase]=- */
192 20 : if (!libspdm_check_request_version_compatibility(
193 20 : spdm_context, spdm_request->header.spdm_version)) {
194 0 : return libspdm_generate_error_response(spdm_context,
195 : SPDM_ERROR_CODE_VERSION_MISMATCH, 0,
196 : response_size, response);
197 : }
198 20 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
199 5 : if (request_size < sizeof(spdm_get_capabilities_request_t)) {
200 0 : return libspdm_generate_error_response(
201 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
202 : } else {
203 5 : request_size = sizeof(spdm_get_capabilities_request_t);
204 : }
205 15 : } else if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
206 13 : if (request_size < sizeof(spdm_get_capabilities_request_t) -
207 : sizeof(spdm_request->data_transfer_size) - sizeof(spdm_request->max_spdm_msg_size)) {
208 0 : return libspdm_generate_error_response(
209 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
210 : } else {
211 13 : request_size = sizeof(spdm_get_capabilities_request_t) -
212 : sizeof(spdm_request->data_transfer_size) -
213 : sizeof(spdm_request->max_spdm_msg_size);
214 : }
215 : } else {
216 2 : if (request_size < sizeof(spdm_message_header_t)) {
217 0 : return libspdm_generate_error_response(
218 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
219 : } else {
220 2 : request_size = sizeof(spdm_message_header_t);
221 : }
222 : }
223 20 : if (!libspdm_check_request_flag_compatibility(
224 20 : spdm_request->flags, spdm_request->header.spdm_version)) {
225 8 : return libspdm_generate_error_response(spdm_context,
226 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
227 : response_size, response);
228 : }
229 12 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
230 5 : if ((spdm_request->data_transfer_size < SPDM_MIN_DATA_TRANSFER_SIZE_VERSION_12) ||
231 5 : (spdm_request->data_transfer_size > spdm_request->max_spdm_msg_size)) {
232 1 : return libspdm_generate_error_response(spdm_context,
233 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
234 : response_size, response);
235 : }
236 4 : if (((spdm_request->flags & SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP) == 0) &&
237 2 : (spdm_request->data_transfer_size != spdm_request->max_spdm_msg_size)) {
238 1 : return libspdm_generate_error_response(spdm_context,
239 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
240 : response_size, response);
241 : }
242 : }
243 10 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
244 8 : if (spdm_request->ct_exponent > LIBSPDM_MAX_CT_EXPONENT) {
245 1 : return libspdm_generate_error_response(spdm_context,
246 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
247 : response_size, response);
248 : }
249 : }
250 :
251 : /* Check that if Param1[0] is set, Requester must have CHUNK_CAP */
252 9 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13 &&
253 2 : (spdm_request->header.param1 & SPDM_GET_CAPABILITIES_REQUEST_PARAM1_SUPPORTED_ALGORITHMS) &&
254 1 : ((spdm_request->flags & SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP) == 0)) {
255 0 : return libspdm_generate_error_response(spdm_context,
256 : SPDM_ERROR_CODE_INVALID_REQUEST,
257 : 0,
258 : response_size,
259 : response);
260 : }
261 :
262 9 : libspdm_reset_message_buffer_via_request_code(spdm_context, NULL,
263 9 : spdm_request->header.request_response_code);
264 :
265 : size_t required_size;
266 :
267 9 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
268 3 : required_size = sizeof(spdm_capabilities_response_t);
269 : } else {
270 6 : required_size = offsetof(spdm_capabilities_response_t, data_transfer_size);
271 : }
272 :
273 9 : uint32_t response_flags = libspdm_mask_capability_flags(
274 : spdm_context, false, spdm_context->local_context.capability.flags);
275 :
276 9 : bool supported_algs_requested =
277 11 : (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) &&
278 2 : ((spdm_request->header.param1 & SPDM_GET_CAPABILITIES_REQUEST_PARAM1_SUPPORTED_ALGORITHMS) != 0) &&
279 12 : ((spdm_request->flags & SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP) != 0) &&
280 1 : ((response_flags & SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP) != 0);
281 :
282 9 : if (supported_algs_requested) {
283 1 : uint8_t table_count = 0;
284 1 : if (spdm_context->local_context.algorithm.dhe_named_group != 0) {
285 1 : table_count++;
286 : }
287 1 : if (spdm_context->local_context.algorithm.aead_cipher_suite != 0) {
288 1 : table_count++;
289 : }
290 1 : if (spdm_context->local_context.algorithm.req_base_asym_alg != 0) {
291 1 : table_count++;
292 : }
293 1 : if (spdm_context->local_context.algorithm.key_schedule != 0) {
294 1 : table_count++;
295 : }
296 :
297 1 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_14) {
298 0 : if (spdm_context->local_context.algorithm.req_pqc_asym_alg != 0) {
299 0 : table_count++;
300 : }
301 0 : if (spdm_context->local_context.algorithm.kem_alg != 0) {
302 0 : table_count++;
303 : }
304 : }
305 :
306 1 : required_size += sizeof(spdm_supported_algorithms_block_t) +
307 1 : (table_count * sizeof(spdm_negotiate_algorithms_common_struct_table_t));
308 : }
309 :
310 9 : LIBSPDM_ASSERT(*response_size >= required_size);
311 9 : *response_size = required_size;
312 :
313 9 : libspdm_zero_mem(response, *response_size);
314 9 : spdm_response = response;
315 :
316 9 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
317 9 : spdm_response->header.request_response_code = SPDM_CAPABILITIES;
318 9 : spdm_response->header.param1 = 0;
319 9 : spdm_response->header.param2 = 0;
320 9 : spdm_response->ct_exponent = spdm_context->local_context.capability.ct_exponent;
321 9 : spdm_response->flags = response_flags;
322 9 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
323 3 : spdm_response->data_transfer_size =
324 3 : spdm_context->local_context.capability.data_transfer_size;
325 3 : spdm_response->max_spdm_msg_size =
326 3 : spdm_context->local_context.capability.max_spdm_msg_size;
327 : }
328 :
329 9 : if (supported_algs_requested) {
330 1 : uint8_t index = 0;
331 :
332 : /* Allocate space for the supported_algorithms block at the end of the response */
333 1 : spdm_supported_algorithms_block_t *supported_algorithms =
334 : (spdm_supported_algorithms_block_t*)((uint8_t*)spdm_response + sizeof(spdm_capabilities_response_t));
335 :
336 1 : supported_algorithms->param2 = 0;
337 1 : supported_algorithms->length = sizeof(spdm_supported_algorithms_block_t);
338 1 : supported_algorithms->measurement_specification =
339 1 : spdm_context->local_context.algorithm.measurement_spec;
340 1 : supported_algorithms->other_params_support =
341 1 : spdm_context->local_context.algorithm.other_params_support;
342 1 : supported_algorithms->base_asym_algo=
343 1 : spdm_context->local_context.algorithm.base_asym_algo;
344 1 : supported_algorithms->base_hash_algo=
345 1 : spdm_context->local_context.algorithm.base_hash_algo;
346 :
347 1 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_14) {
348 0 : supported_algorithms->pqc_asym_algo =
349 0 : spdm_context->local_context.algorithm.pqc_asym_algo;
350 : } else {
351 1 : supported_algorithms->pqc_asym_algo = 0;
352 : }
353 :
354 1 : libspdm_zero_mem(supported_algorithms->reserved2, sizeof(supported_algorithms->reserved2));
355 1 : supported_algorithms->ext_asym_count = 0;
356 1 : supported_algorithms->ext_hash_count = 0;
357 1 : supported_algorithms->reserved3 = 0;
358 1 : supported_algorithms->mel_specification =
359 1 : spdm_context->local_context.algorithm.mel_spec;
360 :
361 1 : spdm_negotiate_algorithms_common_struct_table_t *struct_table =
362 : (spdm_negotiate_algorithms_common_struct_table_t*)(
363 : (uint8_t*)supported_algorithms +
364 : sizeof(spdm_supported_algorithms_block_t)
365 : );
366 :
367 1 : if (spdm_context->local_context.algorithm.dhe_named_group != 0) {
368 1 : struct_table[index].alg_type =
369 : SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_DHE;
370 1 : struct_table[index].alg_count = 0x20;
371 1 : struct_table[index].alg_supported =
372 1 : spdm_context->local_context.algorithm.dhe_named_group;
373 1 : index++;
374 : }
375 :
376 1 : if (spdm_context->local_context.algorithm.aead_cipher_suite != 0) {
377 1 : struct_table[index].alg_type =
378 : SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_AEAD;
379 1 : struct_table[index].alg_count = 0x20;
380 1 : struct_table[index].alg_supported =
381 1 : spdm_context->local_context.algorithm.aead_cipher_suite;
382 1 : index++;
383 : }
384 :
385 1 : if (spdm_context->local_context.algorithm.req_base_asym_alg != 0) {
386 1 : struct_table[index].alg_type =
387 : SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_REQ_BASE_ASYM_ALG;
388 1 : struct_table[index].alg_count = 0x20;
389 1 : struct_table[index].alg_supported =
390 1 : spdm_context->local_context.algorithm.req_base_asym_alg;
391 1 : index++;
392 : }
393 :
394 1 : if (spdm_context->local_context.algorithm.key_schedule != 0) {
395 1 : struct_table[index].alg_type =
396 : SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_KEY_SCHEDULE;
397 1 : struct_table[index].alg_count = 0x20;
398 1 : struct_table[index].alg_supported =
399 1 : spdm_context->local_context.algorithm.key_schedule;
400 1 : index++;
401 : }
402 :
403 1 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_14) {
404 0 : if (spdm_context->local_context.algorithm.req_pqc_asym_alg != 0) {
405 0 : struct_table[index].alg_type =
406 : SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_REQ_PQC_ASYM_ALG;
407 0 : struct_table[index].alg_count = 0x20;
408 0 : struct_table[index].alg_supported =
409 0 : (uint16_t)spdm_context->local_context.algorithm.req_pqc_asym_alg;
410 0 : index++;
411 : }
412 0 : if (spdm_context->local_context.algorithm.kem_alg != 0) {
413 0 : struct_table[index].alg_type =
414 : SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_KEM_ALG;
415 0 : struct_table[index].alg_count = 0x20;
416 0 : struct_table[index].alg_supported =
417 0 : (uint16_t)spdm_context->local_context.algorithm.kem_alg;
418 0 : index++;
419 : }
420 : }
421 :
422 1 : supported_algorithms->param1 = index;
423 1 : supported_algorithms->length +=
424 1 : supported_algorithms->param1*
425 : sizeof(spdm_negotiate_algorithms_common_struct_table_t);
426 :
427 8 : } else if (spdm_response->header.spdm_version < SPDM_MESSAGE_VERSION_12) {
428 6 : *response_size = sizeof(spdm_capabilities_response_t) -
429 : sizeof(spdm_response->data_transfer_size) -
430 : sizeof(spdm_response->max_spdm_msg_size);
431 : }
432 :
433 9 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_14) {
434 0 : spdm_response->ext_flags =
435 0 : libspdm_mask_capability_ext_flags(spdm_context, false,
436 0 : spdm_context->local_context.capability.ext_flags);
437 : } else {
438 9 : spdm_response->ext_flags = 0;
439 : }
440 :
441 : /* -=[Process Request Phase]=- */
442 9 : status = libspdm_append_message_a(spdm_context, spdm_request, request_size);
443 9 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
444 0 : return libspdm_generate_error_response(spdm_context,
445 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
446 : response_size, response);
447 : }
448 9 : status = libspdm_append_message_a(spdm_context, spdm_response, *response_size);
449 :
450 9 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
451 0 : return libspdm_generate_error_response(spdm_context,
452 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
453 : response_size, response);
454 : }
455 :
456 9 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
457 7 : spdm_context->connection_info.capability.ct_exponent = spdm_request->ct_exponent;
458 : } else {
459 2 : spdm_context->connection_info.capability.ct_exponent = 0;
460 : }
461 :
462 9 : spdm_context->connection_info.capability.flags =
463 9 : libspdm_mask_capability_flags(spdm_context, true, spdm_request->flags);
464 :
465 9 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
466 3 : spdm_context->connection_info.capability.data_transfer_size =
467 3 : spdm_request->data_transfer_size;
468 3 : spdm_context->connection_info.capability.max_spdm_msg_size =
469 3 : spdm_request->max_spdm_msg_size;
470 : } else {
471 6 : spdm_context->connection_info.capability.data_transfer_size = 0;
472 6 : spdm_context->connection_info.capability.max_spdm_msg_size = 0;
473 : }
474 :
475 9 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_14) {
476 0 : spdm_context->connection_info.capability.ext_flags =
477 0 : libspdm_mask_capability_ext_flags(spdm_context, true, spdm_request->ext_flags);
478 : } else {
479 9 : spdm_context->connection_info.capability.ext_flags = 0;
480 : }
481 :
482 : /* -=[Update State Phase]=- */
483 9 : libspdm_set_connection_state(spdm_context, LIBSPDM_CONNECTION_STATE_AFTER_CAPABILITIES);
484 :
485 9 : return LIBSPDM_STATUS_SUCCESS;
486 : }
|