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 : : #pragma pack(1)
12 : : typedef struct {
13 : : spdm_message_header_t header;
14 : : uint8_t digest[LIBSPDM_MAX_HASH_SIZE * SPDM_MAX_SLOT_COUNT];
15 : : spdm_key_pair_id_t key_pair_id[SPDM_MAX_SLOT_COUNT];
16 : : spdm_certificate_info_t cert_info[SPDM_MAX_SLOT_COUNT];
17 : : spdm_key_usage_bit_mask_t key_usage_bit_mask[SPDM_MAX_SLOT_COUNT];
18 : : } libspdm_digests_response_max_t;
19 : : #pragma pack()
20 : :
21 : : /**
22 : : * This function sends GET_DIGESTS and receives DIGESTS *
23 : : *
24 : : * @param spdm_context A pointer to the SPDM context.
25 : : * @param slot_mask Bitmask of the slots that contain certificates.
26 : : * @param total_digest_buffer A pointer to a destination buffer to store the digests.
27 : : *
28 : : * @retval LIBSPDM_STATUS_SUCCESS
29 : : * GET_DIGESTS was sent and DIGESTS was received.
30 : : * @retval LIBSPDM_STATUS_INVALID_STATE_LOCAL
31 : : * Cannot send GET_DIGESTS due to Requester's state.
32 : : * @retval LIBSPDM_STATUS_UNSUPPORTED_CAP
33 : : * Cannot send GET_DIGESTS because the Requester's and/or Responder's CERT_CAP = 0.
34 : : * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE
35 : : * The size of the DIGESTS response is invalid.
36 : : * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD
37 : : * The DIGESTS response contains one or more invalid fields.
38 : : * @retval LIBSPDM_STATUS_ERROR_PEER
39 : : * The Responder returned an unexpected error.
40 : : * @retval LIBSPDM_STATUS_BUSY_PEER
41 : : * The Responder continually returned Busy error messages.
42 : : * @retval LIBSPDM_STATUS_RESYNCH_PEER
43 : : * The Responder returned a RequestResynch error message.
44 : : * @retval LIBSPDM_STATUS_BUFFER_FULL
45 : : * The buffer used to store transcripts is exhausted.
46 : : **/
47 : 53 : static libspdm_return_t libspdm_try_get_digest(libspdm_context_t *spdm_context,
48 : : const uint32_t *session_id,
49 : : uint8_t *slot_mask,
50 : : void *total_digest_buffer)
51 : : {
52 : : libspdm_return_t status;
53 : : spdm_get_digest_request_t *spdm_request;
54 : : size_t spdm_request_size;
55 : : libspdm_digests_response_max_t *spdm_response;
56 : : size_t spdm_response_size;
57 : : size_t digest_size;
58 : : size_t digest_count;
59 : : size_t index;
60 : : uint8_t *message;
61 : : size_t message_size;
62 : : size_t transport_header_size;
63 : : libspdm_session_info_t *session_info;
64 : : libspdm_session_state_t session_state;
65 : : size_t additional_size;
66 : : spdm_key_pair_id_t *key_pair_id;
67 : : spdm_certificate_info_t *cert_info;
68 : : spdm_key_usage_bit_mask_t *key_usage_bit_mask;
69 : : size_t slot_index;
70 : : uint8_t cert_model;
71 : 53 : uint8_t zero_digest[LIBSPDM_MAX_HASH_SIZE] = {0};
72 : :
73 : : /* -=[Verify State Phase]=- */
74 [ + + ]: 53 : if (!libspdm_is_capabilities_flag_supported(
75 : : spdm_context, true, 0,
76 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP)) {
77 : 1 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
78 : : }
79 [ + + ]: 52 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
80 : 1 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
81 : : }
82 : :
83 : 51 : session_info = NULL;
84 [ + + ]: 51 : if (session_id != NULL) {
85 : 2 : session_info = libspdm_get_session_info_via_session_id(spdm_context, *session_id);
86 [ - + ]: 2 : if (session_info == NULL) {
87 : 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
88 : : }
89 : 2 : session_state = libspdm_secured_message_get_session_state(
90 : : session_info->secured_message_context);
91 [ - + ]: 2 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
92 : 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
93 : : }
94 : : }
95 : :
96 : 51 : libspdm_reset_message_buffer_via_request_code(spdm_context, session_info, SPDM_GET_DIGESTS);
97 : :
98 : : /* -=[Construct Request Phase]=- */
99 : 51 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
100 : 51 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
101 [ + + ]: 51 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
102 : 1 : return status;
103 : : }
104 [ - + ]: 50 : LIBSPDM_ASSERT (message_size >= transport_header_size +
105 : : spdm_context->local_context.capability.transport_tail_size);
106 : 50 : spdm_request = (void *)(message + transport_header_size);
107 : 50 : spdm_request_size = message_size - transport_header_size -
108 : 50 : spdm_context->local_context.capability.transport_tail_size;
109 : :
110 [ - + ]: 50 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_get_digest_request_t));
111 : 50 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
112 : 50 : spdm_request->header.request_response_code = SPDM_GET_DIGESTS;
113 : 50 : spdm_request->header.param1 = 0;
114 : 50 : spdm_request->header.param2 = 0;
115 : 50 : spdm_request_size = sizeof(spdm_get_digest_request_t);
116 : :
117 : : /* -=[Send Request Phase]=- */
118 : 50 : status = libspdm_send_spdm_request(spdm_context, session_id, spdm_request_size, spdm_request);
119 [ + + ]: 50 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
120 : 1 : libspdm_release_sender_buffer (spdm_context);
121 : 1 : return status;
122 : : }
123 : 49 : libspdm_release_sender_buffer (spdm_context);
124 : 49 : spdm_request = (void *)spdm_context->last_spdm_request;
125 : :
126 : : /* -=[Receive Response Phase]=- */
127 : 49 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
128 [ + + ]: 49 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
129 : 1 : return status;
130 : : }
131 [ - + ]: 48 : LIBSPDM_ASSERT (message_size >= transport_header_size);
132 : 48 : spdm_response = (void *)(message);
133 : 48 : spdm_response_size = message_size;
134 : :
135 : 48 : status = libspdm_receive_spdm_response(
136 : : spdm_context, session_id, &spdm_response_size, (void **)&spdm_response);
137 [ + + ]: 48 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
138 : 3 : goto receive_done;
139 : : }
140 : :
141 : : /* -=[Validate Response Phase]=- */
142 [ - + ]: 45 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
143 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
144 : 0 : goto receive_done;
145 : : }
146 [ + + ]: 45 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
147 : 22 : status = libspdm_handle_error_response_main(
148 : : spdm_context, session_id,
149 : : &spdm_response_size,
150 : : (void **)&spdm_response, SPDM_GET_DIGESTS, SPDM_DIGESTS);
151 [ + - ]: 22 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
152 : 22 : goto receive_done;
153 : : }
154 [ + + ]: 23 : } else if (spdm_response->header.request_response_code != SPDM_DIGESTS) {
155 : 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
156 : 2 : goto receive_done;
157 : : }
158 [ + + ]: 21 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
159 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
160 : 1 : goto receive_done;
161 : : }
162 [ - + ]: 20 : if (spdm_response_size < sizeof(spdm_digest_response_t)) {
163 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
164 : 0 : goto receive_done;
165 : : }
166 : :
167 : 20 : digest_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
168 [ + - ]: 20 : if (slot_mask != NULL) {
169 : 20 : *slot_mask = spdm_response->header.param2;
170 : : }
171 : :
172 : 20 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "provisioned_slot_mask - 0x%02x\n",
173 : : spdm_response->header.param2));
174 [ + + ]: 20 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
175 : 10 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "supported_slot_mask - 0x%02x\n",
176 : : spdm_response->header.param1));
177 : : /* If bit is set in ProvisionedSlotMask then it must also be set in SupportedSlotMask. */
178 : 10 : if ((spdm_response->header.param1 & spdm_response->header.param2) !=
179 [ + + ]: 10 : spdm_response->header.param2) {
180 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
181 : 1 : goto receive_done;
182 : : }
183 : : }
184 : :
185 : 19 : digest_count = 0;
186 [ + + ]: 171 : for (index = 0; index < SPDM_MAX_SLOT_COUNT; index++) {
187 [ + + ]: 152 : if (spdm_response->header.param2 & (1 << index)) {
188 : 47 : digest_count++;
189 : : }
190 : : }
191 [ + + ]: 19 : if (digest_count == 0) {
192 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
193 : 1 : goto receive_done;
194 : : }
195 : :
196 : 18 : additional_size = 0;
197 [ + + ]: 18 : if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) &&
198 [ + + ]: 9 : spdm_context->connection_info.multi_key_conn_rsp) {
199 : 7 : additional_size = sizeof(spdm_key_pair_id_t) + sizeof(spdm_certificate_info_t) +
200 : : sizeof(spdm_key_usage_bit_mask_t);
201 : : }
202 : 18 : if (spdm_response_size <
203 [ + + ]: 18 : sizeof(spdm_digest_response_t) + digest_count * (digest_size + additional_size)) {
204 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
205 : 1 : goto receive_done;
206 : : }
207 : 17 : spdm_response_size =
208 : 17 : sizeof(spdm_digest_response_t) + digest_count * (digest_size + additional_size);
209 : :
210 : : /* -=[Process Response Phase]=- */
211 [ + + ]: 17 : if (session_id == NULL) {
212 : 15 : status = libspdm_append_message_b(spdm_context, spdm_request, spdm_request_size);
213 [ - + ]: 15 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
214 : 0 : goto receive_done;
215 : : }
216 : :
217 : 15 : status = libspdm_append_message_b(spdm_context, spdm_response, spdm_response_size);
218 [ - + ]: 15 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
219 : 0 : goto receive_done;
220 : : }
221 : :
222 [ + + ]: 15 : if (spdm_context->connection_info.multi_key_conn_rsp) {
223 : 7 : status = libspdm_append_message_d(spdm_context, spdm_response, spdm_response_size);
224 [ - + ]: 7 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
225 : 0 : goto receive_done;
226 : : }
227 : : }
228 : : }
229 : :
230 : 17 : key_pair_id =
231 : 17 : (spdm_key_pair_id_t *)((uint8_t *)spdm_response->digest + digest_size * digest_count);
232 : 17 : cert_info =
233 : : (spdm_certificate_info_t *)((uint8_t *)key_pair_id + sizeof(spdm_key_pair_id_t) *
234 : : digest_count);
235 : 17 : key_usage_bit_mask =
236 : : (spdm_key_usage_bit_mask_t *)((uint8_t *)cert_info + sizeof(spdm_certificate_info_t) *
237 : : digest_count);
238 [ + + ]: 60 : for (index = 0; index < digest_count; index++) {
239 : 43 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "digest (0x%zx) - ", index));
240 : 43 : LIBSPDM_INTERNAL_DUMP_DATA(&spdm_response->digest[digest_size * index], digest_size);
241 : 43 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
242 : : }
243 [ + + ]: 17 : if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) &&
244 [ + + ]: 9 : spdm_context->connection_info.multi_key_conn_rsp) {
245 [ + + ]: 22 : for (index = 0; index < digest_count; index++) {
246 : 15 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "key_pair_id (0x%zx) - 0x%02x\n", index,
247 : : key_pair_id[index]));
248 : : }
249 [ + + ]: 22 : for (index = 0; index < digest_count; index++) {
250 : 15 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "cert_info (0x%zx) - 0x%02x\n", index,
251 : : cert_info[index]));
252 : : }
253 [ + + ]: 22 : for (index = 0; index < digest_count; index++) {
254 : 15 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "key_usage_bit_mask (0x%zx) - 0x%04x\n", index,
255 : : key_usage_bit_mask[index]));
256 : : }
257 : : }
258 : :
259 [ + - ]: 17 : if (total_digest_buffer != NULL) {
260 : 17 : libspdm_copy_mem(total_digest_buffer, digest_size * digest_count,
261 : 17 : spdm_response->digest, digest_size * digest_count);
262 : : }
263 : :
264 : 17 : spdm_context->connection_info.peer_provisioned_slot_mask = spdm_response->header.param2;
265 [ + + ]: 17 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
266 : 9 : spdm_context->connection_info.peer_supported_slot_mask = spdm_response->header.param1;
267 : : } else {
268 : 8 : spdm_context->connection_info.peer_supported_slot_mask = spdm_response->header.param2;
269 : : }
270 : :
271 : 17 : libspdm_zero_mem(spdm_context->connection_info.peer_key_pair_id,
272 : : sizeof(spdm_context->connection_info.peer_key_pair_id));
273 : 17 : libspdm_zero_mem(spdm_context->connection_info.peer_cert_info,
274 : : sizeof(spdm_context->connection_info.peer_cert_info));
275 : 17 : libspdm_zero_mem(spdm_context->connection_info.peer_key_usage_bit_mask,
276 : : sizeof(spdm_context->connection_info.peer_key_usage_bit_mask));
277 : :
278 [ + + ]: 17 : if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) &&
279 [ + + ]: 9 : spdm_context->connection_info.multi_key_conn_rsp) {
280 : 7 : slot_index = 0;
281 [ + + ]: 40 : for (index = 0; index < SPDM_MAX_SLOT_COUNT; index++) {
282 [ + + ]: 36 : if (spdm_response->header.param2 & (1 << index)) {
283 : 15 : spdm_context->connection_info.peer_key_pair_id[index] = key_pair_id[slot_index];
284 : 15 : cert_model = cert_info[slot_index] & SPDM_CERTIFICATE_INFO_CERT_MODEL_MASK;
285 [ - + ]: 15 : if (cert_model > SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT) {
286 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
287 : 0 : goto receive_done;
288 : : }
289 [ + + ]: 15 : if (index == 0) {
290 [ + + ]: 7 : if (cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT) {
291 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
292 : 1 : goto receive_done;
293 : : }
294 [ + + ]: 6 : if ((key_usage_bit_mask[slot_index] &
295 : : (SPDM_KEY_USAGE_BIT_MASK_KEY_EX_USE |
296 : : SPDM_KEY_USAGE_BIT_MASK_CHALLENGE_USE |
297 : : SPDM_KEY_USAGE_BIT_MASK_MEASUREMENT_USE |
298 : : SPDM_KEY_USAGE_BIT_MASK_ENDPOINT_INFO_USE)) == 0) {
299 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
300 : 1 : goto receive_done;
301 : : }
302 : : }
303 [ + + ]: 13 : if ((cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) &&
304 [ + - ]: 1 : (!libspdm_consttime_is_mem_equal(
305 : 1 : spdm_response->digest + digest_size * slot_index,
306 : : zero_digest,
307 : : digest_size))) {
308 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
309 : 1 : goto receive_done;
310 : : }
311 : 12 : spdm_context->connection_info.peer_cert_info[index] = cert_model;
312 : 12 : spdm_context->connection_info.peer_key_usage_bit_mask[index] =
313 : 12 : key_usage_bit_mask[slot_index];
314 : 12 : slot_index++;
315 : : }
316 : : }
317 : : }
318 : :
319 : : /* -=[Update State Phase]=- */
320 [ + + ]: 14 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_AFTER_DIGESTS) {
321 : 11 : spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_AFTER_DIGESTS;
322 : : }
323 : 14 : status = LIBSPDM_STATUS_SUCCESS;
324 : :
325 : : /* -=[Log Message Phase]=- */
326 : : #if LIBSPDM_ENABLE_MSG_LOG
327 : 14 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
328 : : #endif /* LIBSPDM_ENABLE_MSG_LOG */
329 : :
330 : 48 : receive_done:
331 : 48 : libspdm_release_receiver_buffer (spdm_context);
332 : 48 : return status;
333 : : }
334 : :
335 : 53 : libspdm_return_t libspdm_get_digest(void *spdm_context, const uint32_t *session_id,
336 : : uint8_t *slot_mask, void *total_digest_buffer)
337 : : {
338 : : libspdm_context_t *context;
339 : : size_t retry;
340 : : uint64_t retry_delay_time;
341 : : libspdm_return_t status;
342 : :
343 : 53 : context = spdm_context;
344 : 53 : context->crypto_request = true;
345 : 53 : retry = context->retry_times;
346 : 53 : retry_delay_time = context->retry_delay_time;
347 : : do {
348 : 53 : status = libspdm_try_get_digest(context, session_id, slot_mask, total_digest_buffer);
349 [ + + ]: 53 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
350 : 52 : return status;
351 : : }
352 : :
353 : 1 : libspdm_sleep(retry_delay_time);
354 [ - + ]: 1 : } while (retry-- != 0);
355 : :
356 : 1 : return status;
357 : : }
358 : :
359 : : #endif /* LIBSPDM_SEND_GET_CERTIFICATE_SUPPORT */
|