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