Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 2024-2026 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 : #if LIBSPDM_ENABLE_CAPABILITY_GET_KEY_PAIR_INFO_CAP
10 :
11 : typedef struct {
12 : spdm_message_header_t header;
13 : uint8_t total_key_pairs;
14 : uint8_t key_pair_id;
15 : uint16_t capabilities;
16 : uint16_t key_usage_capabilities;
17 : uint16_t current_key_usage;
18 : uint32_t asym_algo_capabilities;
19 : uint32_t current_asym_algo;
20 : uint16_t public_key_info_len;
21 : uint8_t assoc_cert_slot_mask;
22 : uint8_t public_key_info[SPDM_MAX_PUBLIC_KEY_INFO_LEN];
23 : uint8_t pqc_asym_algo_cap_len;
24 : uint32_t pqc_asym_algo_capabilities;
25 : uint8_t current_pqc_asym_algo_len;
26 : uint32_t current_pqc_asym_algo;
27 : } libspdm_key_pair_info_response_max_t;
28 :
29 : /**
30 : * This function sends GET_KEY_PAIR_INFO and receives KEY_PAIR_INFO *
31 : *
32 : * @param context A pointer to the SPDM context.
33 : *
34 : **/
35 18 : static libspdm_return_t libspdm_try_get_key_pair_info(libspdm_context_t *spdm_context,
36 : const uint32_t *session_id,
37 : uint8_t key_pair_id,
38 : uint8_t *total_key_pairs,
39 : uint16_t *capabilities,
40 : uint16_t *key_usage_capabilities,
41 : uint16_t *current_key_usage,
42 : uint32_t *asym_algo_capabilities,
43 : uint32_t *current_asym_algo,
44 : uint32_t *pqc_asym_algo_capabilities,
45 : uint32_t *current_pqc_asym_algo,
46 : uint8_t *assoc_cert_slot_mask,
47 : uint16_t *public_key_info_len,
48 : void *public_key_info
49 : )
50 : {
51 : libspdm_return_t status;
52 : spdm_get_key_pair_info_request_t *spdm_request;
53 : size_t spdm_request_size;
54 : libspdm_key_pair_info_response_max_t *spdm_response;
55 : size_t spdm_response_size;
56 : uint8_t *message;
57 : size_t message_size;
58 : size_t transport_header_size;
59 : libspdm_session_info_t *session_info;
60 : libspdm_session_state_t session_state;
61 : uint8_t pqc_asym_algo_cap_raw_len;
62 : uint8_t pqc_asym_algo_cap_copy_len;
63 : uint8_t current_pqc_asym_algo_raw_len;
64 : uint8_t current_pqc_asym_algo_copy_len;
65 : uint8_t *ptr;
66 : uint32_t rsp_pqc_asym_algo_capabilities;
67 : uint32_t rsp_current_pqc_asym_algo;
68 :
69 : /* -=[Check Parameters Phase]=- */
70 18 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_13) {
71 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
72 : }
73 :
74 18 : if (key_pair_id == 0) {
75 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
76 : }
77 :
78 : /* -=[Verify State Phase]=- */
79 18 : if (!libspdm_is_capabilities_flag_supported(
80 : spdm_context, true, 0,
81 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_GET_KEY_PAIR_INFO_CAP)) {
82 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
83 : }
84 18 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
85 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
86 : }
87 :
88 18 : session_info = NULL;
89 18 : if (session_id != NULL) {
90 0 : session_info = libspdm_get_session_info_via_session_id(spdm_context, *session_id);
91 0 : if (session_info == NULL) {
92 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
93 : }
94 0 : session_state = libspdm_secured_message_get_session_state(
95 : session_info->secured_message_context);
96 0 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
97 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
98 : }
99 : }
100 :
101 : /* -=[Construct Request Phase]=- */
102 18 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
103 18 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
104 18 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
105 0 : return status;
106 : }
107 18 : LIBSPDM_ASSERT (message_size >= transport_header_size +
108 : spdm_context->local_context.capability.transport_tail_size);
109 18 : spdm_request = (void *)(message + transport_header_size);
110 18 : spdm_request_size = message_size - transport_header_size -
111 18 : spdm_context->local_context.capability.transport_tail_size;
112 :
113 18 : LIBSPDM_ASSERT(spdm_request_size >= sizeof(spdm_get_key_pair_info_request_t));
114 18 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
115 18 : spdm_request->header.request_response_code = SPDM_GET_KEY_PAIR_INFO;
116 18 : spdm_request->header.param1 = 0;
117 18 : spdm_request->header.param2 = 0;
118 18 : spdm_request->key_pair_id = key_pair_id;
119 18 : spdm_request_size = sizeof(spdm_get_key_pair_info_request_t);
120 :
121 : /* -=[Send Request Phase]=- */
122 18 : status = libspdm_send_spdm_request(spdm_context, session_id, spdm_request_size, spdm_request);
123 18 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
124 1 : libspdm_release_sender_buffer (spdm_context);
125 1 : return status;
126 : }
127 17 : libspdm_release_sender_buffer (spdm_context);
128 17 : spdm_request = (void *)spdm_context->last_spdm_request;
129 :
130 : /* -=[Receive Response Phase]=- */
131 17 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
132 17 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
133 0 : return status;
134 : }
135 17 : LIBSPDM_ASSERT (message_size >= transport_header_size);
136 17 : spdm_response = (void *)(message);
137 17 : spdm_response_size = message_size;
138 :
139 17 : status = libspdm_receive_spdm_response(
140 : spdm_context, session_id, &spdm_response_size, (void **)&spdm_response);
141 17 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
142 0 : goto receive_done;
143 : }
144 :
145 : /* -=[Validate Response Phase]=- */
146 17 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
147 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
148 0 : goto receive_done;
149 : }
150 17 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
151 0 : status = libspdm_handle_error_response_main(
152 : spdm_context, session_id,
153 : &spdm_response_size,
154 : (void **)&spdm_response, SPDM_GET_KEY_PAIR_INFO, SPDM_KEY_PAIR_INFO);
155 0 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
156 0 : goto receive_done;
157 : }
158 17 : } else if (spdm_response->header.request_response_code != SPDM_KEY_PAIR_INFO) {
159 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
160 0 : goto receive_done;
161 : }
162 17 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
163 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
164 0 : goto receive_done;
165 : }
166 :
167 17 : if ((spdm_response->key_pair_id != key_pair_id) ||
168 16 : (spdm_response->key_pair_id > (spdm_response->total_key_pairs))) {
169 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
170 2 : goto receive_done;
171 : }
172 :
173 15 : if (spdm_response_size < sizeof(spdm_key_pair_info_response_t)) {
174 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
175 0 : goto receive_done;
176 : }
177 :
178 15 : if (spdm_response_size < sizeof(spdm_key_pair_info_response_t) +
179 15 : spdm_response->public_key_info_len) {
180 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
181 0 : goto receive_done;
182 : }
183 :
184 15 : rsp_pqc_asym_algo_capabilities = 0;
185 15 : rsp_current_pqc_asym_algo = 0;
186 15 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_14) {
187 1 : if (spdm_response_size < sizeof(spdm_key_pair_info_response_t) +
188 1 : spdm_response->public_key_info_len + sizeof(uint8_t)) {
189 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
190 0 : goto receive_done;
191 : }
192 1 : ptr = (uint8_t *)spdm_response + sizeof(spdm_key_pair_info_response_t) + spdm_response->public_key_info_len;
193 :
194 1 : pqc_asym_algo_cap_raw_len = *ptr;
195 1 : if (spdm_response_size < sizeof(spdm_key_pair_info_response_t) +
196 1 : spdm_response->public_key_info_len + sizeof(uint8_t) +
197 1 : pqc_asym_algo_cap_raw_len + sizeof(uint8_t)) {
198 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
199 0 : goto receive_done;
200 : }
201 1 : pqc_asym_algo_cap_copy_len = (uint8_t)LIBSPDM_MIN(pqc_asym_algo_cap_raw_len,
202 : sizeof(uint32_t));
203 1 : libspdm_copy_mem (&rsp_pqc_asym_algo_capabilities, sizeof(rsp_pqc_asym_algo_capabilities),
204 1 : ptr + sizeof(uint8_t), pqc_asym_algo_cap_copy_len);
205 :
206 1 : current_pqc_asym_algo_raw_len = *(ptr + sizeof(uint8_t) + pqc_asym_algo_cap_raw_len);
207 1 : if (spdm_response_size < sizeof(spdm_key_pair_info_response_t) +
208 1 : spdm_response->public_key_info_len + sizeof(uint8_t) +
209 1 : pqc_asym_algo_cap_raw_len + sizeof(uint8_t) +
210 : current_pqc_asym_algo_raw_len) {
211 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
212 0 : goto receive_done;
213 : }
214 1 : current_pqc_asym_algo_copy_len = (uint8_t)LIBSPDM_MIN(current_pqc_asym_algo_raw_len,
215 : sizeof(uint32_t));
216 1 : libspdm_copy_mem (&rsp_current_pqc_asym_algo, sizeof(rsp_current_pqc_asym_algo),
217 1 : ptr + sizeof(uint8_t) + pqc_asym_algo_cap_raw_len + sizeof(uint8_t),
218 : current_pqc_asym_algo_copy_len);
219 :
220 1 : rsp_pqc_asym_algo_capabilities &= SPDM_KEY_PAIR_PQC_ASYM_ALGO_CAP_MASK;
221 1 : rsp_current_pqc_asym_algo &= SPDM_KEY_PAIR_PQC_ASYM_ALGO_CAP_MASK;
222 : } else {
223 14 : spdm_response_size = sizeof(spdm_key_pair_info_response_t) + spdm_response->public_key_info_len;
224 : }
225 :
226 : /* -=[Process Response Phase]=- */
227 :
228 : /*If responder doesn't support SET_KEY_PAIR_INFO_CAP,the capabilities should be 0*/
229 15 : if ((!libspdm_is_capabilities_flag_supported(
230 : spdm_context, true, 0,
231 0 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_SET_KEY_PAIR_INFO_CAP)) &&
232 0 : ((spdm_response->capabilities & SPDM_KEY_PAIR_CAP_MASK) != 0)) {
233 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
234 0 : goto receive_done;
235 : }
236 :
237 15 : *total_key_pairs = spdm_response->total_key_pairs;
238 15 : *capabilities = spdm_response->capabilities & SPDM_KEY_PAIR_CAP_MASK;
239 15 : if (((*capabilities & SPDM_KEY_PAIR_CAP_SHAREABLE_CAP) != 0) &&
240 1 : ((*capabilities & SPDM_KEY_PAIR_CAP_CERT_ASSOC_CAP) == 0)) {
241 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
242 1 : goto receive_done;
243 : }
244 :
245 14 : *key_usage_capabilities = (spdm_response->key_usage_capabilities) & SPDM_KEY_USAGE_BIT_MASK;
246 14 : if (*key_usage_capabilities == 0) {
247 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
248 1 : goto receive_done;
249 : }
250 13 : *current_key_usage = (spdm_response->current_key_usage) & SPDM_KEY_USAGE_BIT_MASK;
251 13 : if ((*key_usage_capabilities | *current_key_usage) != *key_usage_capabilities) {
252 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
253 2 : goto receive_done;
254 : }
255 :
256 11 : *asym_algo_capabilities = (spdm_response->asym_algo_capabilities) &
257 : SPDM_KEY_PAIR_ASYM_ALGO_CAP_MASK;
258 11 : if (*asym_algo_capabilities == 0) {
259 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
260 1 : goto receive_done;
261 : }
262 10 : *current_asym_algo = (spdm_response->current_asym_algo) & SPDM_KEY_PAIR_ASYM_ALGO_CAP_MASK;
263 10 : if (!libspdm_onehot0(*current_asym_algo)) {
264 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
265 1 : goto receive_done;
266 : }
267 9 : if ((*asym_algo_capabilities | *current_asym_algo) != *asym_algo_capabilities) {
268 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
269 1 : goto receive_done;
270 : }
271 :
272 8 : if (!libspdm_onehot0(rsp_current_pqc_asym_algo)) {
273 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
274 0 : goto receive_done;
275 : }
276 8 : if ((rsp_pqc_asym_algo_capabilities | rsp_current_pqc_asym_algo) != rsp_pqc_asym_algo_capabilities) {
277 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
278 0 : goto receive_done;
279 : }
280 8 : if ((*current_asym_algo != 0) && (rsp_current_pqc_asym_algo != 0)) {
281 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
282 0 : goto receive_done;
283 : }
284 :
285 8 : if (pqc_asym_algo_capabilities != NULL) {
286 8 : *pqc_asym_algo_capabilities = rsp_pqc_asym_algo_capabilities;
287 : }
288 8 : if (current_pqc_asym_algo != NULL) {
289 8 : *current_pqc_asym_algo = rsp_current_pqc_asym_algo;
290 : }
291 :
292 8 : *assoc_cert_slot_mask = spdm_response->assoc_cert_slot_mask;
293 8 : if (!libspdm_onehot0(*assoc_cert_slot_mask) &&
294 2 : (((*capabilities & SPDM_KEY_PAIR_CAP_SHAREABLE_CAP) == 0) &&
295 1 : (libspdm_is_capabilities_flag_supported(
296 : spdm_context, true, 0,
297 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_SET_KEY_PAIR_INFO_CAP)))) {
298 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
299 1 : goto receive_done;
300 : }
301 :
302 7 : if (*public_key_info_len < spdm_response->public_key_info_len) {
303 0 : status = LIBSPDM_STATUS_BUFFER_FULL;
304 0 : goto receive_done;
305 : }
306 7 : *public_key_info_len = spdm_response->public_key_info_len;
307 :
308 7 : libspdm_copy_mem(public_key_info,
309 7 : spdm_response->public_key_info_len,
310 7 : spdm_response->public_key_info,
311 7 : spdm_response->public_key_info_len);
312 :
313 7 : status = LIBSPDM_STATUS_SUCCESS;
314 :
315 : /* -=[Log Message Phase]=- */
316 : #if LIBSPDM_ENABLE_MSG_LOG
317 7 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
318 : #endif /* LIBSPDM_ENABLE_MSG_LOG */
319 :
320 17 : receive_done:
321 17 : libspdm_release_receiver_buffer (spdm_context);
322 17 : return status;
323 : }
324 :
325 18 : libspdm_return_t libspdm_get_key_pair_info(void *spdm_context, const uint32_t *session_id,
326 : uint8_t key_pair_id, uint8_t *total_key_pairs,
327 : uint16_t *capabilities,
328 : uint16_t *key_usage_capabilities,
329 : uint16_t *current_key_usage,
330 : uint32_t *asym_algo_capabilities,
331 : uint32_t *current_asym_algo,
332 : uint32_t *pqc_asym_algo_capabilities,
333 : uint32_t *current_pqc_asym_algo,
334 : uint8_t *assoc_cert_slot_mask,
335 : uint16_t *public_key_info_len,
336 : void *public_key_info
337 : )
338 : {
339 : libspdm_context_t *context;
340 : size_t retry;
341 : uint64_t retry_delay_time;
342 : libspdm_return_t status;
343 :
344 18 : context = spdm_context;
345 18 : context->crypto_request = true;
346 18 : retry = context->retry_times;
347 18 : retry_delay_time = context->retry_delay_time;
348 : do {
349 18 : status = libspdm_try_get_key_pair_info(context, session_id, key_pair_id,
350 : total_key_pairs, capabilities,
351 : key_usage_capabilities, current_key_usage,
352 : asym_algo_capabilities, current_asym_algo,
353 : pqc_asym_algo_capabilities, current_pqc_asym_algo,
354 : assoc_cert_slot_mask, public_key_info_len,
355 : public_key_info);
356 18 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
357 18 : return status;
358 : }
359 :
360 0 : libspdm_sleep(retry_delay_time);
361 0 : } while (retry-- != 0);
362 :
363 0 : return status;
364 : }
365 :
366 : #endif /* LIBSPDM_ENABLE_CAPABILITY_GET_KEY_PAIR_INFO_CAP */
|