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_requester_lib.h"
8 :
9 : #if LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP
10 :
11 23 : bool libspdm_verify_measurement_signature(libspdm_context_t *spdm_context,
12 : libspdm_session_info_t *session_info,
13 : const void *sign_data,
14 : size_t sign_data_size)
15 : {
16 : bool result;
17 : void *context;
18 : uint8_t slot_id;
19 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
20 : libspdm_l1l2_managed_buffer_t l1l2;
21 : uint8_t *l1l2_buffer;
22 : size_t l1l2_buffer_size;
23 : const uint8_t *cert_chain_data;
24 : size_t cert_chain_data_size;
25 : const uint8_t *cert_buffer;
26 : size_t cert_buffer_size;
27 : #else
28 : uint8_t l1l2_hash[LIBSPDM_MAX_HASH_SIZE];
29 : size_t l1l2_hash_size;
30 : #endif
31 :
32 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
33 : result = libspdm_calculate_l1l2(spdm_context, session_info, &l1l2);
34 : l1l2_buffer = libspdm_get_managed_buffer(&l1l2);
35 : l1l2_buffer_size = libspdm_get_managed_buffer_size(&l1l2);
36 : #else
37 23 : l1l2_hash_size = sizeof(l1l2_hash);
38 23 : result = libspdm_calculate_l1l2_hash(spdm_context, session_info, &l1l2_hash_size, l1l2_hash);
39 : #endif
40 23 : libspdm_reset_message_m(spdm_context, session_info);
41 23 : if (!result) {
42 0 : return false;
43 : }
44 :
45 23 : slot_id = spdm_context->connection_info.peer_used_cert_chain_slot_id;
46 23 : LIBSPDM_ASSERT((slot_id < SPDM_MAX_SLOT_COUNT) || (slot_id == 0xF));
47 :
48 23 : if (slot_id == 0xF) {
49 1 : result = libspdm_asym_get_public_key_from_der(
50 : spdm_context->connection_info.algorithm.base_asym_algo,
51 1 : spdm_context->local_context.peer_public_key_provision,
52 : spdm_context->local_context.peer_public_key_provision_size,
53 : &context);
54 1 : if (!result) {
55 0 : return false;
56 : }
57 : } else {
58 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
59 : result = libspdm_get_peer_cert_chain_data(
60 : spdm_context, (const void **)&cert_chain_data, &cert_chain_data_size);
61 : if (!result) {
62 : return false;
63 : }
64 :
65 : /* Get leaf cert from cert chain*/
66 : result = libspdm_x509_get_cert_from_cert_chain(cert_chain_data,
67 : cert_chain_data_size, -1,
68 : &cert_buffer, &cert_buffer_size);
69 : if (!result) {
70 : return false;
71 : }
72 :
73 : result = libspdm_asym_get_public_key_from_x509(
74 : spdm_context->connection_info.algorithm.base_asym_algo,
75 : cert_buffer, cert_buffer_size, &context);
76 : if (!result) {
77 : return false;
78 : }
79 : #else
80 22 : context = spdm_context->connection_info.peer_used_cert_chain[slot_id].leaf_cert_public_key;
81 22 : LIBSPDM_ASSERT(context != NULL);
82 : #endif
83 : }
84 :
85 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
86 : result = libspdm_asym_verify_ex(
87 : spdm_context->connection_info.version, SPDM_MEASUREMENTS,
88 : spdm_context->connection_info.algorithm.base_asym_algo,
89 : spdm_context->connection_info.algorithm.base_hash_algo,
90 : context, l1l2_buffer, l1l2_buffer_size, sign_data, sign_data_size,
91 : &spdm_context->spdm_10_11_verify_signature_endian);
92 : libspdm_asym_free(spdm_context->connection_info.algorithm.base_asym_algo, context);
93 : #else
94 23 : result = libspdm_asym_verify_hash_ex(
95 23 : spdm_context->connection_info.version, SPDM_MEASUREMENTS,
96 : spdm_context->connection_info.algorithm.base_asym_algo,
97 : spdm_context->connection_info.algorithm.base_hash_algo,
98 : context, l1l2_hash, l1l2_hash_size, sign_data, sign_data_size,
99 : &spdm_context->spdm_10_11_verify_signature_endian);
100 23 : if (slot_id == 0xF) {
101 1 : libspdm_asym_free(spdm_context->connection_info.algorithm.base_asym_algo, context);
102 : }
103 : #endif
104 23 : if (!result) {
105 8 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "!!! verify_measurement_signature - FAIL !!!\n"));
106 8 : return false;
107 : }
108 :
109 15 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "!!! verify_measurement_signature - PASS !!!\n"));
110 15 : return true;
111 : }
112 :
113 : /**
114 : * This function sends GET_MEASUREMENT to get measurement from the device.
115 : * If the signature is requested this function verifies the signature of the measurement.
116 : *
117 : * @param context A pointer to the SPDM context.
118 : * @param session_id Indicates if it is a secured message protected via SPDM session.
119 : * If session_id is NULL, it is a normal message.
120 : * If session_id is not NULL, it is a secured message.
121 : * @param request_attribute The request attribute of the request message.
122 : * @param measurement_operation The measurement operation of the request message.
123 : * @param slot_id The number of slot for the certificate chain.
124 : * @param requester_context If not NULL, a buffer to hold the requester context (8 bytes).
125 : * It is used only if the negotiated version >= 1.3.
126 : * @param content_changed The measurement content changed output param.
127 : * @param number_of_blocks The number of blocks of the measurement record.
128 : * @param measurement_record_length On input, indicate the size in bytes of the destination buffer
129 : * to store the measurement record.
130 : * On output, indicate the size in bytes of the measurement record.
131 : * @param measurement_record A pointer to a destination buffer to store the measurement record.
132 : * @param requester_nonce_in If not NULL, a buffer that holds the requester nonce (32 bytes)
133 : * @param requester_nonce If not NULL, a buffer to hold the requester nonce (32 bytes).
134 : * @param responder_nonce If not NULL, a buffer to hold the responder nonce (32 bytes).
135 : *
136 : **/
137 306 : static libspdm_return_t libspdm_try_get_measurement(libspdm_context_t *spdm_context,
138 : const uint32_t *session_id,
139 : uint8_t request_attribute,
140 : uint8_t measurement_operation,
141 : uint8_t slot_id_param,
142 : const void *requester_context,
143 : uint8_t *content_changed,
144 : uint8_t *number_of_blocks,
145 : uint32_t *measurement_record_length,
146 : void *measurement_record,
147 : const void *requester_nonce_in,
148 : void *requester_nonce,
149 : void *responder_nonce,
150 : void *opaque_data,
151 : size_t *opaque_data_size)
152 : {
153 : bool result;
154 : libspdm_return_t status;
155 : spdm_get_measurements_request_t *spdm_request;
156 : size_t spdm_request_size;
157 : spdm_measurements_response_t *spdm_response;
158 : size_t spdm_response_size;
159 : uint32_t measurement_record_data_length;
160 : uint8_t *measurement_record_data;
161 : spdm_measurement_block_common_header_t *measurement_block_header;
162 : uint32_t measurement_block_size;
163 : uint8_t measurement_block_count;
164 : uint8_t *ptr;
165 : void *nonce;
166 : uint16_t opaque_length;
167 : void *signature;
168 : size_t signature_size;
169 : libspdm_session_info_t *session_info;
170 : libspdm_session_state_t session_state;
171 : uint8_t *message;
172 : size_t message_size;
173 : size_t transport_header_size;
174 :
175 : /* -=[Check Parameters Phase]=- */
176 306 : LIBSPDM_ASSERT((slot_id_param < SPDM_MAX_SLOT_COUNT) || (slot_id_param == 0xF));
177 306 : LIBSPDM_ASSERT((slot_id_param != 0xf) ||
178 : (spdm_context->local_context.peer_public_key_provision_size != 0));
179 :
180 : /* -=[Verify State Phase]=- */
181 306 : if (!libspdm_is_capabilities_flag_supported(
182 : spdm_context, true, 0,
183 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP)) {
184 1 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
185 : }
186 :
187 305 : LIBSPDM_ASSERT(spdm_context->local_context.algorithm.measurement_spec != 0);
188 :
189 305 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
190 2 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
191 : }
192 :
193 303 : if (session_id == NULL) {
194 302 : session_info = NULL;
195 : } else {
196 1 : session_info = libspdm_get_session_info_via_session_id(spdm_context, *session_id);
197 1 : if (session_info == NULL) {
198 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
199 : }
200 1 : session_state = libspdm_secured_message_get_session_state(
201 : session_info->secured_message_context);
202 1 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
203 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
204 : }
205 : }
206 :
207 303 : if (libspdm_is_capabilities_flag_supported(
208 : spdm_context, true, 0,
209 3 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP_NO_SIG) &&
210 3 : ((request_attribute & SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE) != 0)) {
211 1 : return LIBSPDM_STATUS_INVALID_PARAMETER;
212 : }
213 :
214 302 : if ((request_attribute & SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE) != 0) {
215 75 : signature_size = libspdm_get_asym_signature_size(
216 : spdm_context->connection_info.algorithm.base_asym_algo);
217 : } else {
218 227 : signature_size = 0;
219 : }
220 :
221 302 : libspdm_reset_message_buffer_via_request_code(spdm_context, NULL, SPDM_GET_MEASUREMENTS);
222 :
223 : /* -=[Construct Request Phase]=- */
224 302 : spdm_context->connection_info.peer_used_cert_chain_slot_id = slot_id_param;
225 302 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
226 302 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
227 302 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
228 1 : return status;
229 : }
230 301 : LIBSPDM_ASSERT (message_size >= transport_header_size +
231 : spdm_context->local_context.capability.transport_tail_size);
232 301 : spdm_request = (void *)(message + transport_header_size);
233 301 : spdm_request_size = message_size - transport_header_size -
234 301 : spdm_context->local_context.capability.transport_tail_size;
235 :
236 301 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_request->header));
237 301 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
238 301 : spdm_request->header.request_response_code = SPDM_GET_MEASUREMENTS;
239 301 : spdm_request->header.param1 = request_attribute;
240 301 : spdm_request->header.param2 = measurement_operation;
241 301 : if ((request_attribute & SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE) != 0) {
242 75 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
243 0 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_get_measurements_request_t) +
244 : SPDM_REQ_CONTEXT_SIZE);
245 0 : spdm_request_size = sizeof(spdm_get_measurements_request_t) + SPDM_REQ_CONTEXT_SIZE;
246 75 : } else if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
247 75 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_get_measurements_request_t));
248 75 : spdm_request_size = sizeof(spdm_get_measurements_request_t);
249 : } else {
250 0 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_get_measurements_request_t) -
251 : sizeof(spdm_request->slot_id_param));
252 0 : spdm_request_size = sizeof(spdm_get_measurements_request_t) -
253 : sizeof(spdm_request->slot_id_param);
254 : }
255 :
256 75 : if (requester_nonce_in == NULL) {
257 73 : if(!libspdm_get_random_number(SPDM_NONCE_SIZE, spdm_request->nonce)) {
258 0 : libspdm_release_sender_buffer (spdm_context);
259 0 : return LIBSPDM_STATUS_LOW_ENTROPY;
260 : }
261 : } else {
262 2 : libspdm_copy_mem(spdm_request->nonce, sizeof(spdm_request->nonce),
263 : requester_nonce_in, SPDM_NONCE_SIZE);
264 : }
265 75 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "RequesterNonce - "));
266 75 : LIBSPDM_INTERNAL_DUMP_DATA(spdm_request->nonce, SPDM_NONCE_SIZE);
267 75 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
268 75 : spdm_request->slot_id_param = slot_id_param;
269 :
270 75 : if (requester_nonce != NULL) {
271 2 : libspdm_copy_mem(requester_nonce, SPDM_NONCE_SIZE,
272 2 : spdm_request->nonce, SPDM_NONCE_SIZE);
273 : }
274 : } else {
275 226 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
276 2 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_request->header) +
277 : SPDM_REQ_CONTEXT_SIZE);
278 2 : spdm_request_size = sizeof(spdm_request->header) + SPDM_REQ_CONTEXT_SIZE;
279 : } else {
280 224 : spdm_request_size = sizeof(spdm_request->header);
281 : }
282 :
283 226 : if (requester_nonce != NULL) {
284 0 : libspdm_zero_mem (requester_nonce, SPDM_NONCE_SIZE);
285 : }
286 : }
287 301 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
288 2 : if (requester_context == NULL) {
289 0 : libspdm_zero_mem((uint8_t *)spdm_request + spdm_request_size - SPDM_REQ_CONTEXT_SIZE,
290 : SPDM_REQ_CONTEXT_SIZE);
291 : } else {
292 2 : libspdm_copy_mem((uint8_t *)spdm_request + spdm_request_size - SPDM_REQ_CONTEXT_SIZE,
293 : SPDM_REQ_CONTEXT_SIZE,
294 : requester_context, SPDM_REQ_CONTEXT_SIZE);
295 : }
296 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "RequesterContext - "));
297 2 : LIBSPDM_INTERNAL_DUMP_DATA((uint8_t *)spdm_request + spdm_request_size -
298 : SPDM_REQ_CONTEXT_SIZE,
299 : SPDM_REQ_CONTEXT_SIZE);
300 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
301 : }
302 :
303 : /* -=[Send Request Phase]=- */
304 301 : status = libspdm_send_spdm_request(spdm_context, session_id, spdm_request_size, spdm_request);
305 301 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
306 2 : libspdm_release_sender_buffer (spdm_context);
307 2 : return status;
308 : }
309 299 : libspdm_release_sender_buffer (spdm_context);
310 299 : spdm_request = (void *)spdm_context->last_spdm_request;
311 :
312 : /* -=[Receive Response Phase]=- */
313 299 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
314 299 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
315 1 : return status;
316 : }
317 298 : LIBSPDM_ASSERT (message_size >= transport_header_size);
318 298 : spdm_response = (void *)(message);
319 298 : spdm_response_size = message_size;
320 :
321 298 : status = libspdm_receive_spdm_response(
322 : spdm_context, session_id, &spdm_response_size, (void **)&spdm_response);
323 298 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
324 1 : goto receive_done;
325 : }
326 :
327 : /* -=[Validate Response Phase]=- */
328 297 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
329 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
330 0 : goto receive_done;
331 : }
332 297 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
333 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
334 0 : goto receive_done;
335 : }
336 297 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
337 46 : status = libspdm_handle_error_response_main(
338 : spdm_context, session_id,
339 : &spdm_response_size, (void **)&spdm_response,
340 : SPDM_GET_MEASUREMENTS, SPDM_MEASUREMENTS);
341 46 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
342 45 : goto receive_done;
343 : }
344 251 : } else if (spdm_response->header.request_response_code != SPDM_MEASUREMENTS) {
345 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
346 2 : goto receive_done;
347 : }
348 250 : if (spdm_response_size < sizeof(spdm_measurements_response_t)) {
349 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
350 0 : goto receive_done;
351 : }
352 250 : if (measurement_operation ==
353 : SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_TOTAL_NUMBER_OF_MEASUREMENTS) {
354 8 : if (spdm_response->number_of_blocks != 0) {
355 4 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
356 4 : goto receive_done;
357 : }
358 242 : } else if (measurement_operation ==
359 : SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_ALL_MEASUREMENTS) {
360 2 : if ((spdm_response->number_of_blocks == 0) || (spdm_response->number_of_blocks == 0xff)) {
361 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
362 0 : goto receive_done;
363 : }
364 : } else {
365 240 : if (spdm_response->number_of_blocks != 1) {
366 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
367 0 : goto receive_done;
368 : }
369 : }
370 :
371 246 : measurement_record_data_length = libspdm_read_uint24(spdm_response->measurement_record_length);
372 246 : if (measurement_operation ==
373 : SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_TOTAL_NUMBER_OF_MEASUREMENTS) {
374 4 : if (measurement_record_data_length != 0) {
375 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
376 2 : goto receive_done;
377 : }
378 : } else {
379 242 : if (spdm_response_size <
380 242 : sizeof(spdm_measurements_response_t) +
381 : measurement_record_data_length) {
382 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
383 0 : goto receive_done;
384 : }
385 242 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "measurement_record_length - 0x%06x\n",
386 : measurement_record_data_length));
387 : }
388 :
389 244 : measurement_record_data = (void *)(spdm_response + 1);
390 :
391 244 : if ((request_attribute & SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE) != 0) {
392 25 : if (spdm_response_size <
393 : sizeof(spdm_measurements_response_t) +
394 25 : measurement_record_data_length + SPDM_NONCE_SIZE + sizeof(uint16_t)) {
395 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
396 0 : goto receive_done;
397 : }
398 25 : if ((spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_11) &&
399 25 : ((spdm_response->header.param2 & SPDM_MEASUREMENTS_RESPONSE_SLOT_ID_MASK)
400 25 : != slot_id_param)) {
401 3 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
402 3 : goto receive_done;
403 : }
404 22 : ptr = measurement_record_data + measurement_record_data_length;
405 22 : nonce = ptr;
406 22 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "nonce (0x%x) - ", SPDM_NONCE_SIZE));
407 22 : LIBSPDM_INTERNAL_DUMP_DATA(nonce, SPDM_NONCE_SIZE);
408 22 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
409 22 : ptr += SPDM_NONCE_SIZE;
410 22 : if (responder_nonce != NULL) {
411 2 : libspdm_copy_mem(responder_nonce, SPDM_NONCE_SIZE, nonce, SPDM_NONCE_SIZE);
412 : }
413 :
414 22 : opaque_length = libspdm_read_uint16((const uint8_t *)ptr);
415 22 : if (opaque_length > SPDM_MAX_OPAQUE_DATA_SIZE) {
416 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
417 0 : goto receive_done;
418 : }
419 22 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
420 3 : if (((spdm_context->connection_info.algorithm.other_params_support &
421 : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) ==
422 : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_NONE)
423 2 : && (opaque_length != 0)) {
424 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
425 0 : goto receive_done;
426 : }
427 : }
428 22 : ptr += sizeof(uint16_t);
429 22 : if (opaque_length != 0) {
430 9 : result = libspdm_process_general_opaque_data_check(spdm_context, opaque_length, ptr);
431 9 : if (!result) {
432 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
433 0 : goto receive_done;
434 : }
435 : }
436 :
437 22 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
438 0 : if (spdm_response_size <
439 : sizeof(spdm_measurements_response_t) +
440 : measurement_record_data_length + SPDM_NONCE_SIZE +
441 0 : sizeof(uint16_t) + opaque_length + SPDM_REQ_CONTEXT_SIZE + signature_size) {
442 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
443 0 : goto receive_done;
444 : }
445 0 : spdm_response_size = sizeof(spdm_measurements_response_t) +
446 : measurement_record_data_length +
447 0 : SPDM_NONCE_SIZE + sizeof(uint16_t) +
448 0 : opaque_length + SPDM_REQ_CONTEXT_SIZE + signature_size;
449 : } else {
450 22 : if (spdm_response_size <
451 : sizeof(spdm_measurements_response_t) +
452 : measurement_record_data_length + SPDM_NONCE_SIZE +
453 22 : sizeof(uint16_t) + opaque_length + signature_size) {
454 6 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
455 6 : goto receive_done;
456 : }
457 16 : spdm_response_size = sizeof(spdm_measurements_response_t) +
458 : measurement_record_data_length +
459 16 : SPDM_NONCE_SIZE + sizeof(uint16_t) +
460 16 : opaque_length + signature_size;
461 : }
462 :
463 16 : if ((opaque_data != NULL) && (opaque_data_size != NULL)) {
464 2 : if (opaque_length >= *opaque_data_size) {
465 0 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
466 0 : goto receive_done;
467 : }
468 2 : libspdm_copy_mem(opaque_data, *opaque_data_size, ptr, opaque_length);
469 2 : *opaque_data_size = opaque_length;
470 : }
471 16 : ptr += opaque_length;
472 16 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
473 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "RequesterContext - "));
474 0 : LIBSPDM_INTERNAL_DUMP_DATA(ptr, SPDM_REQ_CONTEXT_SIZE);
475 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
476 0 : if (!libspdm_consttime_is_mem_equal((uint8_t *)spdm_request +
477 0 : spdm_request_size - SPDM_REQ_CONTEXT_SIZE,
478 : ptr, SPDM_REQ_CONTEXT_SIZE)) {
479 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
480 0 : goto receive_done;
481 : }
482 0 : ptr += SPDM_REQ_CONTEXT_SIZE;
483 : }
484 :
485 : /* -=[Process Response Phase]=- */
486 16 : status = libspdm_append_message_m(spdm_context, session_info, spdm_request,
487 : spdm_request_size);
488 16 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
489 0 : goto receive_done;
490 : }
491 :
492 16 : status = libspdm_append_message_m(spdm_context, session_info, spdm_response,
493 : spdm_response_size - signature_size);
494 16 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
495 0 : goto receive_done;
496 : }
497 :
498 16 : signature = ptr;
499 16 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "signature (0x%zx):\n", signature_size));
500 16 : LIBSPDM_INTERNAL_DUMP_HEX(signature, signature_size);
501 :
502 16 : result = libspdm_verify_measurement_signature(
503 : spdm_context, session_info, signature, signature_size);
504 16 : if (!result) {
505 6 : status = LIBSPDM_STATUS_VERIF_FAIL;
506 6 : goto receive_done;
507 : }
508 :
509 10 : libspdm_reset_message_m(spdm_context, session_info);
510 : } else {
511 219 : if (spdm_response_size <
512 : sizeof(spdm_measurements_response_t) +
513 219 : measurement_record_data_length + sizeof(uint16_t)) {
514 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
515 0 : goto receive_done;
516 : }
517 219 : ptr = measurement_record_data + measurement_record_data_length;
518 :
519 219 : nonce = ptr;
520 219 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "nonce (0x%x) - ", SPDM_NONCE_SIZE));
521 219 : LIBSPDM_INTERNAL_DUMP_DATA(nonce, SPDM_NONCE_SIZE);
522 219 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
523 219 : ptr += SPDM_NONCE_SIZE;
524 219 : if (responder_nonce != NULL) {
525 0 : libspdm_copy_mem(responder_nonce, SPDM_NONCE_SIZE, nonce, SPDM_NONCE_SIZE);
526 : }
527 :
528 219 : opaque_length = libspdm_read_uint16((const uint8_t *)ptr);
529 219 : if (opaque_length > SPDM_MAX_OPAQUE_DATA_SIZE) {
530 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
531 2 : goto receive_done;
532 : }
533 217 : ptr += sizeof(uint16_t);
534 217 : if (opaque_length != 0) {
535 3 : result = libspdm_process_general_opaque_data_check(spdm_context, opaque_length, ptr);
536 3 : if (!result) {
537 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
538 0 : goto receive_done;
539 : }
540 : }
541 :
542 217 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
543 2 : if (spdm_response_size <
544 : sizeof(spdm_measurements_response_t) +
545 : measurement_record_data_length + SPDM_NONCE_SIZE +
546 2 : sizeof(uint16_t) + opaque_length + SPDM_REQ_CONTEXT_SIZE) {
547 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
548 0 : goto receive_done;
549 : }
550 2 : spdm_response_size = sizeof(spdm_measurements_response_t) +
551 : measurement_record_data_length +
552 2 : SPDM_NONCE_SIZE + sizeof(uint16_t) +
553 2 : opaque_length + SPDM_REQ_CONTEXT_SIZE;
554 : } else {
555 215 : if (spdm_response_size <
556 : sizeof(spdm_measurements_response_t) +
557 : measurement_record_data_length + SPDM_NONCE_SIZE +
558 215 : sizeof(uint16_t) + opaque_length) {
559 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
560 0 : goto receive_done;
561 : }
562 215 : spdm_response_size = sizeof(spdm_measurements_response_t) +
563 : measurement_record_data_length +
564 215 : SPDM_NONCE_SIZE + sizeof(uint16_t) +
565 : opaque_length;
566 : }
567 :
568 217 : if ((opaque_data != NULL) && (opaque_data_size != NULL)) {
569 0 : if (opaque_length >= *opaque_data_size) {
570 0 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
571 0 : goto receive_done;
572 : }
573 0 : libspdm_copy_mem(opaque_data, *opaque_data_size, ptr, opaque_length);
574 0 : *opaque_data_size = opaque_length;
575 : }
576 217 : ptr += opaque_length;
577 217 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
578 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "RequesterContext - "));
579 2 : LIBSPDM_INTERNAL_DUMP_DATA(ptr, SPDM_REQ_CONTEXT_SIZE);
580 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
581 2 : if (!libspdm_consttime_is_mem_equal((uint8_t *)spdm_request +
582 2 : spdm_request_size - SPDM_REQ_CONTEXT_SIZE,
583 : ptr, SPDM_REQ_CONTEXT_SIZE)) {
584 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
585 1 : goto receive_done;
586 : }
587 1 : ptr += SPDM_REQ_CONTEXT_SIZE;
588 : }
589 :
590 : /* If a signature is not requested then content_changed must be 0. */
591 216 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
592 4 : if ((spdm_response->header.param2 & SPDM_MEASUREMENTS_RESPONSE_CONTENT_CHANGE_MASK)
593 : != 0) {
594 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
595 1 : goto receive_done;
596 : }
597 : }
598 :
599 215 : status = libspdm_append_message_m(spdm_context, session_info, spdm_request,
600 : spdm_request_size);
601 215 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
602 0 : goto receive_done;
603 : }
604 :
605 215 : status = libspdm_append_message_m(spdm_context, session_info, spdm_response,
606 : spdm_response_size);
607 215 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
608 0 : goto receive_done;
609 : }
610 : }
611 :
612 225 : if (content_changed != NULL) {
613 0 : *content_changed = 0;
614 0 : if ((spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) &&
615 0 : ((request_attribute &
616 : SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE) != 0)) {
617 0 : *content_changed =
618 0 : (spdm_response->header.param2 & SPDM_MEASUREMENTS_RESPONSE_CONTENT_CHANGE_MASK);
619 : }
620 : }
621 225 : if (measurement_operation ==
622 : SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_TOTAL_NUMBER_OF_MEASUREMENTS) {
623 2 : *number_of_blocks = spdm_response->header.param1;
624 2 : if (*number_of_blocks == 0xFF) {
625 : /* the number of block cannot be 0xFF, because index 0xFF will brings confusing.*/
626 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
627 0 : goto receive_done;
628 : }
629 2 : if (*number_of_blocks == 0x0) {
630 : /* the number of block cannot be 0x0, because a responder without measurement should clear capability flags.*/
631 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
632 0 : goto receive_done;
633 : }
634 : } else {
635 223 : *number_of_blocks = spdm_response->number_of_blocks;
636 223 : if (*measurement_record_length < measurement_record_data_length) {
637 0 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
638 0 : goto receive_done;
639 : }
640 223 : if (measurement_record_data_length < sizeof(spdm_measurement_block_common_header_t)) {
641 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
642 0 : goto receive_done;
643 : }
644 :
645 223 : measurement_block_size = 0;
646 223 : measurement_block_count = 1;
647 442 : while (measurement_block_size < measurement_record_data_length) {
648 225 : measurement_block_header =
649 225 : (spdm_measurement_block_common_header_t *)&measurement_record_data
650 : [measurement_block_size];
651 225 : if (measurement_block_header->measurement_size >
652 225 : measurement_record_data_length -
653 225 : ((uint8_t *)measurement_block_header -
654 : (uint8_t *)measurement_record_data)) {
655 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
656 0 : goto receive_done;
657 : }
658 225 : if (measurement_block_header->measurement_specification == 0 ||
659 225 : (measurement_block_header->measurement_specification &
660 225 : (measurement_block_header->measurement_specification - 1))) {
661 4 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
662 4 : goto receive_done;
663 : }
664 221 : if (measurement_block_header->measurement_specification !=
665 221 : spdm_context->connection_info.algorithm.measurement_spec) {
666 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
667 2 : goto receive_done;
668 : }
669 219 : if (measurement_block_header->index == 0 || measurement_block_header->index == 0xFF) {
670 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
671 0 : goto receive_done;
672 : }
673 219 : if (measurement_operation !=
674 : SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_ALL_MEASUREMENTS) {
675 215 : if (measurement_block_header->index != measurement_operation) {
676 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
677 0 : goto receive_done;
678 : }
679 : }
680 219 : if (measurement_block_count > *number_of_blocks) {
681 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
682 0 : goto receive_done;
683 : }
684 219 : measurement_block_count++;
685 219 : measurement_block_size = (uint32_t)(
686 : measurement_block_size +
687 219 : sizeof(spdm_measurement_block_common_header_t) +
688 219 : measurement_block_header->measurement_size);
689 : }
690 :
691 217 : if (measurement_block_size != measurement_record_data_length) {
692 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
693 0 : goto receive_done;
694 : }
695 :
696 217 : *measurement_record_length = measurement_record_data_length;
697 217 : libspdm_copy_mem(measurement_record,
698 : measurement_record_data_length,
699 : measurement_record_data,
700 : measurement_record_data_length);
701 : }
702 :
703 219 : status = LIBSPDM_STATUS_SUCCESS;
704 :
705 : /* -=[Log Message Phase]=- */
706 : #if LIBSPDM_ENABLE_MSG_LOG
707 219 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
708 : #endif /* LIBSPDM_ENABLE_MSG_LOG */
709 :
710 298 : receive_done:
711 298 : if ((status != LIBSPDM_STATUS_SUCCESS) &&
712 : (status != LIBSPDM_STATUS_NOT_READY_PEER)) {
713 77 : libspdm_reset_message_m(spdm_context, session_info);
714 : }
715 298 : libspdm_release_receiver_buffer (spdm_context);
716 298 : return status;
717 : }
718 :
719 301 : libspdm_return_t libspdm_get_measurement(void *spdm_context, const uint32_t *session_id,
720 : uint8_t request_attribute,
721 : uint8_t measurement_operation,
722 : uint8_t slot_id_param,
723 : uint8_t *content_changed,
724 : uint8_t *number_of_blocks,
725 : uint32_t *measurement_record_length,
726 : void *measurement_record)
727 : {
728 : libspdm_context_t *context;
729 : size_t retry;
730 : uint64_t retry_delay_time;
731 : libspdm_return_t status;
732 :
733 301 : context = spdm_context;
734 301 : context->crypto_request = true;
735 301 : retry = context->retry_times;
736 301 : retry_delay_time = context->retry_delay_time;
737 : do {
738 302 : status = libspdm_try_get_measurement(
739 : context, session_id, request_attribute,
740 : measurement_operation, slot_id_param, NULL, content_changed, number_of_blocks,
741 : measurement_record_length, measurement_record,
742 : NULL, NULL, NULL, NULL, NULL);
743 302 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
744 299 : return status;
745 : }
746 :
747 3 : libspdm_sleep(retry_delay_time);
748 3 : } while (retry-- != 0);
749 :
750 2 : return status;
751 : }
752 :
753 2 : libspdm_return_t libspdm_get_measurement_ex(void *spdm_context, const uint32_t *session_id,
754 : uint8_t request_attribute,
755 : uint8_t measurement_operation,
756 : uint8_t slot_id_param,
757 : uint8_t *content_changed,
758 : uint8_t *number_of_blocks,
759 : uint32_t *measurement_record_length,
760 : void *measurement_record,
761 : const void *requester_nonce_in,
762 : void *requester_nonce,
763 : void *responder_nonce,
764 : void *opaque_data,
765 : size_t *opaque_data_size)
766 : {
767 : libspdm_context_t *context;
768 : size_t retry;
769 : uint64_t retry_delay_time;
770 : libspdm_return_t status;
771 :
772 2 : context = spdm_context;
773 2 : context->crypto_request = true;
774 2 : retry = context->retry_times;
775 2 : retry_delay_time = context->retry_delay_time;
776 : do {
777 2 : status = libspdm_try_get_measurement(
778 : context, session_id, request_attribute,
779 : measurement_operation, slot_id_param, NULL, content_changed, number_of_blocks,
780 : measurement_record_length, measurement_record,
781 : requester_nonce_in,
782 : requester_nonce, responder_nonce,
783 : opaque_data, opaque_data_size);
784 2 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
785 2 : return status;
786 : }
787 :
788 0 : libspdm_sleep(retry_delay_time);
789 0 : } while (retry-- != 0);
790 :
791 0 : return status;
792 : }
793 :
794 2 : libspdm_return_t libspdm_get_measurement_ex2(void *spdm_context, const uint32_t *session_id,
795 : uint8_t request_attribute,
796 : uint8_t measurement_operation,
797 : uint8_t slot_id_param,
798 : const void *requester_context,
799 : uint8_t *content_changed,
800 : uint8_t *number_of_blocks,
801 : uint32_t *measurement_record_length,
802 : void *measurement_record,
803 : const void *requester_nonce_in,
804 : void *requester_nonce,
805 : void *responder_nonce,
806 : void *opaque_data,
807 : size_t *opaque_data_size)
808 : {
809 : libspdm_context_t *context;
810 : size_t retry;
811 : uint64_t retry_delay_time;
812 : libspdm_return_t status;
813 :
814 2 : context = spdm_context;
815 2 : context->crypto_request = true;
816 2 : retry = context->retry_times;
817 2 : retry_delay_time = context->retry_delay_time;
818 : do {
819 2 : status = libspdm_try_get_measurement(
820 : context, session_id, request_attribute,
821 : measurement_operation, slot_id_param, requester_context,
822 : content_changed, number_of_blocks,
823 : measurement_record_length, measurement_record,
824 : requester_nonce_in,
825 : requester_nonce, responder_nonce,
826 : opaque_data, opaque_data_size);
827 2 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
828 2 : return status;
829 : }
830 :
831 0 : libspdm_sleep(retry_delay_time);
832 0 : } while (retry-- != 0);
833 :
834 0 : return status;
835 : }
836 :
837 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP*/
|