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 : /**
10 : * This function validates the Responder's capabilities.
11 : *
12 : * @param capabilities_flag The Responder's CAPABILITIES.Flags field.
13 : * @param version The SPDM message version.
14 : *
15 : * @retval true The field is valid.
16 : * @retval false The field is invalid.
17 : **/
18 35 : static bool validate_responder_capability(uint32_t capabilities_flag, uint8_t version)
19 : {
20 : /*uint8_t cache_cap = (uint8_t)(capabilities_flag)&0x01;*/
21 35 : const uint8_t cert_cap = (uint8_t)(capabilities_flag >> 1) & 0x01;
22 35 : const uint8_t chal_cap = (uint8_t)(capabilities_flag >> 2) & 0x01;
23 35 : const uint8_t meas_cap = (uint8_t)(capabilities_flag >> 3) & 0x03;
24 35 : const uint8_t meas_fresh_cap = (uint8_t)(capabilities_flag >> 5) & 0x01;
25 35 : const uint8_t encrypt_cap = (uint8_t)(capabilities_flag >> 6) & 0x01;
26 35 : const uint8_t mac_cap = (uint8_t)(capabilities_flag >> 7) & 0x01;
27 35 : const uint8_t mut_auth_cap = (uint8_t)(capabilities_flag >> 8) & 0x01;
28 35 : const uint8_t key_ex_cap = (uint8_t)(capabilities_flag >> 9) & 0x01;
29 35 : const uint8_t psk_cap = (uint8_t)(capabilities_flag >> 10) & 0x03;
30 35 : const uint8_t encap_cap = (uint8_t)(capabilities_flag >> 12) & 0x01;
31 35 : const uint8_t hbeat_cap = (uint8_t)(capabilities_flag >> 13) & 0x01;
32 35 : const uint8_t key_upd_cap = (uint8_t)(capabilities_flag >> 14) & 0x01;
33 35 : const uint8_t handshake_in_the_clear_cap = (uint8_t)(capabilities_flag >> 15) & 0x01;
34 35 : const uint8_t pub_key_id_cap = (uint8_t)(capabilities_flag >> 16) & 0x01;
35 : /* uint8_t chunk_cap = (uint8_t)(capabilities_flag >> 17) & 0x01; */
36 35 : const uint8_t alias_cert_cap = (uint8_t)(capabilities_flag >> 18) & 0x01;
37 35 : const uint8_t set_cert_cap = (uint8_t)(capabilities_flag >> 19) & 0x01;
38 35 : const uint8_t csr_cap = (uint8_t)(capabilities_flag >> 20) & 0x01;
39 35 : const uint8_t cert_install_reset_cap = (uint8_t)(capabilities_flag >> 21) & 0x01;
40 35 : const uint8_t ep_info_cap = (uint8_t)(capabilities_flag >> 22) & 0x03;
41 : /* const uint8_t mel_cap = (uint8_t)(capabilities_flag >> 24) & 0x01; */
42 35 : const uint8_t event_cap = (uint8_t)(capabilities_flag >> 25) & 0x01;
43 35 : const uint8_t multi_key_cap = (uint8_t)(capabilities_flag >> 26) & 0x03;
44 35 : const uint8_t get_key_pair_info_cap = (uint8_t)(capabilities_flag >> 28) & 0x01;
45 35 : const uint8_t set_key_pair_info_cap = (uint8_t)(capabilities_flag >> 29) & 0x01;
46 35 : const uint8_t set_key_pair_reset_cap = (uint8_t)(capabilities_flag >> 30) & 0x01;
47 : /* const uint8_t large_resp_cap = (uint8_t)(capabilities_flag >> 31) & 0x01; */
48 :
49 : /* Checks common to all SPDM versions. */
50 :
51 : /* Illegal to return reserved value. */
52 35 : if (meas_cap == 3) {
53 1 : return false;
54 : }
55 :
56 : /* If MEAS_FRESH_CAP is set then MEAS_CAP must be set. */
57 34 : if ((meas_cap == 0) && (meas_fresh_cap == 1)) {
58 1 : return false;
59 : }
60 :
61 33 : if (version == SPDM_MESSAGE_VERSION_10) {
62 : /* If measurements are not signed then CERT_CAP must equal CHAL_CAP.
63 : * If measurements are signed then CERT_CAP must be set. */
64 7 : if ((meas_cap == 0) || (meas_cap == 1)) {
65 5 : if (cert_cap != chal_cap) {
66 1 : return false;
67 : }
68 2 : } else if (meas_cap == 2) {
69 2 : if (cert_cap == 0) {
70 1 : return false;
71 : }
72 : }
73 5 : return true;
74 : }
75 :
76 : /* Checks common to 1.1 and higher. */
77 26 : if (version >= SPDM_MESSAGE_VERSION_11) {
78 : /* Illegal to return reserved values. */
79 26 : if (psk_cap == 3) {
80 1 : return false;
81 : }
82 :
83 : /* Checks that originate from key exchange capabilities. */
84 25 : if ((key_ex_cap == 1) || (psk_cap != 0)) {
85 11 : if ((mac_cap == 0) && (encrypt_cap == 0)) {
86 4 : return false;
87 : }
88 : } else {
89 14 : if ((mac_cap == 1) || (encrypt_cap == 1) || (handshake_in_the_clear_cap == 1) ||
90 11 : (hbeat_cap == 1) || (key_upd_cap == 1)) {
91 3 : return false;
92 : }
93 11 : if (version >= SPDM_MESSAGE_VERSION_13) {
94 1 : if (event_cap == 1) {
95 0 : return false;
96 : }
97 : }
98 : }
99 18 : if ((key_ex_cap == 0) && (psk_cap != 0)) {
100 1 : if (handshake_in_the_clear_cap == 1) {
101 1 : return false;
102 : }
103 : }
104 :
105 : /* Checks that originate from certificate or public key capabilities. */
106 17 : if ((cert_cap == 1) || (pub_key_id_cap == 1)) {
107 : /* Certificate capabilities and public key capabilities cannot both be set. */
108 12 : if ((cert_cap == 1) && (pub_key_id_cap == 1)) {
109 1 : return false;
110 : }
111 : /* If certificates or public keys are enabled then at least one of these capabilities
112 : * must be enabled to use the key. */
113 11 : if ((chal_cap == 0) && (key_ex_cap == 0) && ((meas_cap == 0) || (meas_cap == 1))) {
114 1 : if (version >= SPDM_MESSAGE_VERSION_13) {
115 0 : if ((ep_info_cap == 0) || (ep_info_cap == 1)) {
116 0 : return false;
117 : }
118 : } else {
119 1 : return false;
120 : }
121 : }
122 : } else {
123 : /* If certificates or public keys are not enabled then these capabilities
124 : * cannot be enabled. */
125 5 : if ((chal_cap == 1) || (key_ex_cap == 1) || (meas_cap == 2) || (mut_auth_cap == 1)) {
126 1 : return false;
127 : }
128 4 : if (version >= SPDM_MESSAGE_VERSION_13) {
129 1 : if (ep_info_cap == 2) {
130 1 : return false;
131 : }
132 : }
133 : }
134 :
135 : /* Checks that originate from mutual authentication capabilities. */
136 13 : if (mut_auth_cap == 1) {
137 : /* Mutual authentication with asymmetric keys can only occur through the basic mutual
138 : * authentication flow (CHAL_CAP == 1) or the session-based mutual authentication flow
139 : * (KEY_EX_CAP == 1). */
140 4 : if ((key_ex_cap == 0) && (chal_cap == 0)) {
141 0 : return false;
142 : }
143 : }
144 : }
145 :
146 : /* Checks specific to 1.1. */
147 13 : if (version == SPDM_MESSAGE_VERSION_11) {
148 3 : if ((mut_auth_cap == 1) && (encap_cap == 0)) {
149 1 : return false;
150 : }
151 : }
152 :
153 : /* Checks common to 1.2 and higher. */
154 12 : if (version >= SPDM_MESSAGE_VERSION_12) {
155 10 : if ((cert_cap == 0) && ((alias_cert_cap == 1) || (set_cert_cap == 1))) {
156 1 : return false;
157 : }
158 9 : if ((csr_cap == 1) && (set_cert_cap == 0)) {
159 1 : return false;
160 : }
161 8 : if ((cert_install_reset_cap == 1) && (csr_cap == 0) && (set_cert_cap == 0)) {
162 1 : return false;
163 : }
164 : }
165 :
166 : /* Checks specific to 1.3 and higher. */
167 9 : if (version >= SPDM_MESSAGE_VERSION_13) {
168 : /* Illegal to return reserved values. */
169 1 : if ((ep_info_cap == 3) || (multi_key_cap == 3)) {
170 0 : return false;
171 : }
172 1 : if ((multi_key_cap != 0) && ((get_key_pair_info_cap == 0) || (cert_cap == 0))) {
173 0 : return false;
174 : }
175 1 : if (pub_key_id_cap == 1) {
176 0 : if ((multi_key_cap != 0) || (get_key_pair_info_cap == 1) ||
177 : (set_key_pair_info_cap == 1)) {
178 0 : return false;
179 : }
180 : }
181 : }
182 :
183 : /* Checks that are deferred to when a message is sent.
184 : *
185 : * If the Responder supports key exchange then MAC_CAP must be set. In addition, if the
186 : * negotiated SPDM version is greater than 1.1 then the negotiated opaque data format must be
187 : * OpaqueDataFmt1.
188 : */
189 :
190 : /* Checks specific to 1.4 and higher. */
191 9 : if (version >= SPDM_MESSAGE_VERSION_14) {
192 0 : if ((set_key_pair_reset_cap == 1) && (set_key_pair_info_cap == 0)) {
193 0 : return false;
194 : }
195 : }
196 :
197 9 : return true;
198 : }
199 :
200 : /**
201 : * This function sends GET_CAPABILITIES and receives CAPABILITIES.
202 : *
203 : * @param spdm_context A pointer to the SPDM context.
204 : *
205 : * @retval LIBSPDM_STATUS_SUCCESS
206 : * GET_CAPABILITIES was sent and CAPABILITIES was received.
207 : * @retval LIBSPDM_STATUS_INVALID_STATE_LOCAL
208 : * Cannot send GET_CAPABILITIES due to Requester's state. Send GET_VERSION first.
209 : * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE
210 : * The size of the CAPABILITIES response is invalid.
211 : * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD
212 : * The CAPABILITIES response contains one or more invalid fields.
213 : * @retval LIBSPDM_STATUS_ERROR_PEER
214 : * The Responder returned an unexpected error.
215 : * @retval LIBSPDM_STATUS_BUSY_PEER
216 : * The Responder continually returned Busy error messages.
217 : * @retval LIBSPDM_STATUS_RESYNCH_PEER
218 : * The Responder returned a RequestResynch error message.
219 : * @retval LIBSPDM_STATUS_BUFFER_FULL
220 : * The buffer used to store transcripts is exhausted.
221 : **/
222 68 : static libspdm_return_t libspdm_try_get_capabilities(libspdm_context_t *spdm_context)
223 : {
224 : libspdm_return_t status;
225 : spdm_get_capabilities_request_t *spdm_request;
226 : size_t spdm_request_size;
227 : spdm_capabilities_response_t *spdm_response;
228 : size_t spdm_response_size;
229 : uint8_t *message;
230 : size_t message_size;
231 : size_t transport_header_size;
232 :
233 : /* -=[Verify State Phase]=- */
234 68 : if (spdm_context->connection_info.connection_state != LIBSPDM_CONNECTION_STATE_AFTER_VERSION) {
235 1 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
236 : }
237 67 : libspdm_reset_message_buffer_via_request_code(spdm_context, NULL, SPDM_GET_CAPABILITIES);
238 :
239 : /* -=[Construct Request Phase]=- */
240 67 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
241 67 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
242 67 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
243 1 : return status;
244 : }
245 66 : LIBSPDM_ASSERT (message_size >= transport_header_size +
246 : spdm_context->local_context.capability.transport_tail_size);
247 66 : spdm_request = (void *)(message + transport_header_size);
248 66 : spdm_request_size = message_size - transport_header_size -
249 66 : spdm_context->local_context.capability.transport_tail_size;
250 :
251 66 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_request->header));
252 66 : libspdm_zero_mem(spdm_request, spdm_request_size);
253 66 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
254 66 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
255 11 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_get_capabilities_request_t));
256 11 : spdm_request_size = sizeof(spdm_get_capabilities_request_t);
257 55 : } else if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
258 35 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_get_capabilities_request_t) -
259 : sizeof(spdm_request->data_transfer_size) -
260 : sizeof(spdm_request->max_spdm_msg_size));
261 35 : spdm_request_size = sizeof(spdm_get_capabilities_request_t) -
262 : sizeof(spdm_request->data_transfer_size) -
263 : sizeof(spdm_request->max_spdm_msg_size);
264 : } else {
265 20 : spdm_request_size = sizeof(spdm_request->header);
266 : }
267 66 : spdm_request->header.request_response_code = SPDM_GET_CAPABILITIES;
268 66 : spdm_request->header.param1 = 0;
269 66 : spdm_request->header.param2 = 0;
270 66 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
271 46 : spdm_request->ct_exponent = spdm_context->local_context.capability.ct_exponent;
272 46 : spdm_request->flags =
273 46 : libspdm_mask_capability_flags(spdm_context, true,
274 : spdm_context->local_context.capability.flags);
275 : }
276 66 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
277 11 : spdm_request->data_transfer_size =
278 11 : spdm_context->local_context.capability.data_transfer_size;
279 11 : spdm_request->max_spdm_msg_size =
280 11 : spdm_context->local_context.capability.max_spdm_msg_size;
281 : }
282 :
283 : /* -=[Send Request Phase]=- */
284 66 : status = libspdm_send_spdm_request(spdm_context, NULL, spdm_request_size, spdm_request);
285 66 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
286 1 : libspdm_release_sender_buffer (spdm_context);
287 1 : return status;
288 : }
289 65 : libspdm_release_sender_buffer (spdm_context);
290 65 : spdm_request = (void *)spdm_context->last_spdm_request;
291 :
292 : /* -=[Receive Response Phase]=- */
293 65 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
294 65 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
295 1 : return status;
296 : }
297 64 : LIBSPDM_ASSERT (message_size >= transport_header_size);
298 64 : spdm_response = (void *)(message);
299 64 : spdm_response_size = message_size;
300 :
301 64 : status = libspdm_receive_spdm_response(spdm_context, NULL, &spdm_response_size,
302 : (void **)&spdm_response);
303 64 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
304 3 : goto receive_done;
305 : }
306 :
307 : /* -=[Validate Response Phase]=- */
308 61 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
309 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
310 0 : goto receive_done;
311 : }
312 61 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
313 23 : status = libspdm_handle_simple_error_response(
314 23 : spdm_context, spdm_response->header.param1);
315 23 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
316 23 : goto receive_done;
317 : }
318 38 : } else if (spdm_response->header.request_response_code != SPDM_CAPABILITIES) {
319 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
320 1 : goto receive_done;
321 : }
322 37 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
323 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
324 1 : goto receive_done;
325 : }
326 36 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
327 11 : if (spdm_response_size < sizeof(spdm_capabilities_response_t)) {
328 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
329 0 : goto receive_done;
330 : }
331 : } else {
332 25 : if (spdm_response_size < sizeof(spdm_capabilities_response_t) -
333 : sizeof(spdm_response->data_transfer_size) - sizeof(spdm_response->max_spdm_msg_size)) {
334 1 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
335 1 : goto receive_done;
336 : }
337 : }
338 35 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
339 11 : spdm_response_size = sizeof(spdm_capabilities_response_t);
340 : } else {
341 24 : spdm_response_size = sizeof(spdm_capabilities_response_t) -
342 : sizeof(spdm_response->data_transfer_size) -
343 : sizeof(spdm_response->max_spdm_msg_size);
344 : }
345 :
346 35 : if (!validate_responder_capability(spdm_response->flags, spdm_response->header.spdm_version)) {
347 21 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
348 21 : goto receive_done;
349 : }
350 14 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
351 7 : if ((spdm_response->data_transfer_size < SPDM_MIN_DATA_TRANSFER_SIZE_VERSION_12) ||
352 6 : (spdm_response->data_transfer_size > spdm_response->max_spdm_msg_size)) {
353 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
354 2 : goto receive_done;
355 : }
356 :
357 5 : if (((spdm_response->flags & SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP) == 0) &&
358 2 : (spdm_response->data_transfer_size != spdm_response->max_spdm_msg_size)) {
359 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
360 1 : goto receive_done;
361 : }
362 : }
363 :
364 11 : if (spdm_response->ct_exponent > LIBSPDM_MAX_CT_EXPONENT) {
365 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
366 1 : goto receive_done;
367 : }
368 :
369 : /* -=[Process Response Phase]=- */
370 10 : status = libspdm_append_message_a(spdm_context, spdm_request, spdm_request_size);
371 10 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
372 1 : goto receive_done;
373 : }
374 :
375 9 : status = libspdm_append_message_a(spdm_context, spdm_response, spdm_response_size);
376 9 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
377 0 : goto receive_done;
378 : }
379 :
380 9 : spdm_context->connection_info.capability.ct_exponent = spdm_response->ct_exponent;
381 9 : spdm_context->connection_info.capability.flags =
382 9 : libspdm_mask_capability_flags(spdm_context, false, spdm_response->flags);
383 :
384 9 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
385 2 : spdm_context->connection_info.capability.data_transfer_size =
386 2 : spdm_response->data_transfer_size;
387 2 : spdm_context->connection_info.capability.max_spdm_msg_size =
388 2 : spdm_response->max_spdm_msg_size;
389 : } else {
390 7 : spdm_context->connection_info.capability.data_transfer_size = 0;
391 7 : spdm_context->connection_info.capability.max_spdm_msg_size = 0;
392 : }
393 :
394 : /* -=[Update State Phase]=- */
395 9 : spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_AFTER_CAPABILITIES;
396 9 : status = LIBSPDM_STATUS_SUCCESS;
397 :
398 : /* -=[Log Message Phase]=- */
399 : #if LIBSPDM_ENABLE_MSG_LOG
400 9 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
401 : #endif /* LIBSPDM_ENABLE_MSG_LOG */
402 :
403 64 : receive_done:
404 64 : libspdm_release_receiver_buffer (spdm_context);
405 64 : return status;
406 : }
407 :
408 67 : libspdm_return_t libspdm_get_capabilities(libspdm_context_t *spdm_context)
409 : {
410 : size_t retry;
411 : uint64_t retry_delay_time;
412 : libspdm_return_t status;
413 :
414 67 : spdm_context->crypto_request = false;
415 67 : retry = spdm_context->retry_times;
416 67 : retry_delay_time = spdm_context->retry_delay_time;
417 : do {
418 68 : status = libspdm_try_get_capabilities(spdm_context);
419 68 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
420 66 : return status;
421 : }
422 :
423 2 : libspdm_sleep(retry_delay_time);
424 2 : } while (retry-- != 0);
425 :
426 1 : return status;
427 : }
|