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 : 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 : spdm_context->connection_info.peer_used_cert_chain_slot_id = slot_id_param;
261 302 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
262 302 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
263 302 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
264 1 : return status;
265 : }
266 301 : LIBSPDM_ASSERT (message_size >= transport_header_size +
267 : spdm_context->local_context.capability.transport_tail_size);
268 301 : spdm_request = (void *)(message + transport_header_size);
269 301 : spdm_request_size = message_size - transport_header_size -
270 301 : spdm_context->local_context.capability.transport_tail_size;
271 :
272 301 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_request->header));
273 301 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
274 301 : spdm_request->header.request_response_code = SPDM_GET_MEASUREMENTS;
275 301 : spdm_request->header.param1 = request_attribute;
276 301 : spdm_request->header.param2 = measurement_operation;
277 301 : if ((request_attribute & SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE) != 0) {
278 75 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
279 0 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_get_measurements_request_t) +
280 : SPDM_REQ_CONTEXT_SIZE);
281 0 : spdm_request_size = sizeof(spdm_get_measurements_request_t) + SPDM_REQ_CONTEXT_SIZE;
282 75 : } else if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
283 75 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_get_measurements_request_t));
284 75 : spdm_request_size = sizeof(spdm_get_measurements_request_t);
285 : } else {
286 0 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_get_measurements_request_t) -
287 : sizeof(spdm_request->slot_id_param));
288 0 : spdm_request_size = sizeof(spdm_get_measurements_request_t) -
289 : sizeof(spdm_request->slot_id_param);
290 : }
291 :
292 75 : if (requester_nonce_in == NULL) {
293 73 : if (!libspdm_get_random_number(SPDM_NONCE_SIZE, spdm_request->nonce)) {
294 0 : libspdm_release_sender_buffer (spdm_context);
295 0 : return LIBSPDM_STATUS_LOW_ENTROPY;
296 : }
297 : } else {
298 2 : libspdm_copy_mem(spdm_request->nonce, sizeof(spdm_request->nonce),
299 : requester_nonce_in, SPDM_NONCE_SIZE);
300 : }
301 75 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "RequesterNonce - "));
302 75 : LIBSPDM_INTERNAL_DUMP_DATA(spdm_request->nonce, SPDM_NONCE_SIZE);
303 75 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
304 75 : spdm_request->slot_id_param = slot_id_param;
305 :
306 75 : if (requester_nonce != NULL) {
307 2 : libspdm_copy_mem(requester_nonce, SPDM_NONCE_SIZE,
308 2 : spdm_request->nonce, SPDM_NONCE_SIZE);
309 : }
310 : } else {
311 226 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
312 2 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_request->header) +
313 : SPDM_REQ_CONTEXT_SIZE);
314 2 : spdm_request_size = sizeof(spdm_request->header) + SPDM_REQ_CONTEXT_SIZE;
315 : } else {
316 224 : spdm_request_size = sizeof(spdm_request->header);
317 : }
318 :
319 226 : if (requester_nonce != NULL) {
320 0 : libspdm_zero_mem (requester_nonce, SPDM_NONCE_SIZE);
321 : }
322 : }
323 301 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
324 2 : if (requester_context == NULL) {
325 0 : libspdm_zero_mem((uint8_t *)spdm_request + spdm_request_size - SPDM_REQ_CONTEXT_SIZE,
326 : SPDM_REQ_CONTEXT_SIZE);
327 : } else {
328 2 : libspdm_copy_mem((uint8_t *)spdm_request + spdm_request_size - SPDM_REQ_CONTEXT_SIZE,
329 : SPDM_REQ_CONTEXT_SIZE,
330 : requester_context, SPDM_REQ_CONTEXT_SIZE);
331 : }
332 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "RequesterContext - "));
333 2 : LIBSPDM_INTERNAL_DUMP_DATA((uint8_t *)spdm_request + spdm_request_size -
334 : SPDM_REQ_CONTEXT_SIZE,
335 : SPDM_REQ_CONTEXT_SIZE);
336 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
337 : }
338 :
339 : /* -=[Send Request Phase]=- */
340 301 : status = libspdm_send_spdm_request(spdm_context, session_id, spdm_request_size, spdm_request);
341 301 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
342 2 : libspdm_release_sender_buffer (spdm_context);
343 2 : return status;
344 : }
345 299 : libspdm_release_sender_buffer (spdm_context);
346 299 : spdm_request = (void *)spdm_context->last_spdm_request;
347 :
348 : /* -=[Receive Response Phase]=- */
349 299 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
350 299 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
351 1 : return status;
352 : }
353 298 : LIBSPDM_ASSERT (message_size >= transport_header_size);
354 298 : spdm_response = (void *)(message);
355 298 : spdm_response_size = message_size;
356 :
357 298 : status = libspdm_receive_spdm_response(
358 : spdm_context, session_id, &spdm_response_size, (void **)&spdm_response);
359 298 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
360 1 : goto receive_done;
361 : }
362 :
363 : /* -=[Validate Response Phase]=- */
364 297 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
365 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
366 0 : goto receive_done;
367 : }
368 297 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
369 46 : status = libspdm_handle_error_response_main(
370 : spdm_context, session_id,
371 : &spdm_response_size, (void **)&spdm_response,
372 : SPDM_GET_MEASUREMENTS, SPDM_MEASUREMENTS);
373 46 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
374 45 : goto receive_done;
375 : }
376 251 : } else if (spdm_response->header.request_response_code != SPDM_MEASUREMENTS) {
377 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
378 2 : goto receive_done;
379 : }
380 250 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
381 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
382 0 : goto receive_done;
383 : }
384 250 : if (spdm_response_size < sizeof(spdm_measurements_response_t)) {
385 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
386 0 : goto receive_done;
387 : }
388 250 : if (measurement_operation ==
389 : SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_TOTAL_NUMBER_OF_MEASUREMENTS) {
390 8 : if (spdm_response->number_of_blocks != 0) {
391 4 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
392 4 : goto receive_done;
393 : }
394 242 : } else if (measurement_operation ==
395 : SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_ALL_MEASUREMENTS) {
396 2 : if ((spdm_response->number_of_blocks == 0) || (spdm_response->number_of_blocks == 0xff)) {
397 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
398 0 : goto receive_done;
399 : }
400 : } else {
401 240 : if (spdm_response->number_of_blocks != 1) {
402 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
403 0 : goto receive_done;
404 : }
405 : }
406 :
407 246 : measurement_record_data_length = libspdm_read_uint24(spdm_response->measurement_record_length);
408 246 : if (measurement_operation ==
409 : SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_TOTAL_NUMBER_OF_MEASUREMENTS) {
410 4 : if (measurement_record_data_length != 0) {
411 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
412 2 : goto receive_done;
413 : }
414 : } else {
415 242 : if (spdm_response_size <
416 242 : sizeof(spdm_measurements_response_t) +
417 : measurement_record_data_length) {
418 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
419 0 : goto receive_done;
420 : }
421 242 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "measurement_record_length - 0x%06x\n",
422 : measurement_record_data_length));
423 : }
424 :
425 244 : measurement_record_data = (void *)(spdm_response + 1);
426 :
427 244 : if ((request_attribute & SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE) != 0) {
428 25 : if (spdm_response_size <
429 : sizeof(spdm_measurements_response_t) +
430 25 : measurement_record_data_length + SPDM_NONCE_SIZE + sizeof(uint16_t)) {
431 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
432 0 : goto receive_done;
433 : }
434 25 : if ((spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_11) &&
435 25 : ((spdm_response->header.param2 & SPDM_MEASUREMENTS_RESPONSE_SLOT_ID_MASK)
436 25 : != slot_id_param)) {
437 3 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
438 3 : goto receive_done;
439 : }
440 22 : ptr = measurement_record_data + measurement_record_data_length;
441 22 : nonce = ptr;
442 22 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "nonce (0x%x) - ", SPDM_NONCE_SIZE));
443 22 : LIBSPDM_INTERNAL_DUMP_DATA(nonce, SPDM_NONCE_SIZE);
444 22 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
445 22 : ptr += SPDM_NONCE_SIZE;
446 22 : if (responder_nonce != NULL) {
447 2 : libspdm_copy_mem(responder_nonce, SPDM_NONCE_SIZE, nonce, SPDM_NONCE_SIZE);
448 : }
449 :
450 22 : opaque_length = libspdm_read_uint16((const uint8_t *)ptr);
451 22 : if (opaque_length > SPDM_MAX_OPAQUE_DATA_SIZE) {
452 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
453 0 : goto receive_done;
454 : }
455 22 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
456 3 : if (((spdm_context->connection_info.algorithm.other_params_support &
457 : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) ==
458 : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_NONE)
459 2 : && (opaque_length != 0)) {
460 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
461 0 : goto receive_done;
462 : }
463 : }
464 22 : ptr += sizeof(uint16_t);
465 22 : if (opaque_length != 0) {
466 9 : result = libspdm_process_general_opaque_data_check(spdm_context, opaque_length, ptr);
467 9 : if (!result) {
468 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
469 0 : goto receive_done;
470 : }
471 : }
472 :
473 22 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
474 0 : if (spdm_response_size <
475 : sizeof(spdm_measurements_response_t) +
476 : measurement_record_data_length + SPDM_NONCE_SIZE +
477 0 : sizeof(uint16_t) + opaque_length + SPDM_REQ_CONTEXT_SIZE + signature_size) {
478 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
479 0 : goto receive_done;
480 : }
481 0 : spdm_response_size = sizeof(spdm_measurements_response_t) +
482 : measurement_record_data_length +
483 0 : SPDM_NONCE_SIZE + sizeof(uint16_t) +
484 0 : opaque_length + SPDM_REQ_CONTEXT_SIZE + signature_size;
485 : } else {
486 22 : if (spdm_response_size <
487 : sizeof(spdm_measurements_response_t) +
488 : measurement_record_data_length + SPDM_NONCE_SIZE +
489 22 : sizeof(uint16_t) + opaque_length + signature_size) {
490 6 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
491 6 : goto receive_done;
492 : }
493 16 : spdm_response_size = sizeof(spdm_measurements_response_t) +
494 : measurement_record_data_length +
495 16 : SPDM_NONCE_SIZE + sizeof(uint16_t) +
496 16 : opaque_length + signature_size;
497 : }
498 :
499 16 : if ((opaque_data != NULL) && (opaque_data_size != NULL)) {
500 2 : if (opaque_length >= *opaque_data_size) {
501 0 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
502 0 : goto receive_done;
503 : }
504 2 : libspdm_copy_mem(opaque_data, *opaque_data_size, ptr, opaque_length);
505 2 : *opaque_data_size = opaque_length;
506 : }
507 16 : ptr += opaque_length;
508 16 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
509 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "RequesterContext - "));
510 0 : LIBSPDM_INTERNAL_DUMP_DATA(ptr, SPDM_REQ_CONTEXT_SIZE);
511 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
512 0 : if (!libspdm_consttime_is_mem_equal((uint8_t *)spdm_request +
513 0 : spdm_request_size - SPDM_REQ_CONTEXT_SIZE,
514 : ptr, SPDM_REQ_CONTEXT_SIZE)) {
515 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
516 0 : goto receive_done;
517 : }
518 0 : ptr += SPDM_REQ_CONTEXT_SIZE;
519 : }
520 :
521 : /* -=[Process Response Phase]=- */
522 16 : status = libspdm_append_message_m(spdm_context, session_info, spdm_request,
523 : spdm_request_size);
524 16 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
525 0 : goto receive_done;
526 : }
527 :
528 16 : status = libspdm_append_message_m(spdm_context, session_info, spdm_response,
529 : spdm_response_size - signature_size);
530 16 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
531 0 : goto receive_done;
532 : }
533 :
534 16 : signature = ptr;
535 16 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "signature (0x%zx):\n", signature_size));
536 16 : LIBSPDM_INTERNAL_DUMP_HEX(signature, signature_size);
537 :
538 16 : result = libspdm_verify_measurement_signature(
539 : spdm_context, session_info, signature, signature_size);
540 16 : if (!result) {
541 6 : status = LIBSPDM_STATUS_VERIF_FAIL;
542 6 : goto receive_done;
543 : }
544 :
545 10 : libspdm_reset_message_m(spdm_context, session_info);
546 : } else {
547 219 : if (spdm_response_size <
548 : sizeof(spdm_measurements_response_t) +
549 219 : measurement_record_data_length + sizeof(uint16_t)) {
550 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
551 0 : goto receive_done;
552 : }
553 219 : ptr = measurement_record_data + measurement_record_data_length;
554 :
555 219 : nonce = ptr;
556 219 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "nonce (0x%x) - ", SPDM_NONCE_SIZE));
557 219 : LIBSPDM_INTERNAL_DUMP_DATA(nonce, SPDM_NONCE_SIZE);
558 219 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
559 219 : ptr += SPDM_NONCE_SIZE;
560 219 : if (responder_nonce != NULL) {
561 0 : libspdm_copy_mem(responder_nonce, SPDM_NONCE_SIZE, nonce, SPDM_NONCE_SIZE);
562 : }
563 :
564 219 : opaque_length = libspdm_read_uint16((const uint8_t *)ptr);
565 219 : if (opaque_length > SPDM_MAX_OPAQUE_DATA_SIZE) {
566 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
567 2 : goto receive_done;
568 : }
569 217 : ptr += sizeof(uint16_t);
570 217 : if (opaque_length != 0) {
571 3 : result = libspdm_process_general_opaque_data_check(spdm_context, opaque_length, ptr);
572 3 : if (!result) {
573 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
574 0 : goto receive_done;
575 : }
576 : }
577 :
578 217 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
579 2 : if (spdm_response_size <
580 : sizeof(spdm_measurements_response_t) +
581 : measurement_record_data_length + SPDM_NONCE_SIZE +
582 2 : sizeof(uint16_t) + opaque_length + SPDM_REQ_CONTEXT_SIZE) {
583 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
584 0 : goto receive_done;
585 : }
586 2 : spdm_response_size = sizeof(spdm_measurements_response_t) +
587 : measurement_record_data_length +
588 2 : SPDM_NONCE_SIZE + sizeof(uint16_t) +
589 2 : opaque_length + SPDM_REQ_CONTEXT_SIZE;
590 : } else {
591 215 : if (spdm_response_size <
592 : sizeof(spdm_measurements_response_t) +
593 : measurement_record_data_length + SPDM_NONCE_SIZE +
594 215 : sizeof(uint16_t) + opaque_length) {
595 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
596 0 : goto receive_done;
597 : }
598 215 : spdm_response_size = sizeof(spdm_measurements_response_t) +
599 : measurement_record_data_length +
600 215 : SPDM_NONCE_SIZE + sizeof(uint16_t) +
601 : opaque_length;
602 : }
603 :
604 217 : if ((opaque_data != NULL) && (opaque_data_size != NULL)) {
605 0 : if (opaque_length >= *opaque_data_size) {
606 0 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
607 0 : goto receive_done;
608 : }
609 0 : libspdm_copy_mem(opaque_data, *opaque_data_size, ptr, opaque_length);
610 0 : *opaque_data_size = opaque_length;
611 : }
612 217 : ptr += opaque_length;
613 217 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
614 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "RequesterContext - "));
615 2 : LIBSPDM_INTERNAL_DUMP_DATA(ptr, SPDM_REQ_CONTEXT_SIZE);
616 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
617 2 : if (!libspdm_consttime_is_mem_equal((uint8_t *)spdm_request +
618 2 : spdm_request_size - SPDM_REQ_CONTEXT_SIZE,
619 : ptr, SPDM_REQ_CONTEXT_SIZE)) {
620 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
621 1 : goto receive_done;
622 : }
623 1 : ptr += SPDM_REQ_CONTEXT_SIZE;
624 : }
625 :
626 : /* If a signature is not requested then content_changed must be 0. */
627 216 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
628 4 : if ((spdm_response->header.param2 & SPDM_MEASUREMENTS_RESPONSE_CONTENT_CHANGE_MASK)
629 : != 0) {
630 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
631 1 : goto receive_done;
632 : }
633 : }
634 :
635 215 : status = libspdm_append_message_m(spdm_context, session_info, spdm_request,
636 : spdm_request_size);
637 215 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
638 0 : goto receive_done;
639 : }
640 :
641 215 : status = libspdm_append_message_m(spdm_context, session_info, spdm_response,
642 : spdm_response_size);
643 215 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
644 0 : goto receive_done;
645 : }
646 : }
647 :
648 225 : if (content_changed != NULL) {
649 0 : *content_changed = 0;
650 0 : if ((spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) &&
651 0 : ((request_attribute &
652 : SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE) != 0)) {
653 0 : *content_changed =
654 0 : (spdm_response->header.param2 & SPDM_MEASUREMENTS_RESPONSE_CONTENT_CHANGE_MASK);
655 : }
656 : }
657 225 : if (measurement_operation ==
658 : SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_TOTAL_NUMBER_OF_MEASUREMENTS) {
659 2 : *number_of_blocks = spdm_response->header.param1;
660 2 : if (*number_of_blocks == 0xFF) {
661 : /* the number of block cannot be 0xFF, because index 0xFF will brings confusing.*/
662 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
663 0 : goto receive_done;
664 : }
665 2 : if (*number_of_blocks == 0x0) {
666 : /* the number of block cannot be 0x0, because a responder without measurement should clear capability flags.*/
667 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
668 0 : goto receive_done;
669 : }
670 : } else {
671 223 : *number_of_blocks = spdm_response->number_of_blocks;
672 223 : if (*measurement_record_length < measurement_record_data_length) {
673 0 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
674 0 : goto receive_done;
675 : }
676 223 : if (measurement_record_data_length < sizeof(spdm_measurement_block_common_header_t)) {
677 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
678 0 : goto receive_done;
679 : }
680 :
681 223 : measurement_block_size = 0;
682 223 : measurement_block_count = 1;
683 442 : while (measurement_block_size < measurement_record_data_length) {
684 225 : measurement_block_header =
685 225 : (spdm_measurement_block_common_header_t *)&measurement_record_data
686 : [measurement_block_size];
687 225 : if (measurement_block_header->measurement_size >
688 225 : measurement_record_data_length -
689 225 : ((uint8_t *)measurement_block_header -
690 : (uint8_t *)measurement_record_data)) {
691 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
692 0 : goto receive_done;
693 : }
694 225 : if (measurement_block_header->measurement_specification == 0 ||
695 225 : (measurement_block_header->measurement_specification &
696 225 : (measurement_block_header->measurement_specification - 1))) {
697 4 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
698 4 : goto receive_done;
699 : }
700 221 : if (measurement_block_header->measurement_specification !=
701 221 : spdm_context->connection_info.algorithm.measurement_spec) {
702 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
703 2 : goto receive_done;
704 : }
705 219 : if (measurement_block_header->index == 0 || measurement_block_header->index == 0xFF) {
706 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
707 0 : goto receive_done;
708 : }
709 219 : if (measurement_operation !=
710 : SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_ALL_MEASUREMENTS) {
711 215 : if (measurement_block_header->index != measurement_operation) {
712 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
713 0 : goto receive_done;
714 : }
715 : }
716 219 : if (measurement_block_count > *number_of_blocks) {
717 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
718 0 : goto receive_done;
719 : }
720 219 : measurement_block_count++;
721 219 : measurement_block_size = (uint32_t)(
722 : measurement_block_size +
723 219 : sizeof(spdm_measurement_block_common_header_t) +
724 219 : measurement_block_header->measurement_size);
725 : }
726 :
727 217 : if (measurement_block_size != measurement_record_data_length) {
728 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
729 0 : goto receive_done;
730 : }
731 :
732 217 : *measurement_record_length = measurement_record_data_length;
733 217 : libspdm_copy_mem(measurement_record,
734 : measurement_record_data_length,
735 : measurement_record_data,
736 : measurement_record_data_length);
737 : }
738 :
739 219 : status = LIBSPDM_STATUS_SUCCESS;
740 :
741 : /* -=[Log Message Phase]=- */
742 : #if LIBSPDM_ENABLE_MSG_LOG
743 219 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
744 : #endif /* LIBSPDM_ENABLE_MSG_LOG */
745 :
746 298 : receive_done:
747 298 : if ((status != LIBSPDM_STATUS_SUCCESS) &&
748 : (status != LIBSPDM_STATUS_NOT_READY_PEER)) {
749 77 : libspdm_reset_message_m(spdm_context, session_info);
750 : }
751 298 : libspdm_release_receiver_buffer (spdm_context);
752 298 : return status;
753 : }
754 :
755 301 : libspdm_return_t libspdm_get_measurement(void *spdm_context, const uint32_t *session_id,
756 : uint8_t request_attribute,
757 : uint8_t measurement_operation,
758 : uint8_t slot_id_param,
759 : uint8_t *content_changed,
760 : uint8_t *number_of_blocks,
761 : uint32_t *measurement_record_length,
762 : void *measurement_record)
763 : {
764 : libspdm_context_t *context;
765 : size_t retry;
766 : uint64_t retry_delay_time;
767 : libspdm_return_t status;
768 :
769 301 : context = spdm_context;
770 301 : context->crypto_request = true;
771 301 : retry = context->retry_times;
772 301 : retry_delay_time = context->retry_delay_time;
773 : do {
774 302 : status = libspdm_try_get_measurement(
775 : context, session_id, request_attribute,
776 : measurement_operation, slot_id_param, NULL, content_changed, number_of_blocks,
777 : measurement_record_length, measurement_record,
778 : NULL, NULL, NULL, NULL, NULL);
779 302 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
780 299 : return status;
781 : }
782 :
783 3 : libspdm_sleep(retry_delay_time);
784 3 : } while (retry-- != 0);
785 :
786 2 : return status;
787 : }
788 :
789 2 : libspdm_return_t libspdm_get_measurement_ex(void *spdm_context, const uint32_t *session_id,
790 : uint8_t request_attribute,
791 : uint8_t measurement_operation,
792 : uint8_t slot_id_param,
793 : uint8_t *content_changed,
794 : uint8_t *number_of_blocks,
795 : uint32_t *measurement_record_length,
796 : void *measurement_record,
797 : const void *requester_nonce_in,
798 : void *requester_nonce,
799 : void *responder_nonce,
800 : void *opaque_data,
801 : size_t *opaque_data_size)
802 : {
803 : libspdm_context_t *context;
804 : size_t retry;
805 : uint64_t retry_delay_time;
806 : libspdm_return_t status;
807 :
808 2 : context = spdm_context;
809 2 : context->crypto_request = true;
810 2 : retry = context->retry_times;
811 2 : retry_delay_time = context->retry_delay_time;
812 : do {
813 2 : status = libspdm_try_get_measurement(
814 : context, session_id, request_attribute,
815 : measurement_operation, slot_id_param, NULL, content_changed, number_of_blocks,
816 : measurement_record_length, measurement_record,
817 : requester_nonce_in,
818 : requester_nonce, responder_nonce,
819 : opaque_data, opaque_data_size);
820 2 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
821 2 : return status;
822 : }
823 :
824 0 : libspdm_sleep(retry_delay_time);
825 0 : } while (retry-- != 0);
826 :
827 0 : return status;
828 : }
829 :
830 2 : libspdm_return_t libspdm_get_measurement_ex2(void *spdm_context, const uint32_t *session_id,
831 : uint8_t request_attribute,
832 : uint8_t measurement_operation,
833 : uint8_t slot_id_param,
834 : const void *requester_context,
835 : uint8_t *content_changed,
836 : uint8_t *number_of_blocks,
837 : uint32_t *measurement_record_length,
838 : void *measurement_record,
839 : const void *requester_nonce_in,
840 : void *requester_nonce,
841 : void *responder_nonce,
842 : void *opaque_data,
843 : size_t *opaque_data_size)
844 : {
845 : libspdm_context_t *context;
846 : size_t retry;
847 : uint64_t retry_delay_time;
848 : libspdm_return_t status;
849 :
850 2 : context = spdm_context;
851 2 : context->crypto_request = true;
852 2 : retry = context->retry_times;
853 2 : retry_delay_time = context->retry_delay_time;
854 : do {
855 2 : status = libspdm_try_get_measurement(
856 : context, session_id, request_attribute,
857 : measurement_operation, slot_id_param, requester_context,
858 : content_changed, number_of_blocks,
859 : measurement_record_length, measurement_record,
860 : requester_nonce_in,
861 : requester_nonce, responder_nonce,
862 : opaque_data, opaque_data_size);
863 2 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
864 2 : return status;
865 : }
866 :
867 0 : libspdm_sleep(retry_delay_time);
868 0 : } while (retry-- != 0);
869 :
870 0 : return status;
871 : }
872 :
873 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP*/
|