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_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 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 45 : 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 45 : uint8_t zero_digest[LIBSPDM_MAX_HASH_SIZE] = {0};
72 :
73 : /* -=[Verify State Phase]=- */
74 45 : 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 44 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
80 1 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
81 : }
82 :
83 43 : session_info = NULL;
84 43 : if (session_id != NULL) {
85 1 : session_info = libspdm_get_session_info_via_session_id(spdm_context, *session_id);
86 1 : if (session_info == NULL) {
87 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
88 : }
89 1 : session_state = libspdm_secured_message_get_session_state(
90 : session_info->secured_message_context);
91 1 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
92 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
93 : }
94 : }
95 :
96 43 : libspdm_reset_message_buffer_via_request_code(spdm_context, session_info, SPDM_GET_DIGESTS);
97 :
98 : /* -=[Construct Request Phase]=- */
99 43 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
100 43 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
101 43 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
102 1 : return status;
103 : }
104 42 : LIBSPDM_ASSERT (message_size >= transport_header_size +
105 : spdm_context->local_context.capability.transport_tail_size);
106 42 : spdm_request = (void *)(message + transport_header_size);
107 42 : spdm_request_size = message_size - transport_header_size -
108 42 : spdm_context->local_context.capability.transport_tail_size;
109 :
110 42 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_get_digest_request_t));
111 42 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
112 42 : spdm_request->header.request_response_code = SPDM_GET_DIGESTS;
113 42 : spdm_request->header.param1 = 0;
114 42 : spdm_request->header.param2 = 0;
115 42 : spdm_request_size = sizeof(spdm_get_digest_request_t);
116 :
117 : /* -=[Send Request Phase]=- */
118 42 : status = libspdm_send_spdm_request(spdm_context, session_id, spdm_request_size, spdm_request);
119 42 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
120 1 : libspdm_release_sender_buffer (spdm_context);
121 1 : return status;
122 : }
123 41 : libspdm_release_sender_buffer (spdm_context);
124 41 : spdm_request = (void *)spdm_context->last_spdm_request;
125 :
126 : /* -=[Receive Response Phase]=- */
127 41 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
128 41 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
129 1 : return status;
130 : }
131 40 : LIBSPDM_ASSERT (message_size >= transport_header_size);
132 40 : spdm_response = (void *)(message);
133 40 : spdm_response_size = message_size;
134 :
135 40 : status = libspdm_receive_spdm_response(
136 : spdm_context, session_id, &spdm_response_size, (void **)&spdm_response);
137 40 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
138 1 : goto receive_done;
139 : }
140 :
141 : /* -=[Validate Response Phase]=- */
142 39 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
143 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
144 0 : goto receive_done;
145 : }
146 39 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
147 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
148 1 : goto receive_done;
149 : }
150 38 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
151 22 : status = libspdm_handle_error_response_main(
152 : spdm_context, session_id,
153 : &spdm_response_size,
154 : (void **)&spdm_response, SPDM_GET_DIGESTS, SPDM_DIGESTS);
155 22 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
156 22 : goto receive_done;
157 : }
158 16 : } else if (spdm_response->header.request_response_code != SPDM_DIGESTS) {
159 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
160 1 : goto receive_done;
161 : }
162 15 : 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 15 : digest_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
168 15 : if (slot_mask != NULL) {
169 15 : *slot_mask = spdm_response->header.param2;
170 : }
171 :
172 15 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "provisioned_slot_mask - 0x%02x\n",
173 : spdm_response->header.param2));
174 15 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
175 7 : 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 7 : if ((spdm_response->header.param1 & spdm_response->header.param2) !=
179 7 : spdm_response->header.param2) {
180 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
181 1 : goto receive_done;
182 : }
183 : }
184 :
185 14 : digest_count = 0;
186 126 : for (index = 0; index < SPDM_MAX_SLOT_COUNT; index++) {
187 112 : if (spdm_response->header.param2 & (1 << index)) {
188 31 : digest_count++;
189 : }
190 : }
191 14 : if (digest_count == 0) {
192 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
193 1 : goto receive_done;
194 : }
195 :
196 13 : additional_size = 0;
197 13 : if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) &&
198 6 : spdm_context->connection_info.multi_key_conn_rsp) {
199 5 : additional_size = sizeof(spdm_key_pair_id_t) + sizeof(spdm_certificate_info_t) +
200 : sizeof(spdm_key_usage_bit_mask_t);
201 : }
202 13 : if (spdm_response_size <
203 13 : 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 12 : spdm_response_size =
208 12 : sizeof(spdm_digest_response_t) + digest_count * (digest_size + additional_size);
209 :
210 : /* -=[Process Response Phase]=- */
211 12 : if (session_id == NULL) {
212 11 : status = libspdm_append_message_b(spdm_context, spdm_request, spdm_request_size);
213 11 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
214 0 : goto receive_done;
215 : }
216 :
217 11 : status = libspdm_append_message_b(spdm_context, spdm_response, spdm_response_size);
218 11 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
219 0 : goto receive_done;
220 : }
221 :
222 11 : if (spdm_context->connection_info.multi_key_conn_rsp) {
223 5 : status = libspdm_append_message_d(spdm_context, spdm_response, spdm_response_size);
224 5 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
225 0 : goto receive_done;
226 : }
227 : }
228 : }
229 :
230 12 : key_pair_id =
231 12 : (spdm_key_pair_id_t *)((uint8_t *)spdm_response->digest + digest_size * digest_count);
232 12 : cert_info =
233 : (spdm_certificate_info_t *)((uint8_t *)key_pair_id + sizeof(spdm_key_pair_id_t) *
234 : digest_count);
235 12 : key_usage_bit_mask =
236 : (spdm_key_usage_bit_mask_t *)((uint8_t *)cert_info + sizeof(spdm_certificate_info_t) *
237 : digest_count);
238 39 : for (index = 0; index < digest_count; index++) {
239 27 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "digest (0x%zx) - ", index));
240 27 : LIBSPDM_INTERNAL_DUMP_DATA(&spdm_response->digest[digest_size * index], digest_size);
241 27 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
242 : }
243 12 : if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) &&
244 6 : spdm_context->connection_info.multi_key_conn_rsp) {
245 18 : for (index = 0; index < digest_count; index++) {
246 13 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "key_pair_id (0x%zx) - 0x%02x\n", index,
247 : key_pair_id[index]));
248 : }
249 18 : for (index = 0; index < digest_count; index++) {
250 13 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "cert_info (0x%zx) - 0x%02x\n", index,
251 : cert_info[index]));
252 : }
253 18 : for (index = 0; index < digest_count; index++) {
254 13 : 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 12 : if (total_digest_buffer != NULL) {
260 12 : libspdm_copy_mem(total_digest_buffer, digest_size * digest_count,
261 12 : spdm_response->digest, digest_size * digest_count);
262 : }
263 :
264 12 : spdm_context->connection_info.peer_provisioned_slot_mask = spdm_response->header.param2;
265 12 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
266 6 : spdm_context->connection_info.peer_supported_slot_mask = spdm_response->header.param1;
267 : } else {
268 6 : spdm_context->connection_info.peer_supported_slot_mask = spdm_response->header.param2;
269 : }
270 12 : libspdm_copy_mem(
271 12 : spdm_context->connection_info.peer_total_digest_buffer,
272 : sizeof(spdm_context->connection_info.peer_total_digest_buffer),
273 12 : spdm_response->digest, digest_size * digest_count);
274 12 : libspdm_zero_mem(spdm_context->connection_info.peer_key_pair_id,
275 : sizeof(spdm_context->connection_info.peer_key_pair_id));
276 12 : libspdm_zero_mem(spdm_context->connection_info.peer_cert_info,
277 : sizeof(spdm_context->connection_info.peer_cert_info));
278 12 : libspdm_zero_mem(spdm_context->connection_info.peer_key_usage_bit_mask,
279 : sizeof(spdm_context->connection_info.peer_key_usage_bit_mask));
280 12 : if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) &&
281 6 : spdm_context->connection_info.multi_key_conn_rsp) {
282 5 : slot_index = 0;
283 22 : for (index = 0; index < SPDM_MAX_SLOT_COUNT; index++) {
284 20 : if (spdm_response->header.param2 & (1 << index)) {
285 13 : spdm_context->connection_info.peer_key_pair_id[index] = key_pair_id[slot_index];
286 13 : cert_model = cert_info[slot_index] & SPDM_CERTIFICATE_INFO_CERT_MODEL_MASK;
287 13 : if (cert_model > SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT) {
288 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
289 0 : goto receive_done;
290 : }
291 13 : if (index == 0) {
292 5 : if (cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT) {
293 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
294 1 : goto receive_done;
295 : }
296 4 : if ((key_usage_bit_mask[slot_index] &
297 : (SPDM_KEY_USAGE_BIT_MASK_KEY_EX_USE |
298 : SPDM_KEY_USAGE_BIT_MASK_CHALLENGE_USE |
299 : SPDM_KEY_USAGE_BIT_MASK_MEASUREMENT_USE |
300 : SPDM_KEY_USAGE_BIT_MASK_ENDPOINT_INFO_USE)) == 0) {
301 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
302 1 : goto receive_done;
303 : }
304 : }
305 11 : if ((cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) &&
306 1 : (!libspdm_consttime_is_mem_equal(
307 1 : spdm_response->digest + digest_size * slot_index,
308 : zero_digest,
309 : digest_size))) {
310 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
311 1 : goto receive_done;
312 : }
313 10 : spdm_context->connection_info.peer_cert_info[index] = cert_model;
314 10 : spdm_context->connection_info.peer_key_usage_bit_mask[index] =
315 10 : key_usage_bit_mask[slot_index];
316 10 : slot_index++;
317 : }
318 : }
319 : }
320 :
321 : /* -=[Update State Phase]=- */
322 9 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_AFTER_DIGESTS) {
323 7 : spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_AFTER_DIGESTS;
324 : }
325 9 : status = LIBSPDM_STATUS_SUCCESS;
326 :
327 : /* -=[Log Message Phase]=- */
328 : #if LIBSPDM_ENABLE_MSG_LOG
329 9 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
330 : #endif /* LIBSPDM_ENABLE_MSG_LOG */
331 :
332 40 : receive_done:
333 40 : libspdm_release_receiver_buffer (spdm_context);
334 40 : return status;
335 : }
336 :
337 45 : libspdm_return_t libspdm_get_digest(void *spdm_context, const uint32_t *session_id,
338 : uint8_t *slot_mask, void *total_digest_buffer)
339 : {
340 : libspdm_context_t *context;
341 : size_t retry;
342 : uint64_t retry_delay_time;
343 : libspdm_return_t status;
344 :
345 45 : context = spdm_context;
346 45 : context->crypto_request = true;
347 45 : retry = context->retry_times;
348 45 : retry_delay_time = context->retry_delay_time;
349 : do {
350 45 : status = libspdm_try_get_digest(context, session_id, slot_mask, total_digest_buffer);
351 45 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
352 44 : return status;
353 : }
354 :
355 1 : libspdm_sleep(retry_delay_time);
356 1 : } while (retry-- != 0);
357 :
358 1 : return status;
359 : }
360 :
361 : #endif /* LIBSPDM_SEND_GET_CERTIFICATE_SUPPORT */
|