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_responder_lib.h"
8 :
9 : #if (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP) && (LIBSPDM_SEND_GET_CERTIFICATE_SUPPORT)
10 :
11 2 : libspdm_return_t libspdm_get_encap_request_get_certificate(libspdm_context_t *spdm_context,
12 : size_t *encap_request_size,
13 : void *encap_request)
14 : {
15 : spdm_get_certificate_large_request_t *spdm_request;
16 : libspdm_return_t status;
17 : uint32_t req_msg_length;
18 : uint32_t req_msg_offset;
19 : bool use_large_cert_chain;
20 : uint32_t req_msg_header_size;
21 : uint32_t rsp_msg_header_size;
22 :
23 2 : spdm_context->encap_context.last_encap_request_size = 0;
24 :
25 2 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
26 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
27 : }
28 :
29 2 : if (!libspdm_is_capabilities_flag_supported(
30 : spdm_context, false,
31 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CERT_CAP, 0)) {
32 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
33 : }
34 :
35 2 : if ((libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_14) &&
36 0 : libspdm_is_capabilities_flag_supported(
37 : spdm_context, false,
38 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_LARGE_RESP_CAP, 0)) {
39 0 : use_large_cert_chain = true;
40 0 : spdm_context->encap_context.use_large_cert_chain = true;
41 : } else {
42 2 : use_large_cert_chain = false;
43 2 : spdm_context->encap_context.use_large_cert_chain = false;
44 : }
45 :
46 2 : if (use_large_cert_chain) {
47 0 : req_msg_header_size = sizeof(spdm_get_certificate_large_request_t);
48 0 : rsp_msg_header_size = sizeof(spdm_certificate_large_response_t);
49 : } else {
50 2 : req_msg_header_size = sizeof(spdm_get_certificate_request_t);
51 2 : rsp_msg_header_size = sizeof(spdm_certificate_response_t);
52 : }
53 :
54 2 : LIBSPDM_ASSERT(*encap_request_size >= req_msg_header_size);
55 2 : *encap_request_size = req_msg_header_size;
56 :
57 2 : spdm_request = encap_request;
58 :
59 2 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
60 2 : spdm_request->header.request_response_code = SPDM_GET_CERTIFICATE;
61 2 : spdm_request->header.param1 = spdm_context->encap_context.req_slot_id;
62 2 : spdm_request->header.param2 = 0;
63 2 : req_msg_offset = (uint32_t)spdm_context->mut_auth_cert_chain_buffer_size;
64 :
65 : /* certificate response is encapsulate in deliver encapsulated response msg */
66 2 : req_msg_length = spdm_context->local_context.capability.max_spdm_msg_size -
67 2 : sizeof(spdm_deliver_encapsulated_response_request_t) -
68 : rsp_msg_header_size;
69 :
70 2 : if (use_large_cert_chain) {
71 0 : spdm_request->header.param1 |= SPDM_GET_CERTIFICATE_REQUEST_LARGE_CERT_CHAIN;
72 0 : spdm_request->offset = 0;
73 0 : spdm_request->length = 0;
74 0 : spdm_request->large_offset = req_msg_offset;
75 0 : spdm_request->large_length = req_msg_length;
76 : } else {
77 2 : req_msg_length = LIBSPDM_MIN(req_msg_length, SPDM_MAX_CERTIFICATE_CHAIN_SIZE);
78 2 : spdm_request->offset = (uint16_t)req_msg_offset;
79 2 : spdm_request->length = (uint16_t)req_msg_length;
80 : }
81 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "request (offset 0x%x, size 0x%x):\n",
82 : req_msg_offset, req_msg_length));
83 :
84 2 : libspdm_reset_message_buffer_via_request_code(spdm_context, NULL,
85 2 : spdm_request->header.request_response_code);
86 :
87 : /* Cache data*/
88 2 : status = libspdm_append_message_mut_b(spdm_context, spdm_request, *encap_request_size);
89 2 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
90 0 : return LIBSPDM_STATUS_BUFFER_FULL;
91 : }
92 :
93 2 : libspdm_copy_mem(&spdm_context->encap_context.last_encap_request_header,
94 : sizeof(spdm_context->encap_context.last_encap_request_header),
95 2 : &spdm_request->header, sizeof(spdm_message_header_t));
96 2 : spdm_context->encap_context.last_encap_request_size = *encap_request_size;
97 :
98 2 : return LIBSPDM_STATUS_SUCCESS;
99 : }
100 :
101 12 : libspdm_return_t libspdm_process_encap_response_certificate(
102 : libspdm_context_t *spdm_context, size_t encap_response_size,
103 : const void *encap_response, bool *need_continue)
104 : {
105 : const spdm_certificate_large_response_t *spdm_response;
106 : size_t spdm_response_size;
107 : bool result;
108 : libspdm_return_t status;
109 : uint32_t request_offset;
110 : uint8_t slot_id;
111 : uint8_t *cert_chain_buffer;
112 : size_t cert_chain_buffer_size;
113 : size_t cert_chain_buffer_max_size;
114 : uint8_t cert_model;
115 : uint32_t rsp_msg_portion_length;
116 : uint32_t rsp_msg_remainder_length;
117 : bool use_large_cert_chain;
118 : uint32_t rsp_msg_header_size;
119 : uint32_t max_cert_chain_size;
120 : uint32_t req_msg_length;
121 :
122 12 : spdm_response = encap_response;
123 12 : spdm_response_size = encap_response_size;
124 :
125 12 : cert_chain_buffer = (uint8_t *)spdm_context->mut_auth_cert_chain_buffer;
126 12 : cert_chain_buffer_size = spdm_context->mut_auth_cert_chain_buffer_size;
127 12 : cert_chain_buffer_max_size = spdm_context->mut_auth_cert_chain_buffer_max_size;
128 :
129 12 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
130 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
131 : }
132 12 : if (spdm_response->header.spdm_version != libspdm_get_connection_version (spdm_context)) {
133 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
134 : }
135 12 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
136 2 : status = libspdm_handle_encap_error_response_main(
137 2 : spdm_context, spdm_response->header.param1);
138 2 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
139 2 : return status;
140 : }
141 10 : } else if (spdm_response->header.request_response_code != SPDM_CERTIFICATE) {
142 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
143 : }
144 10 : use_large_cert_chain = spdm_context->encap_context.use_large_cert_chain;
145 10 : if (use_large_cert_chain) {
146 0 : if ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_LARGE_CERT_CHAIN) == 0) {
147 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
148 : }
149 : } else {
150 10 : if ((spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_14) &&
151 0 : ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_LARGE_CERT_CHAIN) != 0)) {
152 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
153 : }
154 : }
155 :
156 10 : if (use_large_cert_chain) {
157 0 : max_cert_chain_size = SPDM_MAX_CERTIFICATE_CHAIN_SIZE_14;
158 0 : rsp_msg_header_size = sizeof(spdm_certificate_large_response_t);
159 : } else {
160 10 : max_cert_chain_size = SPDM_MAX_CERTIFICATE_CHAIN_SIZE;
161 10 : rsp_msg_header_size = sizeof(spdm_certificate_response_t);
162 : }
163 :
164 : /* certificate response is encapsulate in deliver encapsulated response msg */
165 10 : req_msg_length = spdm_context->local_context.capability.max_spdm_msg_size -
166 10 : sizeof(spdm_deliver_encapsulated_response_request_t) -
167 : rsp_msg_header_size;
168 :
169 10 : if (!use_large_cert_chain) {
170 10 : req_msg_length = LIBSPDM_MIN(req_msg_length, SPDM_MAX_CERTIFICATE_CHAIN_SIZE);
171 : }
172 :
173 10 : if (encap_response_size < rsp_msg_header_size) {
174 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
175 : }
176 10 : if (use_large_cert_chain) {
177 0 : rsp_msg_portion_length = spdm_response->large_portion_length;
178 0 : rsp_msg_remainder_length = spdm_response->large_remainder_length;
179 : } else {
180 10 : rsp_msg_portion_length = spdm_response->portion_length;
181 10 : rsp_msg_remainder_length = spdm_response->remainder_length;
182 : }
183 :
184 10 : if ((rsp_msg_portion_length > req_msg_length) ||
185 : (rsp_msg_portion_length == 0)) {
186 2 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
187 : }
188 :
189 8 : request_offset = (uint32_t)cert_chain_buffer_size;
190 :
191 8 : if (rsp_msg_portion_length > max_cert_chain_size - request_offset) {
192 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
193 : }
194 8 : if (rsp_msg_remainder_length > max_cert_chain_size - request_offset - rsp_msg_portion_length) {
195 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
196 : }
197 8 : if (request_offset == 0) {
198 8 : spdm_context->encap_context.cert_chain_total_len = rsp_msg_portion_length +
199 : rsp_msg_remainder_length;
200 0 : } else if (spdm_context->encap_context.cert_chain_total_len !=
201 0 : request_offset + rsp_msg_portion_length + rsp_msg_remainder_length) {
202 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
203 : }
204 8 : slot_id = spdm_context->encap_context.req_slot_id;
205 8 : if ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_SLOT_ID_MASK) != slot_id) {
206 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
207 : }
208 8 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
209 6 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "cert_info - 0x%02x\n",
210 : spdm_response->header.param2));
211 6 : cert_model = spdm_response->header.param2 &
212 : SPDM_CERTIFICATE_RESPONSE_ATTRIBUTES_CERTIFICATE_INFO_MASK;
213 6 : if (spdm_context->connection_info.multi_key_conn_req) {
214 5 : if (cert_model > SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT) {
215 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
216 : }
217 5 : if ((slot_id == 0) &&
218 : (cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT)) {
219 1 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
220 : }
221 4 : if ((cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) &&
222 1 : (spdm_response->portion_length != 0)) {
223 1 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
224 : }
225 : } else {
226 1 : if (cert_model != SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) {
227 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
228 : }
229 : }
230 4 : if (spdm_context->connection_info.peer_cert_info[slot_id] ==
231 : SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) {
232 4 : spdm_context->connection_info.peer_cert_info[slot_id] = cert_model;
233 0 : } else if (spdm_context->connection_info.peer_cert_info[slot_id] != cert_model) {
234 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
235 : }
236 : }
237 :
238 6 : if (spdm_response_size < rsp_msg_header_size + rsp_msg_portion_length) {
239 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
240 : }
241 6 : spdm_response_size = rsp_msg_header_size + rsp_msg_portion_length;
242 :
243 : /* Cache data*/
244 :
245 6 : status = libspdm_append_message_mut_b(spdm_context, spdm_response, spdm_response_size);
246 6 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
247 0 : return LIBSPDM_STATUS_BUFFER_FULL;
248 : }
249 :
250 6 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Certificate (offset 0x%x, size 0x%x):\n",
251 : request_offset, rsp_msg_portion_length));
252 6 : LIBSPDM_INTERNAL_DUMP_HEX((const uint8_t *)spdm_response + rsp_msg_header_size,
253 : rsp_msg_portion_length);
254 :
255 6 : if (cert_chain_buffer_size + rsp_msg_portion_length > cert_chain_buffer_max_size) {
256 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "cert_chain_buffer full\n"));
257 0 : return LIBSPDM_STATUS_BUFFER_FULL;
258 : }
259 :
260 6 : libspdm_copy_mem(cert_chain_buffer + cert_chain_buffer_size,
261 : cert_chain_buffer_max_size - cert_chain_buffer_size,
262 : (const uint8_t *)spdm_response + rsp_msg_header_size,
263 : rsp_msg_portion_length);
264 :
265 6 : cert_chain_buffer_size += rsp_msg_portion_length;
266 6 : spdm_context->mut_auth_cert_chain_buffer_size = cert_chain_buffer_size;
267 :
268 6 : if (rsp_msg_remainder_length != 0) {
269 6 : *need_continue = true;
270 :
271 6 : return LIBSPDM_STATUS_SUCCESS;
272 : }
273 :
274 0 : *need_continue = false;
275 :
276 0 : if (spdm_context->local_context.verify_peer_spdm_cert_chain != NULL) {
277 0 : result = spdm_context->local_context.verify_peer_spdm_cert_chain (
278 0 : spdm_context, spdm_context->encap_context.req_slot_id,
279 : cert_chain_buffer_size, cert_chain_buffer, NULL, NULL);
280 0 : if (!result) {
281 0 : return LIBSPDM_STATUS_VERIF_FAIL;
282 : }
283 : } else {
284 0 : result = libspdm_verify_peer_cert_chain_buffer_integrity(
285 : spdm_context, cert_chain_buffer, cert_chain_buffer_size);
286 0 : if (!result) {
287 0 : return LIBSPDM_STATUS_VERIF_FAIL;
288 : }
289 :
290 : /*verify peer cert chain authority*/
291 0 : result = libspdm_verify_peer_cert_chain_buffer_authority(
292 : spdm_context, cert_chain_buffer, cert_chain_buffer_size, NULL, NULL);
293 0 : if (!result) {
294 0 : status = LIBSPDM_STATUS_VERIF_NO_AUTHORITY;
295 : }
296 : }
297 :
298 0 : spdm_context->connection_info.peer_used_cert_chain_slot_id =
299 0 : spdm_context->encap_context.req_slot_id;
300 0 : slot_id = spdm_context->encap_context.req_slot_id;
301 0 : LIBSPDM_ASSERT(slot_id < SPDM_MAX_SLOT_COUNT);
302 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
303 : spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_size =
304 : cert_chain_buffer_size;
305 :
306 : libspdm_copy_mem(spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer,
307 : sizeof(spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer),
308 : cert_chain_buffer, cert_chain_buffer_size);
309 : #else
310 0 : result = libspdm_hash_all(
311 : spdm_context->connection_info.algorithm.base_hash_algo,
312 : cert_chain_buffer, cert_chain_buffer_size,
313 0 : spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_hash);
314 0 : if (!result) {
315 0 : return LIBSPDM_STATUS_CRYPTO_ERROR;
316 : }
317 0 : spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_hash_size =
318 0 : libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
319 :
320 0 : if (spdm_context->connection_info.algorithm.req_pqc_asym_alg != 0) {
321 0 : result = libspdm_get_pqc_leaf_cert_public_key_from_cert_chain(
322 : spdm_context->connection_info.algorithm.base_hash_algo,
323 : spdm_context->connection_info.algorithm.req_pqc_asym_alg,
324 : cert_chain_buffer, cert_chain_buffer_size,
325 0 : &spdm_context->connection_info.peer_used_cert_chain[slot_id].leaf_cert_public_key);
326 : } else {
327 0 : result = libspdm_get_leaf_cert_public_key_from_cert_chain(
328 : spdm_context->connection_info.algorithm.base_hash_algo,
329 0 : spdm_context->connection_info.algorithm.req_base_asym_alg,
330 : cert_chain_buffer, cert_chain_buffer_size,
331 0 : &spdm_context->connection_info.peer_used_cert_chain[slot_id].leaf_cert_public_key);
332 : }
333 0 : if (!result) {
334 0 : return LIBSPDM_STATUS_INVALID_CERT;
335 : }
336 : #endif
337 0 : if (status != LIBSPDM_STATUS_VERIF_NO_AUTHORITY) {
338 0 : return LIBSPDM_STATUS_SUCCESS;
339 : } else {
340 0 : return LIBSPDM_STATUS_VERIF_NO_AUTHORITY;
341 : }
342 : }
343 :
344 : #endif /* (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP) && (...) */
|