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 (spdm_response_size <
465 : sizeof(spdm_measurements_response_t) + measurement_record_data_length +
466 22 : SPDM_NONCE_SIZE + sizeof(uint16_t) + opaque_length) {
467 2 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
468 2 : goto receive_done;
469 : }
470 20 : if (opaque_length != 0) {
471 7 : result = libspdm_process_general_opaque_data_check(spdm_context, opaque_length, ptr);
472 7 : if (!result) {
473 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
474 0 : goto receive_done;
475 : }
476 : }
477 :
478 20 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
479 0 : if (spdm_response_size <
480 : sizeof(spdm_measurements_response_t) +
481 : measurement_record_data_length + SPDM_NONCE_SIZE +
482 0 : sizeof(uint16_t) + opaque_length + SPDM_REQ_CONTEXT_SIZE + signature_size) {
483 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
484 0 : goto receive_done;
485 : }
486 0 : spdm_response_size = sizeof(spdm_measurements_response_t) +
487 : measurement_record_data_length +
488 0 : SPDM_NONCE_SIZE + sizeof(uint16_t) +
489 0 : opaque_length + SPDM_REQ_CONTEXT_SIZE + signature_size;
490 : } else {
491 20 : if (spdm_response_size <
492 : sizeof(spdm_measurements_response_t) +
493 : measurement_record_data_length + SPDM_NONCE_SIZE +
494 20 : sizeof(uint16_t) + opaque_length + signature_size) {
495 4 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
496 4 : goto receive_done;
497 : }
498 16 : spdm_response_size = sizeof(spdm_measurements_response_t) +
499 : measurement_record_data_length +
500 16 : SPDM_NONCE_SIZE + sizeof(uint16_t) +
501 16 : opaque_length + signature_size;
502 : }
503 :
504 16 : if ((opaque_data != NULL) && (opaque_data_size != NULL)) {
505 2 : if (opaque_length >= *opaque_data_size) {
506 0 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
507 0 : goto receive_done;
508 : }
509 2 : libspdm_copy_mem(opaque_data, *opaque_data_size, ptr, opaque_length);
510 2 : *opaque_data_size = opaque_length;
511 : }
512 16 : ptr += opaque_length;
513 16 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
514 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "RequesterContext - "));
515 0 : LIBSPDM_INTERNAL_DUMP_DATA(ptr, SPDM_REQ_CONTEXT_SIZE);
516 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
517 0 : if (!libspdm_consttime_is_mem_equal((uint8_t *)spdm_request +
518 0 : spdm_request_size - SPDM_REQ_CONTEXT_SIZE,
519 : ptr, SPDM_REQ_CONTEXT_SIZE)) {
520 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
521 0 : goto receive_done;
522 : }
523 0 : ptr += SPDM_REQ_CONTEXT_SIZE;
524 : }
525 :
526 : /* -=[Process Response Phase]=- */
527 16 : status = libspdm_append_message_m(spdm_context, session_info, spdm_request,
528 : spdm_request_size);
529 16 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
530 0 : goto receive_done;
531 : }
532 :
533 16 : status = libspdm_append_message_m(spdm_context, session_info, spdm_response,
534 : spdm_response_size - signature_size);
535 16 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
536 0 : goto receive_done;
537 : }
538 :
539 16 : signature = ptr;
540 16 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "signature (0x%zx):\n", signature_size));
541 16 : LIBSPDM_INTERNAL_DUMP_HEX(signature, signature_size);
542 :
543 16 : result = libspdm_verify_measurement_signature(
544 : spdm_context, session_info, slot_id_param, signature, signature_size);
545 16 : if (!result) {
546 6 : status = LIBSPDM_STATUS_VERIF_FAIL;
547 6 : goto receive_done;
548 : }
549 :
550 10 : libspdm_reset_message_m(spdm_context, session_info);
551 : } else {
552 219 : if (spdm_response_size <
553 : sizeof(spdm_measurements_response_t) +
554 219 : measurement_record_data_length + SPDM_NONCE_SIZE + sizeof(uint16_t)) {
555 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
556 0 : goto receive_done;
557 : }
558 219 : ptr = measurement_record_data + measurement_record_data_length;
559 :
560 219 : nonce = ptr;
561 219 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "nonce (0x%x) - ", SPDM_NONCE_SIZE));
562 219 : LIBSPDM_INTERNAL_DUMP_DATA(nonce, SPDM_NONCE_SIZE);
563 219 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
564 219 : ptr += SPDM_NONCE_SIZE;
565 219 : if (responder_nonce != NULL) {
566 0 : libspdm_copy_mem(responder_nonce, SPDM_NONCE_SIZE, nonce, SPDM_NONCE_SIZE);
567 : }
568 :
569 219 : opaque_length = libspdm_read_uint16((const uint8_t *)ptr);
570 219 : if (opaque_length > SPDM_MAX_OPAQUE_DATA_SIZE) {
571 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
572 2 : goto receive_done;
573 : }
574 217 : ptr += sizeof(uint16_t);
575 217 : if (spdm_response_size <
576 : sizeof(spdm_measurements_response_t) + measurement_record_data_length +
577 217 : SPDM_NONCE_SIZE + sizeof(uint16_t) + opaque_length) {
578 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
579 0 : goto receive_done;
580 : }
581 217 : if (opaque_length != 0) {
582 3 : result = libspdm_process_general_opaque_data_check(spdm_context, opaque_length, ptr);
583 3 : if (!result) {
584 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
585 0 : goto receive_done;
586 : }
587 : }
588 :
589 217 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
590 2 : if (spdm_response_size <
591 : sizeof(spdm_measurements_response_t) +
592 : measurement_record_data_length + SPDM_NONCE_SIZE +
593 2 : sizeof(uint16_t) + opaque_length + SPDM_REQ_CONTEXT_SIZE) {
594 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
595 0 : goto receive_done;
596 : }
597 2 : spdm_response_size = sizeof(spdm_measurements_response_t) +
598 : measurement_record_data_length +
599 2 : SPDM_NONCE_SIZE + sizeof(uint16_t) +
600 2 : opaque_length + SPDM_REQ_CONTEXT_SIZE;
601 : } else {
602 215 : if (spdm_response_size <
603 : sizeof(spdm_measurements_response_t) +
604 : measurement_record_data_length + SPDM_NONCE_SIZE +
605 215 : sizeof(uint16_t) + opaque_length) {
606 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
607 0 : goto receive_done;
608 : }
609 215 : spdm_response_size = sizeof(spdm_measurements_response_t) +
610 : measurement_record_data_length +
611 215 : SPDM_NONCE_SIZE + sizeof(uint16_t) +
612 : opaque_length;
613 : }
614 :
615 217 : if ((opaque_data != NULL) && (opaque_data_size != NULL)) {
616 0 : if (opaque_length >= *opaque_data_size) {
617 0 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
618 0 : goto receive_done;
619 : }
620 0 : libspdm_copy_mem(opaque_data, *opaque_data_size, ptr, opaque_length);
621 0 : *opaque_data_size = opaque_length;
622 : }
623 217 : ptr += opaque_length;
624 217 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
625 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "RequesterContext - "));
626 2 : LIBSPDM_INTERNAL_DUMP_DATA(ptr, SPDM_REQ_CONTEXT_SIZE);
627 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
628 2 : if (!libspdm_consttime_is_mem_equal((uint8_t *)spdm_request +
629 2 : spdm_request_size - SPDM_REQ_CONTEXT_SIZE,
630 : ptr, SPDM_REQ_CONTEXT_SIZE)) {
631 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
632 1 : goto receive_done;
633 : }
634 1 : ptr += SPDM_REQ_CONTEXT_SIZE;
635 : }
636 :
637 : /* If a signature is not requested then content_changed must be 0. */
638 216 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
639 4 : if ((spdm_response->header.param2 & SPDM_MEASUREMENTS_RESPONSE_CONTENT_CHANGE_MASK)
640 : != 0) {
641 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
642 1 : goto receive_done;
643 : }
644 : }
645 :
646 215 : status = libspdm_append_message_m(spdm_context, session_info, spdm_request,
647 : spdm_request_size);
648 215 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
649 0 : goto receive_done;
650 : }
651 :
652 215 : status = libspdm_append_message_m(spdm_context, session_info, spdm_response,
653 : spdm_response_size);
654 215 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
655 0 : goto receive_done;
656 : }
657 : }
658 :
659 225 : if (content_changed != NULL) {
660 0 : *content_changed = 0;
661 0 : if ((spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) &&
662 0 : ((request_attribute &
663 : SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE) != 0)) {
664 0 : *content_changed =
665 0 : (spdm_response->header.param2 & SPDM_MEASUREMENTS_RESPONSE_CONTENT_CHANGE_MASK);
666 : }
667 : }
668 225 : if (measurement_operation ==
669 : SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_TOTAL_NUMBER_OF_MEASUREMENTS) {
670 2 : *number_of_blocks = spdm_response->header.param1;
671 2 : if (*number_of_blocks == 0xFF) {
672 : /* the number of block cannot be 0xFF, because index 0xFF will brings confusing.*/
673 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
674 0 : goto receive_done;
675 : }
676 2 : if (*number_of_blocks == 0x0) {
677 : /* the number of block cannot be 0x0, because a responder without measurement should clear capability flags.*/
678 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
679 0 : goto receive_done;
680 : }
681 : } else {
682 223 : *number_of_blocks = spdm_response->number_of_blocks;
683 223 : if (*measurement_record_length < measurement_record_data_length) {
684 0 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
685 0 : goto receive_done;
686 : }
687 223 : if (measurement_record_data_length < sizeof(spdm_measurement_block_common_header_t)) {
688 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
689 0 : goto receive_done;
690 : }
691 :
692 223 : measurement_block_size = 0;
693 223 : measurement_block_count = 1;
694 442 : while (measurement_block_size < measurement_record_data_length) {
695 225 : measurement_block_header =
696 225 : (spdm_measurement_block_common_header_t *)&measurement_record_data
697 : [measurement_block_size];
698 225 : if (measurement_block_header->measurement_size >
699 225 : measurement_record_data_length -
700 225 : ((uint8_t *)measurement_block_header -
701 : (uint8_t *)measurement_record_data)) {
702 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
703 0 : goto receive_done;
704 : }
705 225 : if (measurement_block_header->measurement_specification == 0 ||
706 225 : (measurement_block_header->measurement_specification &
707 225 : (measurement_block_header->measurement_specification - 1))) {
708 4 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
709 4 : goto receive_done;
710 : }
711 221 : if (measurement_block_header->measurement_specification !=
712 221 : spdm_context->connection_info.algorithm.measurement_spec) {
713 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
714 2 : goto receive_done;
715 : }
716 219 : if (measurement_block_header->index == 0 || measurement_block_header->index == 0xFF) {
717 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
718 0 : goto receive_done;
719 : }
720 219 : if (measurement_operation !=
721 : SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_ALL_MEASUREMENTS) {
722 215 : if (measurement_block_header->index != measurement_operation) {
723 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
724 0 : goto receive_done;
725 : }
726 : }
727 219 : if (measurement_block_count > *number_of_blocks) {
728 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
729 0 : goto receive_done;
730 : }
731 219 : measurement_block_count++;
732 219 : measurement_block_size = (uint32_t)(
733 : measurement_block_size +
734 219 : sizeof(spdm_measurement_block_common_header_t) +
735 219 : measurement_block_header->measurement_size);
736 : }
737 :
738 217 : if (measurement_block_size != measurement_record_data_length) {
739 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
740 0 : goto receive_done;
741 : }
742 :
743 217 : *measurement_record_length = measurement_record_data_length;
744 217 : libspdm_copy_mem(measurement_record,
745 : measurement_record_data_length,
746 : measurement_record_data,
747 : measurement_record_data_length);
748 : }
749 :
750 219 : status = LIBSPDM_STATUS_SUCCESS;
751 :
752 : /* -=[Log Message Phase]=- */
753 : #if LIBSPDM_ENABLE_MSG_LOG
754 219 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
755 : #endif /* LIBSPDM_ENABLE_MSG_LOG */
756 :
757 298 : receive_done:
758 298 : if ((status != LIBSPDM_STATUS_SUCCESS) &&
759 : (status != LIBSPDM_STATUS_NOT_READY_PEER)) {
760 77 : libspdm_reset_message_m(spdm_context, session_info);
761 : }
762 298 : libspdm_release_receiver_buffer (spdm_context);
763 298 : return status;
764 : }
765 :
766 301 : libspdm_return_t libspdm_get_measurement(void *spdm_context, const uint32_t *session_id,
767 : uint8_t request_attribute,
768 : uint8_t measurement_operation,
769 : uint8_t slot_id_param,
770 : uint8_t *content_changed,
771 : uint8_t *number_of_blocks,
772 : uint32_t *measurement_record_length,
773 : void *measurement_record)
774 : {
775 : libspdm_context_t *context;
776 : size_t retry;
777 : uint64_t retry_delay_time;
778 : libspdm_return_t status;
779 :
780 301 : context = spdm_context;
781 301 : context->crypto_request = true;
782 301 : retry = context->retry_times;
783 301 : retry_delay_time = context->retry_delay_time;
784 : do {
785 302 : status = libspdm_try_get_measurement(
786 : context, session_id, request_attribute,
787 : measurement_operation, slot_id_param, NULL, content_changed, number_of_blocks,
788 : measurement_record_length, measurement_record,
789 : NULL, NULL, NULL, NULL, NULL);
790 302 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
791 299 : return status;
792 : }
793 :
794 3 : libspdm_sleep(retry_delay_time);
795 3 : } while (retry-- != 0);
796 :
797 2 : return status;
798 : }
799 :
800 2 : libspdm_return_t libspdm_get_measurement_ex(void *spdm_context, const uint32_t *session_id,
801 : uint8_t request_attribute,
802 : uint8_t measurement_operation,
803 : uint8_t slot_id_param,
804 : uint8_t *content_changed,
805 : uint8_t *number_of_blocks,
806 : uint32_t *measurement_record_length,
807 : void *measurement_record,
808 : const void *requester_nonce_in,
809 : void *requester_nonce,
810 : void *responder_nonce,
811 : void *opaque_data,
812 : size_t *opaque_data_size)
813 : {
814 : libspdm_context_t *context;
815 : size_t retry;
816 : uint64_t retry_delay_time;
817 : libspdm_return_t status;
818 :
819 2 : context = spdm_context;
820 2 : context->crypto_request = true;
821 2 : retry = context->retry_times;
822 2 : retry_delay_time = context->retry_delay_time;
823 : do {
824 2 : status = libspdm_try_get_measurement(
825 : context, session_id, request_attribute,
826 : measurement_operation, slot_id_param, NULL, content_changed, number_of_blocks,
827 : measurement_record_length, measurement_record,
828 : requester_nonce_in,
829 : requester_nonce, responder_nonce,
830 : opaque_data, opaque_data_size);
831 2 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
832 2 : return status;
833 : }
834 :
835 0 : libspdm_sleep(retry_delay_time);
836 0 : } while (retry-- != 0);
837 :
838 0 : return status;
839 : }
840 :
841 2 : libspdm_return_t libspdm_get_measurement_ex2(void *spdm_context, const uint32_t *session_id,
842 : uint8_t request_attribute,
843 : uint8_t measurement_operation,
844 : uint8_t slot_id_param,
845 : const void *requester_context,
846 : uint8_t *content_changed,
847 : uint8_t *number_of_blocks,
848 : uint32_t *measurement_record_length,
849 : void *measurement_record,
850 : const void *requester_nonce_in,
851 : void *requester_nonce,
852 : void *responder_nonce,
853 : void *opaque_data,
854 : size_t *opaque_data_size)
855 : {
856 : libspdm_context_t *context;
857 : size_t retry;
858 : uint64_t retry_delay_time;
859 : libspdm_return_t status;
860 :
861 2 : context = spdm_context;
862 2 : context->crypto_request = true;
863 2 : retry = context->retry_times;
864 2 : retry_delay_time = context->retry_delay_time;
865 : do {
866 2 : status = libspdm_try_get_measurement(
867 : context, session_id, request_attribute,
868 : measurement_operation, slot_id_param, requester_context,
869 : content_changed, number_of_blocks,
870 : measurement_record_length, measurement_record,
871 : requester_nonce_in,
872 : requester_nonce, responder_nonce,
873 : opaque_data, opaque_data_size);
874 2 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
875 2 : return status;
876 : }
877 :
878 0 : libspdm_sleep(retry_delay_time);
879 0 : } while (retry-- != 0);
880 :
881 0 : return status;
882 : }
883 :
884 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP*/
|