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 :
9 : /**
10 : * This function checks the compatibility of the received SPDM version,
11 : * if received version is valid, subsequent spdm communication will follow this version.
12 : *
13 : * @param spdm_context A pointer to the SPDM context.
14 : * @param version The SPDM message version.
15 : *
16 : *
17 : * @retval true The received SPDM version is valid.
18 : * @retval false The received SPDM version is invalid.
19 : **/
20 19 : static bool libspdm_check_request_version_compatibility(libspdm_context_t *spdm_context,
21 : uint8_t version)
22 : {
23 : uint8_t local_ver;
24 : size_t index;
25 :
26 41 : for (index = 0; index < spdm_context->local_context.version.spdm_version_count; index++) {
27 41 : local_ver = libspdm_get_version_from_version_number(
28 41 : spdm_context->local_context.version.spdm_version[index]);
29 41 : if (local_ver == version) {
30 19 : spdm_context->connection_info.version = version << SPDM_VERSION_NUMBER_SHIFT_BIT;
31 19 : return true;
32 : }
33 : }
34 0 : return false;
35 : }
36 :
37 : /**
38 : * This function checks the compatibility of the received GET_CAPABILITES flag.
39 : * Some flags are mutually inclusive/exclusive.
40 : *
41 : * @param capabilities_flag The received CAPABILITIES Flag.
42 : * @param version The SPDM message version.
43 : *
44 : *
45 : * @retval true The received Capabilities flag is valid.
46 : * @retval false The received Capabilities flag is invalid.
47 : **/
48 19 : static bool libspdm_check_request_flag_compatibility(uint32_t capabilities_flag, uint8_t version)
49 : {
50 19 : const uint8_t cert_cap = (uint8_t)(capabilities_flag >> 1) & 0x01;
51 19 : const uint8_t chal_cap = (uint8_t)(capabilities_flag >> 2) & 0x01;
52 19 : const uint8_t encrypt_cap = (uint8_t)(capabilities_flag >> 6) & 0x01;
53 19 : const uint8_t mac_cap = (uint8_t)(capabilities_flag >> 7) & 0x01;
54 19 : const uint8_t mut_auth_cap = (uint8_t)(capabilities_flag >> 8) & 0x01;
55 19 : const uint8_t key_ex_cap = (uint8_t)(capabilities_flag >> 9) & 0x01;
56 19 : const uint8_t psk_cap = (uint8_t)(capabilities_flag >> 10) & 0x03;
57 19 : const uint8_t encap_cap = (uint8_t)(capabilities_flag >> 12) & 0x01;
58 19 : const uint8_t hbeat_cap = (uint8_t)(capabilities_flag >> 13) & 0x01;
59 19 : const uint8_t key_upd_cap = (uint8_t)(capabilities_flag >> 14) & 0x01;
60 19 : const uint8_t handshake_in_the_clear_cap = (uint8_t)(capabilities_flag >> 15) & 0x01;
61 19 : const uint8_t pub_key_id_cap = (uint8_t)(capabilities_flag >> 16) & 0x01;
62 19 : const uint8_t ep_info_cap = (uint8_t)(capabilities_flag >> 22) & 0x03;
63 19 : const uint8_t event_cap = (uint8_t)(capabilities_flag >> 25) & 0x01;
64 19 : const uint8_t multi_key_cap = (uint8_t)(capabilities_flag >> 26) & 0x03;
65 :
66 : /* Checks common to 1.1 and higher */
67 19 : if (version >= SPDM_MESSAGE_VERSION_11) {
68 : /* Illegal to return reserved values. */
69 17 : if ((psk_cap == 2) || (psk_cap == 3)) {
70 0 : return false;
71 : }
72 :
73 : /* Checks that originate from key exchange capabilities. */
74 17 : if ((key_ex_cap == 1) || (psk_cap != 0)) {
75 11 : if ((mac_cap == 0) && (encrypt_cap == 0)) {
76 2 : return false;
77 : }
78 : } else {
79 6 : if ((mac_cap == 1) || (encrypt_cap == 1) || (handshake_in_the_clear_cap == 1) ||
80 4 : (hbeat_cap == 1) || (key_upd_cap == 1)) {
81 2 : return false;
82 : }
83 4 : if (version >= SPDM_MESSAGE_VERSION_13) {
84 1 : if (event_cap == 1) {
85 0 : return false;
86 : }
87 : }
88 : }
89 13 : if ((key_ex_cap == 0) && (psk_cap == 1)) {
90 1 : if (handshake_in_the_clear_cap == 1) {
91 1 : return false;
92 : }
93 : }
94 :
95 : /* Checks that originate from certificate or public key capabilities. */
96 12 : if ((cert_cap == 1) || (pub_key_id_cap == 1)) {
97 : /* Certificate capabilities and public key capabilities cannot both be set. */
98 9 : if ((cert_cap == 1) && (pub_key_id_cap == 1)) {
99 2 : return false;
100 : }
101 : /* If certificates or public keys are enabled then at least one of these capabilities
102 : * must be enabled to use the key. */
103 7 : if ((chal_cap == 0) && (key_ex_cap == 0)) {
104 1 : if (version >= SPDM_MESSAGE_VERSION_13) {
105 1 : if ((ep_info_cap == 0) || (ep_info_cap == 1)) {
106 0 : return false;
107 : }
108 : } else {
109 0 : return false;
110 : }
111 : }
112 : } else {
113 : /* If certificates or public keys are not enabled then these capabilities
114 : * cannot be enabled. */
115 3 : if ((chal_cap == 1) || (mut_auth_cap == 1)) {
116 0 : return false;
117 : }
118 3 : if (version >= SPDM_MESSAGE_VERSION_13) {
119 0 : if (ep_info_cap == 2) {
120 0 : return false;
121 : }
122 : }
123 : }
124 :
125 : /* Checks that originate from mutual authentication capabilities. */
126 10 : if (mut_auth_cap == 1) {
127 : /* Mutual authentication with asymmetric keys can only occur through the basic mutual
128 : * authentication flow (CHAL_CAP == 1) or the session-based mutual authentication flow
129 : * (KEY_EX_CAP == 1). */
130 6 : if ((key_ex_cap == 0) && (chal_cap == 0)) {
131 0 : return false;
132 : }
133 : }
134 : }
135 :
136 : /* Checks specific to 1.1. */
137 12 : if (version == SPDM_MESSAGE_VERSION_11) {
138 6 : if ((mut_auth_cap == 1) && (encap_cap == 0)) {
139 1 : return false;
140 : }
141 : }
142 :
143 : /* Checks specific to 1.3 and higher. */
144 11 : if (version >= SPDM_MESSAGE_VERSION_13) {
145 : /* Illegal to return reserved values. */
146 1 : if ((ep_info_cap == 3) || (multi_key_cap == 3)) {
147 0 : return false;
148 : }
149 1 : if ((multi_key_cap != 0) && ((pub_key_id_cap == 1) || (cert_cap == 0))) {
150 0 : return false;
151 : }
152 : }
153 :
154 : /* Checks that are deferred to when a message is received.
155 : *
156 : * If the Requester supports key exchange then MAC_CAP must be set. In addition, if the
157 : * negotiated SPDM version is greater than 1.1 then the negotiated opaque data format must be
158 : * OpaqueDataFmt1.
159 : */
160 :
161 11 : return true;
162 : }
163 :
164 22 : libspdm_return_t libspdm_get_response_capabilities(libspdm_context_t *spdm_context,
165 : size_t request_size,
166 : const void *request,
167 : size_t *response_size,
168 : void *response)
169 : {
170 : const spdm_get_capabilities_request_t *spdm_request;
171 : spdm_capabilities_response_t *spdm_response;
172 : libspdm_return_t status;
173 :
174 22 : spdm_request = request;
175 :
176 : /* -=[Check Parameters Phase]=- */
177 22 : LIBSPDM_ASSERT(spdm_request->header.request_response_code == SPDM_GET_CAPABILITIES);
178 :
179 : /* -=[Verify State Phase]=- */
180 22 : if (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) {
181 2 : return libspdm_responder_handle_response_state(
182 2 : spdm_context, spdm_request->header.request_response_code, response_size, response);
183 : }
184 20 : if (spdm_context->connection_info.connection_state != LIBSPDM_CONNECTION_STATE_AFTER_VERSION) {
185 1 : return libspdm_generate_error_response(spdm_context,
186 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST,
187 : 0, response_size, response);
188 : }
189 :
190 : /* -=[Validate Request Phase]=- */
191 19 : if (!libspdm_check_request_version_compatibility(
192 19 : spdm_context, spdm_request->header.spdm_version)) {
193 0 : return libspdm_generate_error_response(spdm_context,
194 : SPDM_ERROR_CODE_VERSION_MISMATCH, 0,
195 : response_size, response);
196 : }
197 19 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
198 4 : if (request_size < sizeof(spdm_get_capabilities_request_t)) {
199 0 : return libspdm_generate_error_response(
200 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
201 : } else {
202 4 : request_size = sizeof(spdm_get_capabilities_request_t);
203 : }
204 15 : } else if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
205 13 : if (request_size < sizeof(spdm_get_capabilities_request_t) -
206 : sizeof(spdm_request->data_transfer_size) - sizeof(spdm_request->max_spdm_msg_size)) {
207 0 : return libspdm_generate_error_response(
208 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
209 : } else {
210 13 : request_size = sizeof(spdm_get_capabilities_request_t) -
211 : sizeof(spdm_request->data_transfer_size) -
212 : sizeof(spdm_request->max_spdm_msg_size);
213 : }
214 : } else {
215 2 : if (request_size < sizeof(spdm_message_header_t)) {
216 0 : return libspdm_generate_error_response(
217 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
218 : } else {
219 2 : request_size = sizeof(spdm_message_header_t);
220 : }
221 : }
222 19 : if (!libspdm_check_request_flag_compatibility(
223 19 : spdm_request->flags, spdm_request->header.spdm_version)) {
224 8 : return libspdm_generate_error_response(spdm_context,
225 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
226 : response_size, response);
227 : }
228 11 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
229 4 : if ((spdm_request->data_transfer_size < SPDM_MIN_DATA_TRANSFER_SIZE_VERSION_12) ||
230 4 : (spdm_request->data_transfer_size > spdm_request->max_spdm_msg_size)) {
231 1 : return libspdm_generate_error_response(spdm_context,
232 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
233 : response_size, response);
234 : }
235 3 : if (((spdm_request->flags & SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP) == 0) &&
236 2 : (spdm_request->data_transfer_size != spdm_request->max_spdm_msg_size)) {
237 1 : return libspdm_generate_error_response(spdm_context,
238 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
239 : response_size, response);
240 : }
241 : }
242 9 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
243 7 : if (spdm_request->ct_exponent > LIBSPDM_MAX_CT_EXPONENT) {
244 1 : return libspdm_generate_error_response(spdm_context,
245 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
246 : response_size, response);
247 : }
248 : }
249 :
250 8 : libspdm_reset_message_buffer_via_request_code(spdm_context, NULL,
251 8 : spdm_request->header.request_response_code);
252 :
253 : /* -=[Construct Response Phase]=- */
254 8 : LIBSPDM_ASSERT(*response_size >= sizeof(spdm_capabilities_response_t));
255 8 : *response_size = sizeof(spdm_capabilities_response_t);
256 8 : libspdm_zero_mem(response, *response_size);
257 8 : spdm_response = response;
258 :
259 8 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
260 8 : spdm_response->header.request_response_code = SPDM_CAPABILITIES;
261 8 : spdm_response->header.param1 = 0;
262 8 : spdm_response->header.param2 = 0;
263 8 : spdm_response->ct_exponent = spdm_context->local_context.capability.ct_exponent;
264 8 : spdm_response->flags =
265 8 : libspdm_mask_capability_flags(spdm_context, false,
266 : spdm_context->local_context.capability.flags);
267 8 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
268 2 : spdm_response->data_transfer_size =
269 2 : spdm_context->local_context.capability.data_transfer_size;
270 2 : spdm_response->max_spdm_msg_size =
271 2 : spdm_context->local_context.capability.max_spdm_msg_size;
272 : }
273 :
274 8 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
275 2 : *response_size = sizeof(spdm_capabilities_response_t);
276 : } else {
277 6 : *response_size = sizeof(spdm_capabilities_response_t) -
278 : sizeof(spdm_response->data_transfer_size) -
279 : sizeof(spdm_response->max_spdm_msg_size);
280 : }
281 :
282 : /* -=[Process Request Phase]=- */
283 8 : status = libspdm_append_message_a(spdm_context, spdm_request, request_size);
284 8 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
285 0 : return libspdm_generate_error_response(spdm_context,
286 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
287 : response_size, response);
288 : }
289 8 : status = libspdm_append_message_a(spdm_context, spdm_response, *response_size);
290 :
291 8 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
292 0 : return libspdm_generate_error_response(spdm_context,
293 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
294 : response_size, response);
295 : }
296 :
297 8 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
298 6 : spdm_context->connection_info.capability.ct_exponent = spdm_request->ct_exponent;
299 : } else {
300 2 : spdm_context->connection_info.capability.ct_exponent = 0;
301 : }
302 :
303 8 : spdm_context->connection_info.capability.flags =
304 8 : libspdm_mask_capability_flags(spdm_context, true, spdm_request->flags);
305 :
306 8 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
307 2 : spdm_context->connection_info.capability.data_transfer_size =
308 2 : spdm_request->data_transfer_size;
309 2 : spdm_context->connection_info.capability.max_spdm_msg_size =
310 2 : spdm_request->max_spdm_msg_size;
311 : } else {
312 6 : spdm_context->connection_info.capability.data_transfer_size = 0;
313 6 : spdm_context->connection_info.capability.max_spdm_msg_size = 0;
314 : }
315 :
316 : /* -=[Update State Phase]=- */
317 8 : libspdm_set_connection_state(spdm_context, LIBSPDM_CONNECTION_STATE_AFTER_CAPABILITIES);
318 :
319 8 : return LIBSPDM_STATUS_SUCCESS;
320 : }
|