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_responder_lib.h"
8 :
9 : #if LIBSPDM_ENABLE_CAPABILITY_SET_KEY_PAIR_INFO_CAP
10 :
11 22 : libspdm_return_t libspdm_get_response_set_key_pair_info_ack(libspdm_context_t *spdm_context,
12 : size_t request_size,
13 : const void *request,
14 : size_t *response_size,
15 : void *response)
16 : {
17 : const spdm_set_key_pair_info_request_t *spdm_request;
18 : spdm_set_key_pair_info_ack_response_t *spdm_response;
19 :
20 : libspdm_session_info_t *session_info;
21 : libspdm_session_state_t session_state;
22 :
23 : uint16_t capabilities;
24 : uint16_t key_usage_capabilities;
25 : uint16_t current_key_usage;
26 : uint32_t asym_algo_capabilities;
27 : uint32_t current_asym_algo;
28 : uint32_t pqc_asym_algo_capabilities;
29 : uint32_t current_pqc_asym_algo;
30 : uint8_t assoc_cert_slot_mask;
31 : uint8_t key_pair_id;
32 : uint8_t total_key_pairs;
33 : bool result;
34 :
35 : uint16_t desired_key_usage;
36 : uint32_t desired_asym_algo;
37 : uint8_t desired_assoc_cert_slot_mask;
38 : uint8_t desired_pqc_asym_algo_len;
39 : uint32_t desired_pqc_asym_algo;
40 : uint8_t operation;
41 : bool need_reset;
42 : const uint8_t *ptr;
43 :
44 22 : spdm_request = request;
45 :
46 : /* -=[Check Parameters Phase]=- */
47 22 : LIBSPDM_ASSERT(spdm_request->header.request_response_code == SPDM_SET_KEY_PAIR_INFO);
48 :
49 22 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_13) {
50 1 : return libspdm_generate_error_response(spdm_context,
51 : SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
52 : SPDM_SET_KEY_PAIR_INFO,
53 : response_size, response);
54 : }
55 :
56 21 : if (spdm_request->header.spdm_version != libspdm_get_connection_version(spdm_context)) {
57 1 : return libspdm_generate_error_response(spdm_context,
58 : SPDM_ERROR_CODE_VERSION_MISMATCH, 0,
59 : response_size, response);
60 : }
61 :
62 20 : if (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) {
63 0 : return libspdm_responder_handle_response_state(spdm_context,
64 0 : spdm_request->header.request_response_code,
65 : response_size, response);
66 : }
67 :
68 20 : if (request_size < sizeof(spdm_set_key_pair_info_request_t)) {
69 1 : return libspdm_generate_error_response(spdm_context,
70 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
71 : response_size, response);
72 : }
73 :
74 19 : if (spdm_context->connection_info.connection_state <
75 : LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
76 1 : return libspdm_generate_error_response(
77 : spdm_context,
78 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
79 : response_size, response);
80 : }
81 :
82 18 : if (spdm_context->last_spdm_request_session_id_valid) {
83 0 : session_info = libspdm_get_session_info_via_session_id(
84 : spdm_context,
85 : spdm_context->last_spdm_request_session_id);
86 0 : if (session_info == NULL) {
87 0 : return libspdm_generate_error_response(
88 : spdm_context,
89 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
90 : response_size, response);
91 : }
92 0 : session_state = libspdm_secured_message_get_session_state(
93 : session_info->secured_message_context);
94 0 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
95 0 : return libspdm_generate_error_response(
96 : spdm_context,
97 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
98 : response_size, response);
99 : }
100 : }
101 :
102 18 : if (!libspdm_is_capabilities_flag_supported(
103 : spdm_context, false, 0,
104 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_SET_KEY_PAIR_INFO_CAP)) {
105 1 : return libspdm_generate_error_response(
106 : spdm_context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
107 : SPDM_SET_KEY_PAIR_INFO, response_size, response);
108 : }
109 :
110 17 : LIBSPDM_ASSERT(*response_size >= sizeof(spdm_set_key_pair_info_ack_response_t));
111 :
112 17 : libspdm_zero_mem(response, *response_size);
113 :
114 17 : total_key_pairs = 0;
115 17 : key_pair_id = spdm_request->key_pair_id;
116 17 : result = libspdm_read_key_pair_info(
117 : spdm_context,
118 : key_pair_id,
119 : &total_key_pairs,
120 : &capabilities,
121 : &key_usage_capabilities,
122 : ¤t_key_usage,
123 : &asym_algo_capabilities,
124 : ¤t_asym_algo,
125 : &pqc_asym_algo_capabilities,
126 : ¤t_pqc_asym_algo,
127 : &assoc_cert_slot_mask,
128 : NULL, NULL);
129 17 : if ((key_pair_id == 0) || (key_pair_id > total_key_pairs)) {
130 1 : return libspdm_generate_error_response(spdm_context,
131 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
132 : response_size, response);
133 : }
134 16 : if (!result) {
135 0 : return libspdm_generate_error_response(spdm_context,
136 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
137 : response_size, response);
138 : }
139 :
140 16 : operation = spdm_request->header.param1;
141 :
142 : /* Validate the Operation value up front, before parsing the operation-specific fields. */
143 16 : if (operation > SPDM_SET_KEY_PAIR_INFO_GENERATE_OPERATION) {
144 0 : return libspdm_generate_error_response(spdm_context,
145 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
146 : response_size, response);
147 : }
148 :
149 16 : if (operation != SPDM_SET_KEY_PAIR_INFO_ERASE_OPERATION) {
150 12 : if (request_size < sizeof(spdm_set_key_pair_info_request_t) +
151 : sizeof(uint8_t) + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint8_t)) {
152 1 : return libspdm_generate_error_response(spdm_context,
153 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
154 : response_size, response);
155 : }
156 :
157 11 : ptr = (const uint8_t*)(spdm_request + 1);
158 11 : ptr += sizeof(uint8_t);
159 :
160 11 : desired_key_usage = libspdm_read_uint16((const uint8_t *)ptr);
161 11 : ptr += sizeof(uint16_t);
162 :
163 11 : desired_asym_algo = libspdm_read_uint32((const uint8_t *)ptr);
164 11 : ptr += sizeof(uint32_t);
165 :
166 11 : desired_assoc_cert_slot_mask = *ptr;
167 11 : ptr += sizeof(uint8_t);
168 :
169 11 : desired_pqc_asym_algo = 0;
170 11 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_14) {
171 9 : if (request_size < sizeof(spdm_set_key_pair_info_request_t) +
172 : sizeof(uint8_t) + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint8_t) +
173 : sizeof(uint8_t)) {
174 0 : return libspdm_generate_error_response(spdm_context,
175 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
176 : response_size, response);
177 : }
178 :
179 9 : desired_pqc_asym_algo_len = *ptr;
180 9 : ptr += sizeof(uint8_t);
181 :
182 9 : if (request_size < sizeof(spdm_set_key_pair_info_request_t) +
183 : sizeof(uint8_t) + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint8_t) +
184 9 : sizeof(uint8_t) + desired_pqc_asym_algo_len) {
185 0 : return libspdm_generate_error_response(spdm_context,
186 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
187 : response_size, response);
188 : }
189 :
190 9 : if (desired_pqc_asym_algo_len > sizeof(uint32_t)) {
191 0 : desired_pqc_asym_algo_len = sizeof(uint32_t);
192 : }
193 9 : libspdm_copy_mem (&desired_pqc_asym_algo, sizeof(desired_pqc_asym_algo),
194 : ptr, desired_pqc_asym_algo_len);
195 9 : ptr += desired_pqc_asym_algo_len;
196 : }
197 :
198 : } else {
199 4 : desired_key_usage = 0;
200 4 : desired_asym_algo = 0;
201 4 : desired_pqc_asym_algo = 0;
202 4 : desired_assoc_cert_slot_mask = 0;
203 : }
204 :
205 15 : if (((capabilities & SPDM_KEY_PAIR_CAP_GEN_KEY_CAP) == 0) &&
206 : (operation == SPDM_SET_KEY_PAIR_INFO_GENERATE_OPERATION)) {
207 0 : return libspdm_generate_error_response(spdm_context,
208 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
209 : response_size, response);
210 : }
211 15 : if (((capabilities & SPDM_KEY_PAIR_CAP_ERASABLE_CAP) == 0) &&
212 : (operation == SPDM_SET_KEY_PAIR_INFO_ERASE_OPERATION)) {
213 0 : return libspdm_generate_error_response(spdm_context,
214 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
215 : response_size, response);
216 : }
217 15 : if (((capabilities & SPDM_KEY_PAIR_CAP_CERT_ASSOC_CAP) == 0) &&
218 0 : (desired_assoc_cert_slot_mask != 0) &&
219 0 : (desired_assoc_cert_slot_mask != assoc_cert_slot_mask)) {
220 0 : return libspdm_generate_error_response(spdm_context,
221 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
222 : response_size, response);
223 : }
224 :
225 15 : if (((capabilities & SPDM_KEY_PAIR_CAP_KEY_USAGE_CAP) == 0) && (desired_key_usage != 0)) {
226 0 : return libspdm_generate_error_response(spdm_context,
227 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
228 : response_size, response);
229 : }
230 15 : if ((desired_key_usage != 0) &&
231 5 : ((key_usage_capabilities | desired_key_usage) != key_usage_capabilities)) {
232 0 : return libspdm_generate_error_response(spdm_context,
233 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
234 : response_size, response);
235 : }
236 :
237 15 : if (((capabilities & SPDM_KEY_PAIR_CAP_ASYM_ALGO_CAP) == 0) &&
238 0 : ((desired_asym_algo != 0) || (desired_pqc_asym_algo != 0))) {
239 0 : return libspdm_generate_error_response(spdm_context,
240 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
241 : response_size, response);
242 : }
243 15 : if (!libspdm_onehot0(desired_asym_algo) || !libspdm_onehot0(desired_pqc_asym_algo)) {
244 1 : return libspdm_generate_error_response(spdm_context,
245 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
246 : response_size, response);
247 : }
248 14 : if ((desired_asym_algo != 0) && (desired_pqc_asym_algo != 0)) {
249 1 : return libspdm_generate_error_response(spdm_context,
250 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
251 : response_size, response);
252 : }
253 13 : if ((desired_asym_algo != 0) &&
254 3 : ((asym_algo_capabilities | desired_asym_algo) != asym_algo_capabilities)) {
255 0 : return libspdm_generate_error_response(spdm_context,
256 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
257 : response_size, response);
258 : }
259 13 : if ((desired_pqc_asym_algo != 0) &&
260 1 : ((pqc_asym_algo_capabilities | desired_pqc_asym_algo) != pqc_asym_algo_capabilities)) {
261 : /* Per DSP0274 Table 115, the Requester shall only select from bits set in the
262 : * capabilities. A DesiredPqcAsymAlgo outside PqcAsymAlgoCapabilities is the same class
263 : * of malformed request as the DesiredAsymAlgo case above, so use InvalidRequest for
264 : * both. */
265 1 : return libspdm_generate_error_response(spdm_context,
266 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
267 : response_size, response);
268 : }
269 :
270 12 : if (((capabilities & SPDM_KEY_PAIR_CAP_SHAREABLE_CAP) == 0) &&
271 0 : (!libspdm_onehot0(desired_assoc_cert_slot_mask))) {
272 0 : return libspdm_generate_error_response(spdm_context,
273 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
274 : response_size, response);
275 : }
276 12 : if ((operation == SPDM_SET_KEY_PAIR_INFO_ERASE_OPERATION) ||
277 : (operation == SPDM_SET_KEY_PAIR_INFO_GENERATE_OPERATION)) {
278 4 : if (assoc_cert_slot_mask != 0) {
279 1 : return libspdm_generate_error_response(spdm_context,
280 : SPDM_ERROR_CODE_OPERATION_FAILED, 0,
281 : response_size, response);
282 : }
283 : }
284 :
285 : /* Per DSP0274, a request for key generation (GenerateKeyPair) when no asymmetric algorithm
286 : * has been selected yet should be answered with ERROR(OperationFailed). The algorithm is
287 : * selected either by this request (DesiredAsymAlgo/DesiredPqcAsymAlgo) or already configured
288 : * for the key pair (CurrentAsymAlgo/CurrentPqcAsymAlgo). */
289 11 : if (operation == SPDM_SET_KEY_PAIR_INFO_GENERATE_OPERATION) {
290 0 : if ((desired_asym_algo == 0) && (desired_pqc_asym_algo == 0) &&
291 0 : (current_asym_algo == 0) && (current_pqc_asym_algo == 0)) {
292 0 : return libspdm_generate_error_response(spdm_context,
293 : SPDM_ERROR_CODE_OPERATION_FAILED, 0,
294 : response_size, response);
295 : }
296 : }
297 :
298 : /* Per DSP0274, the value of a key pair is bound to its selected asymmetric algorithm
299 : * (CurrentAsymAlgo). Once a key pair is generated for a KeyPairID, a ParameterChange that
300 : * would change the algorithm of the generated key pair shall be rejected with
301 : * InvalidRequest. A key pair is considered generated here when an algorithm is already
302 : * configured (CurrentAsymAlgo or CurrentPqcAsymAlgo is set). A desired algorithm of 0 means
303 : * "do not change", so only a non-zero desired algorithm that differs from the current one is
304 : * rejected. */
305 11 : if (operation == SPDM_SET_KEY_PAIR_INFO_CHANGE_OPERATION) {
306 8 : if (((current_asym_algo != 0) || (current_pqc_asym_algo != 0)) &&
307 0 : (((desired_asym_algo != 0) && (desired_asym_algo != current_asym_algo)) ||
308 5 : ((desired_pqc_asym_algo != 0) && (desired_pqc_asym_algo != current_pqc_asym_algo)))) {
309 0 : return libspdm_generate_error_response(spdm_context,
310 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
311 : response_size, response);
312 : }
313 : }
314 :
315 11 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) {
316 8 : need_reset = libspdm_is_capabilities_flag_supported(
317 : spdm_context, false, 0,
318 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_SET_KEY_PAIR_RESET_CAP);
319 : } else {
320 3 : need_reset = false;
321 : }
322 11 : result = libspdm_write_key_pair_info(
323 : spdm_context,
324 : key_pair_id,
325 : operation,
326 : desired_key_usage,
327 : desired_asym_algo,
328 : desired_pqc_asym_algo,
329 : desired_assoc_cert_slot_mask,
330 : &need_reset);
331 11 : if (!result) {
332 0 : return libspdm_generate_error_response(spdm_context,
333 : SPDM_ERROR_CODE_OPERATION_FAILED, 0,
334 : response_size, response);
335 : }
336 :
337 11 : spdm_response = response;
338 11 : *response_size = sizeof(spdm_set_key_pair_info_ack_response_t);
339 :
340 11 : if (need_reset) {
341 5 : return libspdm_generate_error_response(spdm_context,
342 : SPDM_ERROR_CODE_RESET_REQUIRED, 0,
343 : response_size, response);
344 : } else {
345 6 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
346 6 : spdm_response->header.request_response_code = SPDM_SET_KEY_PAIR_INFO_ACK;
347 6 : spdm_response->header.param1 = 0;
348 6 : spdm_response->header.param2 = 0;
349 : }
350 :
351 6 : return LIBSPDM_STATUS_SUCCESS;
352 : }
353 :
354 : #endif /*LIBSPDM_ENABLE_CAPABILITY_SET_KEY_PAIR_INFO_CAP*/
|