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