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_requester_lib.h"
8 : :
9 : : #if LIBSPDM_SEND_GET_CERTIFICATE_SUPPORT
10 : :
11 : : /**
12 : : * This function sends GET_CERTIFICATE and receives CERTIFICATE.
13 : : *
14 : : * This function verify the integrity of the certificate chain.
15 : : * root_hash -> Root certificate -> Intermediate certificate -> Leaf certificate.
16 : : *
17 : : * If the peer root certificate hash is deployed,
18 : : * this function also verifies the digest with the root hash in the certificate chain.
19 : : *
20 : : * @param spdm_context A pointer to the SPDM context.
21 : : * @param slot_id The number of slot for the certificate chain.
22 : : * @param cert_chain_size On input, indicate the size in bytes of the destination buffer to store
23 : : * the certificate chain.
24 : : * On output, indicate the size in bytes of the certificate chain.
25 : : * @param cert_chain A pointer to a destination buffer to store the certificate chain.
26 : : * @param trust_anchor A buffer to hold the trust_anchor which is used to validate the peer
27 : : * certificate, if not NULL.
28 : : * @param trust_anchor_size A buffer to hold the trust_anchor_size, if not NULL.
29 : : *
30 : : * @retval LIBSPDM_STATUS_SUCCESS
31 : : * GET_CERTIFICATE was sent and CERTIFICATE was received.
32 : : * @retval LIBSPDM_STATUS_INVALID_STATE_LOCAL
33 : : * Cannot send GET_CERTIFICATE due to Requester's state.
34 : : * @retval LIBSPDM_STATUS_UNSUPPORTED_CAP
35 : : * Cannot send GET_CERTIFICATE because the Requester's and/or Responder's CERT_CAP = 0.
36 : : * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE
37 : : * The size of the CERTIFICATE response is invalid.
38 : : * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD
39 : : * The CERTIFICATE response contains one or more invalid fields.
40 : : * @retval LIBSPDM_STATUS_ERROR_PEER
41 : : * The Responder returned an unexpected error.
42 : : * @retval LIBSPDM_STATUS_BUSY_PEER
43 : : * The Responder continually returned Busy error messages.
44 : : * @retval LIBSPDM_STATUS_RESYNCH_PEER
45 : : * The Responder returned a RequestResynch error message.
46 : : * @retval LIBSPDM_STATUS_BUFFER_FULL
47 : : * The buffer used to store transcripts is exhausted.
48 : : * @retval LIBSPDM_STATUS_VERIF_FAIL
49 : : * Verification of the certificate chain failed.
50 : : * @retval LIBSPDM_STATUS_INVALID_CERT
51 : : * The certificate is unable to be parsed or contains invalid field values.
52 : : * @retval LIBSPDM_STATUS_CRYPTO_ERROR
53 : : * A generic cryptography error occurred.
54 : : **/
55 : 88 : static libspdm_return_t libspdm_try_get_large_certificate(libspdm_context_t *spdm_context,
56 : : const uint32_t *session_id,
57 : : uint8_t slot_id,
58 : : uint32_t length,
59 : : size_t *cert_chain_size,
60 : : void *cert_chain,
61 : : const void **trust_anchor,
62 : : size_t *trust_anchor_size,
63 : : bool slot_storage_size_requested,
64 : : uint32_t *slot_storage_size)
65 : : {
66 : : bool result;
67 : : libspdm_return_t status;
68 : : spdm_get_certificate_large_request_t *spdm_request;
69 : : size_t spdm_request_size;
70 : : spdm_certificate_large_response_t *spdm_response;
71 : : size_t spdm_response_size;
72 : : uint32_t total_responder_cert_chain_buffer_length;
73 : : size_t cert_chain_capacity;
74 : : size_t cert_chain_size_internal;
75 : : uint32_t remainder_length;
76 : : uint8_t *message;
77 : : size_t message_size;
78 : : size_t transport_header_size;
79 : : libspdm_session_info_t *session_info;
80 : : libspdm_session_state_t session_state;
81 : : bool chunk_enabled;
82 : : uint8_t cert_model;
83 : : uint32_t req_msg_length;
84 : : uint32_t req_msg_offset;
85 : : uint32_t rsp_msg_portion_length;
86 : : uint32_t rsp_msg_remainder_length;
87 : : bool use_large_cert_chain;
88 : : uint32_t req_msg_header_size;
89 : : uint32_t rsp_msg_header_size;
90 : : uint32_t max_cert_chain_size;
91 : :
92 : : /* -=[Check Parameters Phase]=- */
93 [ - + ]: 88 : LIBSPDM_ASSERT(slot_id < SPDM_MAX_SLOT_COUNT);
94 [ + + ]: 88 : if (slot_storage_size_requested){
95 [ - + ]: 6 : LIBSPDM_ASSERT(slot_storage_size != NULL);
96 : : } else {
97 [ - + ]: 82 : LIBSPDM_ASSERT(cert_chain_size != NULL);
98 [ - + ]: 82 : LIBSPDM_ASSERT(*cert_chain_size > 0);
99 [ - + ]: 82 : LIBSPDM_ASSERT(cert_chain != NULL);
100 : : }
101 : :
102 [ + + + - ]: 89 : if ((length > SPDM_MAX_CERTIFICATE_CHAIN_SIZE) &&
103 : 1 : (libspdm_get_connection_version (spdm_context) < SPDM_MESSAGE_VERSION_14)) {
104 : 1 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
105 : : }
106 : :
107 [ + + + + ]: 89 : if ((length == SPDM_MAX_CERTIFICATE_CHAIN_SIZE) &&
108 : 2 : (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_14)) {
109 : : /* support compatibility */
110 : 1 : length = SPDM_MAX_CERTIFICATE_CHAIN_SIZE_14;
111 : : }
112 : :
113 [ + + + + ]: 90 : if ((libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_14) &&
114 : 3 : libspdm_is_capabilities_flag_supported(
115 : : spdm_context, true, 0,
116 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_LARGE_RESP_CAP)) {
117 : 2 : use_large_cert_chain = true;
118 : : } else {
119 : 85 : use_large_cert_chain = false;
120 : : }
121 : :
122 [ + + ]: 87 : if (slot_storage_size_requested){
123 [ + + ]: 6 : if (libspdm_get_connection_version (spdm_context) < SPDM_MESSAGE_VERSION_13) {
124 : 1 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
125 : : }
126 : :
127 [ + + ]: 5 : if (!libspdm_is_capabilities_flag_supported(
128 : : spdm_context, true, 0,
129 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_SET_CERT_CAP)) {
130 : 1 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
131 : : }
132 : : }
133 : :
134 [ + + ]: 85 : if (use_large_cert_chain) {
135 : 2 : max_cert_chain_size = SPDM_MAX_CERTIFICATE_CHAIN_SIZE_14;
136 : 2 : req_msg_header_size = sizeof(spdm_get_certificate_large_request_t);
137 : 2 : rsp_msg_header_size = sizeof(spdm_certificate_large_response_t);
138 : : } else {
139 : 83 : max_cert_chain_size = SPDM_MAX_CERTIFICATE_CHAIN_SIZE;
140 : 83 : req_msg_header_size = sizeof(spdm_get_certificate_request_t);
141 : 83 : rsp_msg_header_size = sizeof(spdm_certificate_response_t);
142 : : }
143 : :
144 : : /* use default max buffer length */
145 [ + + ]: 85 : if (length == 0) {
146 : 82 : length = spdm_context->local_context.capability.max_spdm_msg_size - rsp_msg_header_size;
147 : :
148 [ + + ]: 82 : if (!use_large_cert_chain) {
149 : 81 : length = LIBSPDM_MIN(length, SPDM_MAX_CERTIFICATE_CHAIN_SIZE);
150 : : }
151 : : }
152 : :
153 : : /* -=[Verify State Phase]=- */
154 [ + + ]: 85 : if (!libspdm_is_capabilities_flag_supported(
155 : : spdm_context, true, 0,
156 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP)) {
157 : 1 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
158 : : }
159 [ + + ]: 84 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
160 : 1 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
161 : : }
162 : :
163 : 83 : session_info = NULL;
164 [ + + ]: 83 : if (session_id != NULL) {
165 : 3 : session_info = libspdm_get_session_info_via_session_id(spdm_context, *session_id);
166 [ - + ]: 3 : if (session_info == NULL) {
167 : 0 : LIBSPDM_ASSERT(false);
168 : 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
169 : : }
170 : 3 : session_state = libspdm_secured_message_get_session_state(
171 : : session_info->secured_message_context);
172 [ + + ]: 3 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
173 : 1 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
174 : : }
175 : : }
176 : :
177 : 82 : libspdm_reset_message_buffer_via_request_code(spdm_context, session_info, SPDM_GET_CERTIFICATE);
178 : :
179 : : chunk_enabled =
180 : 82 : libspdm_is_capabilities_flag_supported(spdm_context, true,
181 : : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP,
182 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP);
183 : :
184 : 82 : remainder_length = 0;
185 : 82 : total_responder_cert_chain_buffer_length = 0;
186 [ + + ]: 82 : if (!slot_storage_size_requested){
187 : 78 : cert_chain_capacity = *cert_chain_size;
188 : : }
189 : 82 : cert_chain_size_internal = 0;
190 : :
191 : 82 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
192 : :
193 : : do {
194 : : /* -=[Construct Request Phase]=- */
195 : 1565 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
196 [ + + ]: 1565 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
197 : 1 : return status;
198 : : }
199 [ - + ]: 1564 : LIBSPDM_ASSERT (message_size >= transport_header_size +
200 : : spdm_context->local_context.capability.transport_tail_size);
201 : 1564 : spdm_request = (void *)(message + transport_header_size);
202 : 1564 : spdm_request_size = message_size - transport_header_size -
203 : 1564 : spdm_context->local_context.capability.transport_tail_size;
204 : :
205 [ - + ]: 1564 : LIBSPDM_ASSERT (spdm_request_size >= req_msg_header_size);
206 : 1564 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
207 : 1564 : spdm_request->header.request_response_code = SPDM_GET_CERTIFICATE;
208 : 1564 : spdm_request->header.param1 = slot_id;
209 : 1564 : spdm_request->header.param2 = 0;
210 [ + + ]: 1564 : if (slot_storage_size_requested) {
211 : 4 : spdm_request->header.param2 |= SPDM_GET_CERTIFICATE_REQUEST_ATTRIBUTES_SLOT_SIZE_REQUESTED;
212 : 4 : req_msg_length = 0;
213 : 4 : req_msg_offset = 0;
214 : : } else {
215 : 1560 : req_msg_offset = (uint32_t)cert_chain_size_internal;
216 [ + + ]: 1560 : if (req_msg_offset == 0) {
217 : 77 : req_msg_length = length;
218 : : } else {
219 : 1483 : req_msg_length = LIBSPDM_MIN(length, remainder_length);
220 : : }
221 : : }
222 [ + + ]: 1564 : if (use_large_cert_chain) {
223 : 2 : spdm_request->header.param1 |= SPDM_GET_CERTIFICATE_REQUEST_LARGE_CERT_CHAIN;
224 : 2 : spdm_request->offset = 0;
225 : 2 : spdm_request->length = 0;
226 : 2 : spdm_request->large_offset = req_msg_offset;
227 : 2 : spdm_request->large_length = req_msg_length;
228 : : } else {
229 : 1562 : spdm_request->offset = (uint16_t)req_msg_offset;
230 : 1562 : spdm_request->length = (uint16_t)req_msg_length;
231 : : }
232 : 1564 : spdm_request_size = req_msg_header_size;
233 : 1564 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "request (offset 0x%x, size 0x%x):\n",
234 : : req_msg_offset,req_msg_length));
235 : :
236 : : /* -=[Send Request Phase]=- */
237 : : status =
238 : 1564 : libspdm_send_spdm_request(spdm_context, session_id, spdm_request_size, spdm_request);
239 [ + + ]: 1564 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
240 : 1 : libspdm_release_sender_buffer (spdm_context);
241 : 1 : status = LIBSPDM_STATUS_SEND_FAIL;
242 : 1 : goto done;
243 : : }
244 : 1563 : libspdm_release_sender_buffer (spdm_context);
245 : 1563 : spdm_request = (void *)spdm_context->last_spdm_request;
246 : :
247 : : /* -=[Receive Response Phase]=- */
248 : 1563 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
249 [ + + ]: 1563 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
250 : 1 : return status;
251 : : }
252 [ - + ]: 1562 : LIBSPDM_ASSERT (message_size >= transport_header_size);
253 : 1562 : spdm_response = (void *)(message);
254 : 1562 : spdm_response_size = message_size;
255 : :
256 : 1562 : status = libspdm_receive_spdm_response(spdm_context, session_id,
257 : : &spdm_response_size,
258 : : (void **)&spdm_response);
259 [ + + ]: 1562 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
260 : 2 : libspdm_release_receiver_buffer (spdm_context);
261 : 2 : status = LIBSPDM_STATUS_RECEIVE_FAIL;
262 : 2 : goto done;
263 : : }
264 : :
265 : : /* -=[Validate Response Phase]=- */
266 [ - + ]: 1560 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
267 : 0 : libspdm_release_receiver_buffer (spdm_context);
268 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
269 : 0 : goto done;
270 : : }
271 [ + + ]: 1560 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
272 : 26 : status = libspdm_handle_error_response_main(
273 : : spdm_context, session_id,
274 : : &spdm_response_size,
275 : : (void **)&spdm_response, SPDM_GET_CERTIFICATE,
276 : : SPDM_CERTIFICATE);
277 [ + + ]: 26 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
278 : 25 : libspdm_release_receiver_buffer (spdm_context);
279 : 25 : goto done;
280 : : }
281 [ + + ]: 1534 : } else if (spdm_response->header.request_response_code != SPDM_CERTIFICATE) {
282 : 1 : libspdm_release_receiver_buffer (spdm_context);
283 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
284 : 1 : goto done;
285 : : }
286 [ + + ]: 1534 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
287 : 1 : libspdm_release_receiver_buffer (spdm_context);
288 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
289 : 1 : goto done;
290 : : }
291 [ + + ]: 1533 : if (spdm_response_size < rsp_msg_header_size) {
292 : 1 : libspdm_release_receiver_buffer (spdm_context);
293 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
294 : 1 : goto done;
295 : : }
296 [ + + ]: 1532 : if (use_large_cert_chain) {
297 [ + + ]: 2 : if ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_LARGE_CERT_CHAIN) == 0) {
298 : 1 : libspdm_release_receiver_buffer (spdm_context);
299 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
300 : 1 : goto done;
301 : : }
302 : : } else {
303 [ + + ]: 1530 : if ((spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_14) &&
304 [ + - ]: 1 : ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_LARGE_CERT_CHAIN) != 0)) {
305 : 1 : libspdm_release_receiver_buffer (spdm_context);
306 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
307 : 1 : goto done;
308 : : }
309 : : }
310 [ + + ]: 1530 : if (use_large_cert_chain) {
311 : 1 : rsp_msg_portion_length = spdm_response->large_portion_length;
312 : 1 : rsp_msg_remainder_length = spdm_response->large_remainder_length;
313 : : } else {
314 : 1529 : rsp_msg_portion_length = spdm_response->portion_length;
315 : 1529 : rsp_msg_remainder_length = spdm_response->remainder_length;
316 : : }
317 : :
318 [ + + ]: 1530 : if (slot_storage_size_requested) {
319 [ + + ]: 2 : if (rsp_msg_portion_length != 0) {
320 : 1 : libspdm_release_receiver_buffer (spdm_context);
321 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
322 : 1 : goto done;
323 : : }
324 : : } else {
325 [ + + + + ]: 1528 : if ((rsp_msg_portion_length > req_msg_length) ||
326 : : (rsp_msg_portion_length == 0)) {
327 : 3 : libspdm_release_receiver_buffer (spdm_context);
328 : 3 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
329 : 3 : goto done;
330 : : }
331 [ + + ]: 1525 : if ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_SLOT_ID_MASK) != slot_id) {
332 : 1 : libspdm_release_receiver_buffer (spdm_context);
333 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
334 : 1 : goto done;
335 : : }
336 [ + + ]: 1524 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
337 : 14 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "cert_info - 0x%02x\n",
338 : : spdm_response->header.param2));
339 : 14 : cert_model = spdm_response->header.param2 &
340 : : SPDM_CERTIFICATE_RESPONSE_ATTRIBUTES_CERTIFICATE_INFO_MASK;
341 [ + + ]: 14 : if (spdm_context->connection_info.multi_key_conn_rsp) {
342 [ + + ]: 10 : if (cert_model > SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT) {
343 : 1 : libspdm_release_receiver_buffer (spdm_context);
344 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
345 : 1 : goto done;
346 : : }
347 [ + + + + ]: 9 : if ((slot_id == 0) &&
348 : : (cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT)) {
349 : 1 : libspdm_release_receiver_buffer (spdm_context);
350 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
351 : 1 : goto done;
352 : : }
353 [ + + + - ]: 8 : if ((cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) &&
354 : : (rsp_msg_portion_length != 0)) {
355 : 1 : libspdm_release_receiver_buffer (spdm_context);
356 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
357 : 1 : goto done;
358 : : }
359 : : } else {
360 [ + + ]: 4 : if (cert_model != SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) {
361 : 1 : libspdm_release_receiver_buffer (spdm_context);
362 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
363 : 1 : goto done;
364 : : }
365 : : }
366 [ + + ]: 10 : if (spdm_context->connection_info.peer_cert_info[slot_id] ==
367 : : SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) {
368 : 6 : spdm_context->connection_info.peer_cert_info[slot_id] = cert_model;
369 [ + + ]: 4 : } else if (spdm_context->connection_info.peer_cert_info[slot_id] != cert_model) {
370 : 1 : libspdm_release_receiver_buffer (spdm_context);
371 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
372 : 1 : goto done;
373 : : }
374 : : }
375 [ + + ]: 1519 : if (spdm_response_size < rsp_msg_header_size +
376 : : rsp_msg_portion_length) {
377 : 1 : libspdm_release_receiver_buffer (spdm_context);
378 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
379 : 1 : goto done;
380 : : }
381 [ - + ]: 1518 : if (rsp_msg_portion_length > max_cert_chain_size - req_msg_offset) {
382 : 0 : libspdm_release_receiver_buffer (spdm_context);
383 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
384 : 0 : goto done;
385 : : }
386 [ + + ]: 1518 : if (rsp_msg_remainder_length > max_cert_chain_size - req_msg_offset -
387 : : rsp_msg_portion_length) {
388 : 1 : libspdm_release_receiver_buffer (spdm_context);
389 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
390 : 1 : goto done;
391 : : }
392 [ + + ]: 1517 : if (req_msg_offset == 0) {
393 : 35 : total_responder_cert_chain_buffer_length = rsp_msg_portion_length +
394 : : rsp_msg_remainder_length;
395 [ + + ]: 35 : if (total_responder_cert_chain_buffer_length > cert_chain_capacity) {
396 : 1 : libspdm_release_receiver_buffer (spdm_context);
397 : 1 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
398 : 1 : goto done;
399 : : }
400 [ + + ]: 1482 : } else if (req_msg_offset + rsp_msg_portion_length +
401 : : rsp_msg_remainder_length != total_responder_cert_chain_buffer_length) {
402 : 1 : libspdm_release_receiver_buffer (spdm_context);
403 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
404 : 1 : goto done;
405 : : }
406 [ + + + - : 1515 : if (chunk_enabled && (req_msg_offset == 0) && (req_msg_length == max_cert_chain_size) &&
+ + + - ]
407 : : (rsp_msg_remainder_length != 0)) {
408 : 1 : libspdm_release_receiver_buffer (spdm_context);
409 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
410 : 1 : goto done;
411 : : }
412 : : }
413 : :
414 : : /* -=[Process Response Phase]=- */
415 : 1515 : remainder_length = rsp_msg_remainder_length;
416 : 1515 : spdm_response_size = rsp_msg_header_size + rsp_msg_portion_length;
417 : :
418 [ + + ]: 1515 : if (session_id == NULL) {
419 : 1513 : status = libspdm_append_message_b(spdm_context, spdm_request, spdm_request_size);
420 [ - + ]: 1513 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
421 : 0 : libspdm_release_receiver_buffer (spdm_context);
422 : 0 : goto done;
423 : : }
424 : 1513 : status = libspdm_append_message_b(spdm_context, spdm_response, spdm_response_size);
425 [ - + ]: 1513 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
426 : 0 : libspdm_release_receiver_buffer (spdm_context);
427 : 0 : goto done;
428 : : }
429 : : }
430 : :
431 [ + + ]: 1515 : if (slot_storage_size_requested) {
432 : 1 : *slot_storage_size = remainder_length;
433 : 1 : libspdm_release_receiver_buffer (spdm_context);
434 : 1 : status = LIBSPDM_STATUS_SUCCESS;
435 : 1 : goto done;
436 : : }
437 : :
438 : 1514 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Certificate (offset 0x%x, size 0x%x):\n",
439 : : req_msg_offset, rsp_msg_portion_length));
440 : 1514 : LIBSPDM_INTERNAL_DUMP_HEX((uint8_t *)spdm_response + rsp_msg_header_size,
441 : : rsp_msg_portion_length);
442 : :
443 : 1514 : libspdm_copy_mem((uint8_t *)cert_chain + cert_chain_size_internal,
444 : : cert_chain_capacity - cert_chain_size_internal,
445 : 1514 : (uint8_t *)spdm_response + rsp_msg_header_size,
446 : : rsp_msg_portion_length);
447 : :
448 : 1514 : cert_chain_size_internal += rsp_msg_portion_length;
449 : :
450 [ + + ]: 1514 : if (spdm_context->connection_info.connection_state <
451 : : LIBSPDM_CONNECTION_STATE_AFTER_CERTIFICATE) {
452 : 29 : spdm_context->connection_info.connection_state =
453 : : LIBSPDM_CONNECTION_STATE_AFTER_CERTIFICATE;
454 : : }
455 : :
456 : : /* -=[Log Message Phase]=- */
457 : : #if LIBSPDM_ENABLE_MSG_LOG
458 : 1514 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
459 : : #endif /* LIBSPDM_ENABLE_MSG_LOG */
460 : :
461 : 1514 : libspdm_release_receiver_buffer (spdm_context);
462 [ + + ]: 1514 : } while (remainder_length != 0);
463 : :
464 : 31 : *cert_chain_size = cert_chain_size_internal;
465 [ - + ]: 31 : LIBSPDM_ASSERT(*cert_chain_size <= SPDM_MAX_CERTIFICATE_CHAIN_SIZE_14);
466 : :
467 [ + + ]: 31 : if (spdm_context->local_context.verify_peer_spdm_cert_chain != NULL) {
468 : 3 : result = spdm_context->local_context.verify_peer_spdm_cert_chain (
469 : : spdm_context, slot_id, cert_chain_size_internal, cert_chain,
470 : : trust_anchor, trust_anchor_size);
471 [ + + ]: 3 : if (!result) {
472 : 1 : status = LIBSPDM_STATUS_VERIF_FAIL;
473 : 1 : goto done;
474 : : }
475 : : } else {
476 : 28 : result = libspdm_verify_peer_cert_chain_buffer_integrity(
477 : : spdm_context, cert_chain, cert_chain_size_internal);
478 [ + + ]: 28 : if (!result) {
479 : 7 : status = LIBSPDM_STATUS_VERIF_FAIL;
480 : 7 : goto done;
481 : : }
482 : :
483 : : /*verify peer cert chain authority*/
484 : 21 : result = libspdm_verify_peer_cert_chain_buffer_authority(
485 : : spdm_context, cert_chain,cert_chain_size_internal,
486 : : trust_anchor, trust_anchor_size);
487 [ + + ]: 21 : if (!result) {
488 : 2 : status = LIBSPDM_STATUS_VERIF_NO_AUTHORITY;
489 : : }
490 : : }
491 : :
492 : : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
493 : : spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_size =
494 : : cert_chain_size_internal;
495 : : libspdm_copy_mem(spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer,
496 : : sizeof(spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer),
497 : : cert_chain, cert_chain_size_internal);
498 : : #else
499 : 23 : result = libspdm_hash_all(
500 : : spdm_context->connection_info.algorithm.base_hash_algo,
501 : : cert_chain, cert_chain_size_internal,
502 : 23 : spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_hash);
503 [ - + ]: 23 : if (!result) {
504 : 0 : status = LIBSPDM_STATUS_CRYPTO_ERROR;
505 : 0 : goto done;
506 : : }
507 : :
508 : 46 : spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_hash_size =
509 : 23 : libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
510 : :
511 : 23 : libspdm_free_peer_leaf_cert_public_key(spdm_context, slot_id);
512 [ - + ]: 23 : if (spdm_context->connection_info.algorithm.pqc_asym_algo != 0) {
513 : 0 : result = libspdm_get_pqc_leaf_cert_public_key_from_cert_chain(
514 : : spdm_context->connection_info.algorithm.base_hash_algo,
515 : : spdm_context->connection_info.algorithm.pqc_asym_algo,
516 : : cert_chain, cert_chain_size_internal,
517 : 0 : &spdm_context->connection_info.peer_used_cert_chain[slot_id].leaf_cert_public_key);
518 : : } else {
519 : 23 : result = libspdm_get_leaf_cert_public_key_from_cert_chain(
520 : : spdm_context->connection_info.algorithm.base_hash_algo,
521 : : spdm_context->connection_info.algorithm.base_asym_algo,
522 : : cert_chain, cert_chain_size_internal,
523 : 23 : &spdm_context->connection_info.peer_used_cert_chain[slot_id].leaf_cert_public_key);
524 : : }
525 [ + + ]: 23 : if (!result) {
526 : 2 : status = LIBSPDM_STATUS_INVALID_CERT;
527 : 2 : goto done;
528 : : }
529 : : #endif
530 : :
531 [ + + ]: 21 : if (status != LIBSPDM_STATUS_VERIF_NO_AUTHORITY) {
532 : 19 : status = LIBSPDM_STATUS_SUCCESS;
533 : : }
534 : 2 : done:
535 : 80 : return status;
536 : : }
537 : :
538 : 81 : libspdm_return_t libspdm_get_certificate_ex(void *spdm_context, const uint32_t *session_id,
539 : : uint8_t slot_id,
540 : : uint32_t length,
541 : : size_t *cert_chain_size,
542 : : void *cert_chain,
543 : : const void **trust_anchor,
544 : : size_t *trust_anchor_size)
545 : : {
546 : : libspdm_context_t *context;
547 : : size_t retry;
548 : : uint64_t retry_delay_time;
549 : : libspdm_return_t status;
550 : :
551 : 81 : context = spdm_context;
552 : 81 : context->crypto_request = true;
553 : 81 : retry = context->retry_times;
554 : 81 : retry_delay_time = context->retry_delay_time;
555 : : do {
556 : 82 : status = libspdm_try_get_large_certificate(context, session_id, slot_id, length,
557 : : cert_chain_size, cert_chain, trust_anchor,
558 : : trust_anchor_size, false, NULL);
559 [ + + ]: 82 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
560 : 80 : return status;
561 : : }
562 : :
563 : 2 : libspdm_sleep(retry_delay_time);
564 [ + + ]: 2 : } while (retry-- != 0);
565 : :
566 : 1 : return status;
567 : : }
568 : :
569 : 74 : libspdm_return_t libspdm_get_certificate(void *spdm_context, const uint32_t *session_id,
570 : : uint8_t slot_id,
571 : : size_t *cert_chain_size,
572 : : void *cert_chain)
573 : : {
574 : 74 : return libspdm_get_certificate_ex(spdm_context, session_id, slot_id, 0,
575 : : cert_chain_size, cert_chain,
576 : : NULL, NULL);
577 : : }
578 : :
579 : 5 : libspdm_return_t libspdm_get_slot_storage_size(void *spdm_context, const uint32_t *session_id,
580 : : uint8_t slot_id, uint32_t *slot_storage_size)
581 : : {
582 : : libspdm_context_t *context;
583 : : size_t retry;
584 : : uint64_t retry_delay_time;
585 : : libspdm_return_t status;
586 : :
587 : 5 : context = spdm_context;
588 : 5 : context->crypto_request = true;
589 : 5 : retry = context->retry_times;
590 : 5 : retry_delay_time = context->retry_delay_time;
591 : : do {
592 : 6 : status = libspdm_try_get_large_certificate(context, session_id, slot_id, 0,
593 : : NULL, NULL, NULL, NULL,
594 : : true, slot_storage_size);
595 [ + + ]: 6 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
596 : 4 : return status;
597 : : }
598 : :
599 : 2 : libspdm_sleep(retry_delay_time);
600 [ + + ]: 2 : } while (retry-- != 0);
601 : :
602 : 1 : return status;
603 : : }
604 : :
605 : : #endif /* LIBSPDM_SEND_GET_CERTIFICATE_SUPPORT */
|