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