Branch data Line data Source code
1 : : /**
2 : : * Copyright Notice:
3 : : * Copyright 2021-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_CERT_CAP
10 : :
11 : : #if LIBSPDM_CERT_PARSE_SUPPORT
12 : : /*set_cert verify cert_chain*/
13 : 8 : static bool libspdm_set_cert_verify_certchain(
14 : : uint8_t spdm_version,
15 : : const uint8_t *cert_chain, size_t cert_chain_size,
16 : : uint32_t base_asym_algo, uint32_t pqc_asym_algo, uint32_t base_hash_algo,
17 : : uint8_t cert_model)
18 : : {
19 : : const uint8_t *root_cert_buffer;
20 : : size_t root_cert_buffer_size;
21 : : const uint8_t *leaf_cert_buffer;
22 : : size_t leaf_cert_buffer_size;
23 : :
24 : : /*get root cert*/
25 [ - + ]: 8 : if (!libspdm_x509_get_cert_from_cert_chain(
26 : : cert_chain, cert_chain_size, 0, &root_cert_buffer,
27 : : &root_cert_buffer_size)) {
28 : 0 : return false;
29 : : }
30 : :
31 : : /*verify cert_chain*/
32 [ - + ]: 8 : if (!libspdm_x509_verify_cert_chain(root_cert_buffer, root_cert_buffer_size,
33 : : cert_chain, cert_chain_size)) {
34 : 0 : return false;
35 : : }
36 : :
37 : : /*get leaf cert*/
38 [ - + ]: 8 : if (!libspdm_x509_get_cert_from_cert_chain(
39 : : cert_chain, cert_chain_size, -1, &leaf_cert_buffer,
40 : : &leaf_cert_buffer_size)) {
41 : 0 : return false;
42 : : }
43 : :
44 : : /*verify leaf cert*/
45 [ - + ]: 8 : if (!libspdm_x509_set_cert_certificate_check(
46 : : spdm_version,
47 : : leaf_cert_buffer, leaf_cert_buffer_size,
48 : : base_asym_algo, pqc_asym_algo, base_hash_algo,
49 : : false, cert_model)) {
50 : 0 : return false;
51 : : }
52 : :
53 : 8 : return true;
54 : : }
55 : : #endif /*LIBSPDM_CERT_PARSE_SUPPORT*/
56 : :
57 : 14 : libspdm_return_t libspdm_get_response_set_certificate(libspdm_context_t *spdm_context,
58 : : size_t request_size, const void *request,
59 : : size_t *response_size, void *response)
60 : : {
61 : : const spdm_set_certificate_request_t *spdm_request;
62 : : spdm_set_certificate_response_t *spdm_response;
63 : :
64 : : bool result;
65 : : uint8_t spdm_version;
66 : : uint8_t slot_id;
67 : : bool need_reset;
68 : : bool is_busy;
69 : : bool erase;
70 : : uint8_t set_cert_model;
71 : :
72 : : size_t root_cert_hash_size;
73 : : const spdm_cert_chain_t *cert_chain_header;
74 : : #if LIBSPDM_CERT_PARSE_SUPPORT
75 : : size_t cert_chain_size;
76 : : #endif /*LIBSPDM_CERT_PARSE_SUPPORT*/
77 : : const void * cert_chain;
78 : : const void *full_cert_chain;
79 : : size_t full_cert_chain_size;
80 : : const void *old_local_cert_chain;
81 : : size_t old_local_cert_chain_size;
82 : :
83 : : libspdm_session_info_t *session_info;
84 : : const uint32_t *session_id;
85 : : libspdm_session_state_t session_state;
86 : :
87 : 14 : spdm_request = request;
88 : 14 : full_cert_chain = NULL;
89 : 14 : full_cert_chain_size = 0;
90 : :
91 : : /* -=[Check Parameters Phase]=- */
92 [ - + ]: 14 : LIBSPDM_ASSERT(spdm_request->header.request_response_code == SPDM_SET_CERTIFICATE);
93 : :
94 : 14 : spdm_version = libspdm_get_connection_version(spdm_context);
95 : :
96 [ - + ]: 14 : if (spdm_version < SPDM_MESSAGE_VERSION_12) {
97 : 0 : return libspdm_generate_error_response(spdm_context,
98 : : SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
99 : : SPDM_SET_CERTIFICATE,
100 : : response_size, response);
101 : : }
102 : :
103 [ - + ]: 14 : if (spdm_request->header.spdm_version != spdm_version) {
104 : 0 : return libspdm_generate_error_response(spdm_context,
105 : : SPDM_ERROR_CODE_VERSION_MISMATCH, 0,
106 : : response_size, response);
107 : : }
108 : :
109 [ + + ]: 14 : if (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) {
110 : 2 : return libspdm_responder_handle_response_state(spdm_context,
111 : 2 : spdm_request->header.request_response_code,
112 : : response_size, response);
113 : : }
114 : :
115 [ - + ]: 12 : if (spdm_context->connection_info.connection_state <
116 : : LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
117 : 0 : return libspdm_generate_error_response(
118 : : spdm_context,
119 : : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
120 : : response_size, response);
121 : : }
122 : :
123 : 12 : session_id = NULL;
124 [ + + ]: 12 : if (spdm_context->last_spdm_request_session_id_valid) {
125 : 7 : session_id = &spdm_context->last_spdm_request_session_id;
126 : 7 : session_info = libspdm_get_session_info_via_session_id(
127 : : spdm_context,
128 : : spdm_context->last_spdm_request_session_id);
129 [ - + ]: 7 : if (session_info == NULL) {
130 : 0 : return libspdm_generate_error_response(
131 : : spdm_context,
132 : : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
133 : : response_size, response);
134 : : }
135 : 7 : session_state = libspdm_secured_message_get_session_state(
136 : : session_info->secured_message_context);
137 [ - + ]: 7 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
138 : 0 : return libspdm_generate_error_response(
139 : : spdm_context,
140 : : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
141 : : response_size, response);
142 : : }
143 : : }
144 : :
145 [ - + ]: 12 : if (!libspdm_is_capabilities_flag_supported(
146 : : spdm_context, false, 0,
147 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_SET_CERT_CAP)) {
148 : 0 : return libspdm_generate_error_response(
149 : : spdm_context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
150 : : SPDM_SET_CERTIFICATE, response_size, response);
151 : : }
152 : :
153 : 12 : slot_id = spdm_request->header.param1 & SPDM_SET_CERTIFICATE_REQUEST_SLOT_ID_MASK;
154 [ - + ]: 12 : if (slot_id >= SPDM_MAX_SLOT_COUNT) {
155 : 0 : return libspdm_generate_error_response(spdm_context,
156 : : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
157 : : response_size, response);
158 : : }
159 : :
160 [ + + + + : 12 : if ((!libspdm_is_in_trusted_environment(spdm_context, session_id)) && (slot_id != 0) &&
+ + ]
161 : : (session_id == NULL)) {
162 : 1 : return libspdm_generate_error_response(spdm_context,
163 : : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
164 : : response_size, response);
165 : : }
166 : :
167 : 11 : root_cert_hash_size = libspdm_get_hash_size(
168 : : spdm_context->connection_info.algorithm.base_hash_algo);
169 : :
170 : 11 : old_local_cert_chain =
171 : 11 : spdm_context->local_context.local_cert_chain_provision[slot_id];
172 : 11 : old_local_cert_chain_size =
173 : 11 : spdm_context->local_context.local_cert_chain_provision_size[slot_id];
174 : :
175 [ + + ]: 11 : if (spdm_version >= SPDM_MESSAGE_VERSION_13) {
176 : 3 : const uint8_t key_pair_id = spdm_request->header.param2;
177 : :
178 : 3 : set_cert_model =
179 : 3 : (spdm_request->header.param1 &
180 : 3 : SPDM_SET_CERTIFICATE_REQUEST_ATTRIBUTES_CERT_MODEL_MASK) >>
181 : : SPDM_SET_CERTIFICATE_REQUEST_ATTRIBUTES_CERT_MODEL_OFFSET;
182 : 3 : erase = (spdm_request->header.param1 & SPDM_SET_CERTIFICATE_REQUEST_ATTRIBUTES_ERASE) != 0;
183 : :
184 [ + + ]: 3 : if (spdm_context->connection_info.multi_key_conn_rsp) {
185 [ - + ]: 2 : if (key_pair_id == 0) {
186 : 0 : return libspdm_generate_error_response(spdm_context,
187 : : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
188 : : response_size, response);
189 : : }
190 [ + - ]: 2 : if (!erase) {
191 [ + + - + ]: 2 : if ((set_cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) ||
192 : : (set_cert_model > SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT)) {
193 : 1 : return libspdm_generate_error_response(spdm_context,
194 : : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
195 : : response_size, response);
196 : : }
197 : : }
198 : : } else {
199 [ + - - + ]: 1 : if ((key_pair_id != 0) || (set_cert_model != 0)) {
200 : 0 : return libspdm_generate_error_response(spdm_context,
201 : : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
202 : : response_size, response);
203 : : }
204 [ - + ]: 1 : if ((spdm_context->local_context.capability.flags &
205 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ALIAS_CERT_CAP) != 0) {
206 : 0 : set_cert_model = SPDM_CERTIFICATE_INFO_CERT_MODEL_ALIAS_CERT;
207 : : } else {
208 : 1 : set_cert_model = SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT;
209 : : }
210 : : }
211 : : } else {
212 [ + + ]: 8 : if ((spdm_context->local_context.capability.flags &
213 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ALIAS_CERT_CAP) != 0) {
214 : 1 : set_cert_model = SPDM_CERTIFICATE_INFO_CERT_MODEL_ALIAS_CERT;
215 : : } else {
216 : 7 : set_cert_model = SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT;
217 : : }
218 : : }
219 : :
220 : 10 : need_reset = libspdm_is_capabilities_flag_supported(
221 : : spdm_context, false, 0,
222 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_INSTALL_RESET_CAP);
223 : 10 : is_busy = false;
224 : :
225 [ + + + + ]: 10 : if ((spdm_version >= SPDM_MESSAGE_VERSION_13) && erase) {
226 : : /*the CertChain field shall be absent; the value of SetCertModel shall be zero*/
227 [ + - ]: 1 : if ((request_size < sizeof(spdm_set_certificate_request_t)) ||
228 [ - + ]: 1 : ((spdm_request->header.param1 &
229 : : SPDM_SET_CERTIFICATE_REQUEST_ATTRIBUTES_CERT_MODEL_MASK) != 0)) {
230 : 0 : return libspdm_generate_error_response(spdm_context,
231 : : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
232 : : response_size, response);
233 : : }
234 : :
235 : : /* erase slot_id cert_chain*/
236 : 1 : result = libspdm_update_local_cert_chain(
237 : : spdm_context,
238 : : session_id,
239 : : slot_id, 0, 0, 0, 0,
240 : : old_local_cert_chain,
241 : : old_local_cert_chain_size,
242 : : NULL, 0,
243 : : set_cert_model,
244 : : &need_reset, &is_busy);
245 [ - + ]: 1 : if (!result) {
246 [ # # ]: 0 : if (is_busy) {
247 : 0 : return libspdm_generate_error_response(spdm_context,
248 : : SPDM_ERROR_CODE_BUSY, 0,
249 : : response_size, response);
250 : : } else {
251 : 0 : return libspdm_generate_error_response(spdm_context,
252 : : SPDM_ERROR_CODE_OPERATION_FAILED, 0,
253 : : response_size, response);
254 : : }
255 : : }
256 : : } else {
257 : 9 : if (request_size < sizeof(spdm_set_certificate_request_t) +
258 [ + + ]: 9 : sizeof(spdm_cert_chain_t) + root_cert_hash_size) {
259 : 1 : return libspdm_generate_error_response(spdm_context,
260 : : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
261 : : response_size, response);
262 : : }
263 : :
264 : : /*point to full SPDM certificate chain*/
265 : 8 : cert_chain = (const void*)(spdm_request + 1);
266 : 8 : cert_chain_header = cert_chain;
267 : 8 : full_cert_chain = cert_chain;
268 : 8 : full_cert_chain_size = cert_chain_header->length;
269 : :
270 [ - + ]: 8 : if (cert_chain_header->length < sizeof(spdm_cert_chain_t) + root_cert_hash_size) {
271 : 0 : return libspdm_generate_error_response(spdm_context,
272 : : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
273 : : response_size, response);
274 : : }
275 [ - + ]: 8 : if (cert_chain_header->length > request_size - sizeof(spdm_set_certificate_request_t)) {
276 : 0 : return libspdm_generate_error_response(spdm_context,
277 : : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
278 : : response_size, response);
279 : : }
280 : :
281 [ - + ]: 8 : if ((cert_chain_header->length > SPDM_MAX_CERTIFICATE_CHAIN_SIZE) &&
282 [ # # ]: 0 : (!libspdm_is_capabilities_flag_supported(
283 : : spdm_context, false, 0,
284 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_LARGE_RESP_CAP))) {
285 : 0 : return libspdm_generate_error_response(spdm_context,
286 : : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
287 : : response_size, response);
288 : : }
289 : :
290 : : /*point to actual cert_chain*/
291 : 8 : cert_chain = (const void*)((const uint8_t *)cert_chain
292 : 8 : + sizeof(spdm_cert_chain_t) + root_cert_hash_size);
293 : :
294 : : #if LIBSPDM_CERT_PARSE_SUPPORT
295 : : /*get actual cert_chain size*/
296 : 8 : cert_chain_size = cert_chain_header->length - sizeof(spdm_cert_chain_t) -
297 : : root_cert_hash_size;
298 : :
299 : : /*check the cert_chain*/
300 : 8 : result = libspdm_set_cert_verify_certchain(spdm_version,
301 : : cert_chain, cert_chain_size,
302 : : spdm_context->connection_info.algorithm.base_asym_algo,
303 : : spdm_context->connection_info.algorithm.pqc_asym_algo,
304 : : spdm_context->connection_info.algorithm.base_hash_algo,
305 : : set_cert_model);
306 [ - + ]: 8 : if (!result) {
307 : 0 : return libspdm_generate_error_response(spdm_context,
308 : : SPDM_ERROR_CODE_UNSPECIFIED, 0,
309 : : response_size, response);
310 : : }
311 : : #endif /*LIBSPDM_CERT_PARSE_SUPPORT*/
312 : : /* set certificate to NV*/
313 : 8 : result = libspdm_update_local_cert_chain(
314 : : spdm_context,
315 : : session_id,
316 : : slot_id,
317 : : spdm_context->connection_info.algorithm.base_hash_algo,
318 : : spdm_context->connection_info.algorithm.base_asym_algo,
319 : : spdm_context->connection_info.algorithm.pqc_asym_algo,
320 : : root_cert_hash_size,
321 : : old_local_cert_chain,
322 : : old_local_cert_chain_size,
323 : : full_cert_chain,
324 : : &full_cert_chain_size,
325 : : set_cert_model,
326 : : &need_reset, &is_busy);
327 : :
328 [ + + ]: 8 : if (!result) {
329 [ + - ]: 1 : if (is_busy) {
330 : 1 : return libspdm_generate_error_response(spdm_context,
331 : : SPDM_ERROR_CODE_BUSY, 0,
332 : : response_size, response);
333 : : } else {
334 : 0 : return libspdm_generate_error_response(spdm_context,
335 : : SPDM_ERROR_CODE_UNSPECIFIED, 0,
336 : : response_size, response);
337 : : }
338 : : }
339 : : }
340 : :
341 [ - + ]: 8 : LIBSPDM_ASSERT(*response_size >= sizeof(spdm_set_certificate_response_t));
342 : 8 : *response_size = sizeof(spdm_set_certificate_response_t);
343 : 8 : libspdm_zero_mem(response, *response_size);
344 : 8 : spdm_response = response;
345 : :
346 : : /*requires a reset to complete the SET_CERTIFICATE request*/
347 [ + + ]: 8 : if (libspdm_is_capabilities_flag_supported(
348 : : spdm_context, false, 0,
349 [ + - ]: 1 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_INSTALL_RESET_CAP) && need_reset) {
350 : 1 : spdm_context->local_context.cert_slot_reset_mask |= (1 << slot_id);
351 : :
352 : : /*the device will reset to set cert*/
353 : 1 : return libspdm_generate_error_response(spdm_context,
354 : : SPDM_ERROR_CODE_RESET_REQUIRED, 0,
355 : : response_size, response);
356 : : } else {
357 : 7 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
358 : 7 : spdm_response->header.request_response_code = SPDM_SET_CERTIFICATE_RSP;
359 : 7 : spdm_response->header.param1 = slot_id;
360 : 7 : spdm_response->header.param2 = 0;
361 : : }
362 : :
363 : 7 : return LIBSPDM_STATUS_SUCCESS;
364 : : }
365 : :
366 : : #endif /*LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP*/
|