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