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_responder_lib.h"
8 :
9 : #if LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP
10 16 : bool libspdm_generate_measurement_signature(libspdm_context_t *spdm_context,
11 : libspdm_session_info_t *session_info,
12 : uint8_t *signature)
13 : {
14 : size_t signature_size;
15 : bool result;
16 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
17 : libspdm_l1l2_managed_buffer_t l1l2;
18 : uint8_t *l1l2_buffer;
19 : size_t l1l2_buffer_size;
20 : #else
21 : uint8_t l1l2_hash[LIBSPDM_MAX_HASH_SIZE];
22 : size_t l1l2_hash_size;
23 : #endif
24 :
25 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
26 : result = libspdm_calculate_l1l2(spdm_context, session_info, &l1l2);
27 : #else
28 16 : l1l2_hash_size = sizeof(l1l2_hash);
29 16 : result = libspdm_calculate_l1l2_hash(spdm_context, session_info, &l1l2_hash_size, l1l2_hash);
30 : #endif
31 16 : libspdm_reset_message_m(spdm_context, session_info);
32 16 : if (!result) {
33 0 : return false;
34 : }
35 :
36 16 : if (spdm_context->connection_info.algorithm.pqc_asym_algo != 0) {
37 0 : signature_size = libspdm_get_pqc_asym_signature_size(
38 : spdm_context->connection_info.algorithm.pqc_asym_algo);
39 : } else {
40 16 : signature_size = libspdm_get_asym_signature_size(
41 : spdm_context->connection_info.algorithm.base_asym_algo);
42 : }
43 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
44 : l1l2_buffer = libspdm_get_managed_buffer(&l1l2);
45 : l1l2_buffer_size = libspdm_get_managed_buffer_size(&l1l2);
46 :
47 : result = libspdm_responder_data_sign(
48 : spdm_context,
49 : spdm_context->connection_info.version, SPDM_MEASUREMENTS,
50 : spdm_context->connection_info.algorithm.base_asym_algo,
51 : spdm_context->connection_info.algorithm.pqc_asym_algo,
52 : spdm_context->connection_info.algorithm.base_hash_algo,
53 : false, l1l2_buffer, l1l2_buffer_size, signature, &signature_size);
54 : #else
55 16 : result = libspdm_responder_data_sign(
56 : spdm_context,
57 16 : spdm_context->connection_info.version, SPDM_MEASUREMENTS,
58 : spdm_context->connection_info.algorithm.base_asym_algo,
59 : spdm_context->connection_info.algorithm.pqc_asym_algo,
60 : spdm_context->connection_info.algorithm.base_hash_algo,
61 : true, l1l2_hash, l1l2_hash_size, signature, &signature_size);
62 : #endif
63 16 : return result;
64 : }
65 137 : libspdm_return_t libspdm_get_response_measurements(libspdm_context_t *spdm_context,
66 : size_t request_size,
67 : const void *request,
68 : size_t *response_size,
69 : void *response)
70 : {
71 : const spdm_get_measurements_request_t *spdm_request;
72 : size_t spdm_request_size;
73 : spdm_measurements_response_t *spdm_response;
74 : size_t spdm_response_size;
75 : libspdm_return_t status;
76 : size_t signature_size;
77 : uint8_t slot_id_param;
78 : uint8_t measurements_index;
79 : uint8_t measurements_count;
80 : uint8_t *measurements;
81 : size_t measurements_size;
82 : uint8_t *opaque_data;
83 : size_t opaque_data_size;
84 : size_t meas_opaque_buffer_size;
85 : bool ret;
86 : libspdm_session_info_t *session_info;
87 : libspdm_session_state_t session_state;
88 : uint8_t content_changed;
89 : uint8_t *fill_response_ptr;
90 :
91 137 : spdm_request = request;
92 :
93 : /* -=[Check Parameters Phase]=- */
94 137 : LIBSPDM_ASSERT(spdm_request->header.request_response_code == SPDM_GET_MEASUREMENTS);
95 :
96 137 : if (!spdm_context->last_spdm_request_session_id_valid) {
97 136 : session_info = NULL;
98 : } else {
99 1 : session_info = libspdm_get_session_info_via_session_id(
100 : spdm_context,
101 : spdm_context->last_spdm_request_session_id);
102 1 : if (session_info == NULL) {
103 : /* do not reset message_m because it is unclear which context it should be used. */
104 0 : return libspdm_generate_error_response(
105 : spdm_context,
106 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
107 : response_size, response);
108 : }
109 1 : session_state = libspdm_secured_message_get_session_state(
110 : session_info->secured_message_context);
111 1 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
112 0 : libspdm_reset_message_m(spdm_context, session_info);
113 0 : return libspdm_generate_error_response(
114 : spdm_context,
115 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
116 : response_size, response);
117 : }
118 : }
119 :
120 137 : if (spdm_request->header.spdm_version != libspdm_get_connection_version(spdm_context)) {
121 0 : libspdm_reset_message_m(spdm_context, session_info);
122 0 : return libspdm_generate_error_response(spdm_context,
123 : SPDM_ERROR_CODE_VERSION_MISMATCH, 0,
124 : response_size, response);
125 : }
126 137 : if (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) {
127 : #if LIBSPDM_RESPOND_IF_READY_SUPPORT
128 3 : if (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NOT_READY) {
129 : #endif
130 2 : libspdm_reset_message_m(spdm_context, session_info);
131 : #if LIBSPDM_RESPOND_IF_READY_SUPPORT
132 : }
133 : #endif
134 3 : return libspdm_responder_handle_response_state(
135 : spdm_context,
136 3 : spdm_request->header.request_response_code,
137 : response_size, response);
138 : }
139 : /* check local context here, because meas_cap is reserved for requester.*/
140 134 : if (!libspdm_is_capabilities_flag_supported(
141 : spdm_context, false, 0,
142 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP)) {
143 1 : libspdm_reset_message_m(spdm_context, session_info);
144 1 : return libspdm_generate_error_response(
145 : spdm_context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
146 : SPDM_GET_MEASUREMENTS, response_size, response);
147 : }
148 133 : if ((spdm_context->connection_info.algorithm.measurement_spec == 0) ||
149 133 : (spdm_context->connection_info.algorithm.measurement_hash_algo == 0) ) {
150 0 : libspdm_reset_message_m(spdm_context, session_info);
151 0 : return libspdm_generate_error_response(
152 : spdm_context, SPDM_ERROR_CODE_UNEXPECTED_REQUEST,
153 : 0, response_size, response);
154 : }
155 133 : if (spdm_context->connection_info.connection_state <
156 : LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
157 1 : libspdm_reset_message_m(spdm_context, session_info);
158 1 : return libspdm_generate_error_response(
159 : spdm_context,
160 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
161 : response_size, response);
162 : }
163 :
164 132 : if ((spdm_request->header.param1 &
165 : SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE) != 0) {
166 24 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
167 13 : if (request_size < sizeof(spdm_get_measurements_request_t)) {
168 4 : libspdm_reset_message_m(spdm_context, session_info);
169 4 : return libspdm_generate_error_response(
170 : spdm_context,
171 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
172 : response_size, response);
173 : }
174 9 : spdm_request_size = sizeof(spdm_get_measurements_request_t);
175 : } else {
176 11 : if (request_size <
177 : sizeof(spdm_get_measurements_request_t) -
178 : sizeof(spdm_request->slot_id_param)) {
179 1 : libspdm_reset_message_m(spdm_context, session_info);
180 1 : return libspdm_generate_error_response(
181 : spdm_context,
182 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
183 : response_size, response);
184 : }
185 10 : spdm_request_size = sizeof(spdm_get_measurements_request_t) -
186 : sizeof(spdm_request->slot_id_param);
187 : }
188 : } else {
189 108 : if (request_size < sizeof(spdm_message_header_t)) {
190 0 : libspdm_reset_message_m(spdm_context, session_info);
191 0 : return libspdm_generate_error_response(
192 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
193 : 0, response_size, response);
194 : }
195 108 : spdm_request_size = sizeof(spdm_message_header_t);
196 : }
197 127 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
198 2 : if (request_size < spdm_request_size + SPDM_REQ_CONTEXT_SIZE) {
199 0 : libspdm_reset_message_m(spdm_context, session_info);
200 0 : return libspdm_generate_error_response(
201 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
202 : 0, response_size, response);
203 : }
204 2 : spdm_request_size += SPDM_REQ_CONTEXT_SIZE;
205 : }
206 :
207 127 : if ((spdm_request->header.param1 &
208 : SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE) != 0) {
209 19 : if (!libspdm_is_capabilities_flag_supported(
210 : spdm_context, false, 0,
211 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP_SIG)) {
212 1 : libspdm_reset_message_m(spdm_context, session_info);
213 1 : return libspdm_generate_error_response(
214 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
215 : 0, response_size, response);
216 : }
217 : }
218 :
219 126 : if ((spdm_request->header.param1 &
220 : SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE) == 0) {
221 108 : signature_size = 0;
222 : } else {
223 18 : if (spdm_context->connection_info.algorithm.pqc_asym_algo != 0) {
224 0 : signature_size = libspdm_get_pqc_asym_signature_size(
225 : spdm_context->connection_info.algorithm.pqc_asym_algo);
226 : } else {
227 18 : signature_size = libspdm_get_asym_signature_size(
228 : spdm_context->connection_info.algorithm.base_asym_algo);
229 : }
230 : }
231 :
232 :
233 : /* response_size should be large enough to hold a MEASUREMENTS response without
234 : * measurements or opaque data. */
235 126 : LIBSPDM_ASSERT(*response_size >= (sizeof(spdm_measurements_response_t) +
236 : SPDM_NONCE_SIZE + sizeof(uint16_t) + signature_size));
237 :
238 126 : meas_opaque_buffer_size = *response_size - (sizeof(spdm_measurements_response_t) +
239 : SPDM_NONCE_SIZE + sizeof(uint16_t) +
240 : signature_size);
241 :
242 126 : libspdm_zero_mem(response, *response_size);
243 :
244 126 : measurements_index = spdm_request->header.param2;
245 126 : measurements_count = 0;
246 126 : measurements = (uint8_t*)response + sizeof(spdm_measurements_response_t);
247 126 : measurements_size = meas_opaque_buffer_size;
248 :
249 126 : status = libspdm_measurement_collection(
250 : spdm_context,
251 126 : spdm_context->connection_info.version,
252 126 : spdm_context->connection_info.algorithm.measurement_spec,
253 : spdm_context->connection_info.algorithm.measurement_hash_algo,
254 : measurements_index,
255 126 : spdm_request->header.param1,
256 : &content_changed,
257 : &measurements_count,
258 : measurements,
259 : &measurements_size);
260 :
261 126 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
262 1 : if (status == LIBSPDM_STATUS_MEAS_INVALID_INDEX) {
263 1 : libspdm_reset_message_m(spdm_context, session_info);
264 1 : return libspdm_generate_error_response(
265 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
266 : 0, response_size, response);
267 : } else {
268 0 : libspdm_reset_message_m(spdm_context, session_info);
269 0 : return libspdm_generate_error_response(
270 : spdm_context, SPDM_ERROR_CODE_UNSPECIFIED,
271 : 0, response_size, response);
272 : }
273 : }
274 :
275 125 : LIBSPDM_ASSERT(measurements_count != 0);
276 125 : LIBSPDM_ASSERT((measurements_index == 0) || (measurements_size > 0));
277 125 : LIBSPDM_ASSERT(measurements_size <= SPDM_MAX_MEASUREMENT_RECORD_LENGTH);
278 125 : LIBSPDM_ASSERT(measurements_size <= meas_opaque_buffer_size);
279 :
280 125 : if (measurements_index == 0) {
281 11 : measurements_size = 0;
282 : }
283 :
284 125 : opaque_data =
285 : (uint8_t*)response + sizeof(spdm_measurements_response_t) + measurements_size +
286 125 : SPDM_NONCE_SIZE + sizeof(uint16_t);
287 :
288 125 : if ((libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) &&
289 8 : ((spdm_context->connection_info.algorithm.other_params_support &
290 : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) == SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_NONE)) {
291 4 : opaque_data_size = 0;
292 : } else {
293 121 : opaque_data_size = meas_opaque_buffer_size - measurements_size;
294 :
295 121 : ret = libspdm_measurement_opaque_data(
296 : spdm_context,
297 121 : spdm_context->connection_info.version,
298 121 : spdm_context->connection_info.algorithm.measurement_spec,
299 : spdm_context->connection_info.algorithm.measurement_hash_algo,
300 : measurements_index,
301 121 : spdm_request->header.param1,
302 : opaque_data,
303 : &opaque_data_size);
304 :
305 121 : if (!ret) {
306 0 : libspdm_reset_message_m(spdm_context, session_info);
307 0 : return libspdm_generate_error_response(
308 : spdm_context, SPDM_ERROR_CODE_UNSPECIFIED,
309 : 0, response_size, response);
310 : }
311 : }
312 :
313 125 : LIBSPDM_ASSERT(opaque_data_size <= (meas_opaque_buffer_size - measurements_size));
314 :
315 125 : spdm_response_size =
316 : sizeof(spdm_measurements_response_t) + measurements_size + SPDM_NONCE_SIZE +
317 125 : sizeof(uint16_t) + opaque_data_size + signature_size;
318 125 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
319 2 : spdm_response_size += SPDM_REQ_CONTEXT_SIZE;
320 : }
321 :
322 125 : LIBSPDM_ASSERT(*response_size >= spdm_response_size);
323 :
324 125 : *response_size = spdm_response_size;
325 125 : spdm_response = response;
326 :
327 125 : switch (spdm_request->header.param2) {
328 11 : case SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_TOTAL_NUMBER_OF_MEASUREMENTS:
329 11 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
330 11 : spdm_response->header.request_response_code = SPDM_MEASUREMENTS;
331 11 : spdm_response->header.param1 = measurements_count;
332 11 : spdm_response->header.param2 = 0;
333 11 : spdm_response->number_of_blocks = 0;
334 11 : libspdm_write_uint24(spdm_response->measurement_record_length, 0);
335 11 : break;
336 5 : case SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_ALL_MEASUREMENTS:
337 45 : LIBSPDM_DEBUG_CODE(
338 : uint8_t index;
339 : size_t debug_measurements_record_size;
340 : size_t debug_measurements_block_size;
341 : spdm_measurement_block_dmtf_t *debug_measurement_block;
342 :
343 : debug_measurements_record_size = 0;
344 : debug_measurement_block = (void *)measurements;
345 : for (index = 0; index < measurements_count; index++) {
346 : debug_measurements_block_size =
347 : sizeof(spdm_measurement_block_dmtf_t) +
348 : debug_measurement_block->measurement_block_dmtf_header
349 : .dmtf_spec_measurement_value_size;
350 : debug_measurements_record_size += debug_measurements_block_size;
351 : debug_measurement_block =
352 : (void *)((size_t)debug_measurement_block + debug_measurements_block_size);
353 : }
354 : LIBSPDM_ASSERT(debug_measurements_record_size == measurements_size);
355 : );
356 :
357 5 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
358 5 : spdm_response->header.request_response_code = SPDM_MEASUREMENTS;
359 5 : spdm_response->header.param1 = 0;
360 5 : spdm_response->header.param2 = 0;
361 5 : spdm_response->number_of_blocks = measurements_count;
362 5 : libspdm_write_uint24(spdm_response->measurement_record_length, (uint32_t)measurements_size);
363 5 : break;
364 109 : default:
365 109 : LIBSPDM_ASSERT(measurements_count == 1);
366 :
367 109 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
368 109 : spdm_response->header.request_response_code = SPDM_MEASUREMENTS;
369 109 : spdm_response->header.param1 = 0;
370 109 : spdm_response->header.param2 = 0;
371 109 : spdm_response->number_of_blocks = 1;
372 109 : libspdm_write_uint24(spdm_response->measurement_record_length, (uint32_t)measurements_size);
373 109 : break;
374 : }
375 :
376 125 : if ((spdm_request->header.param1 &
377 : SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE) != 0) {
378 18 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
379 8 : slot_id_param = spdm_request->slot_id_param &
380 : SPDM_GET_MEASUREMENTS_REQUEST_SLOT_ID_MASK;
381 8 : if ((slot_id_param != 0xF) && (slot_id_param >= SPDM_MAX_SLOT_COUNT)) {
382 1 : libspdm_reset_message_m(spdm_context, session_info);
383 1 : return libspdm_generate_error_response(
384 : spdm_context,
385 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
386 : response_size, response);
387 : }
388 7 : if (slot_id_param != 0xF) {
389 6 : if (spdm_context->local_context
390 6 : .local_cert_chain_provision[slot_id_param] == NULL) {
391 0 : libspdm_reset_message_m(spdm_context, session_info);
392 0 : return libspdm_generate_error_response(
393 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
394 : 0, response_size, response);
395 : }
396 : } else {
397 1 : if (spdm_context->local_context
398 1 : .local_public_key_provision == NULL) {
399 0 : libspdm_reset_message_m(spdm_context, session_info);
400 0 : return libspdm_generate_error_response(
401 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
402 : 0, response_size, response);
403 : }
404 : }
405 :
406 7 : if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) &&
407 1 : spdm_context->connection_info.multi_key_conn_rsp &&
408 : (slot_id_param != 0xF)) {
409 1 : if ((spdm_context->local_context.local_key_usage_bit_mask[slot_id_param] &
410 : SPDM_KEY_USAGE_BIT_MASK_MEASUREMENT_USE) == 0) {
411 1 : return libspdm_generate_error_response(
412 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
413 : 0, response_size, response);
414 : }
415 : }
416 :
417 6 : spdm_response->header.param2 = slot_id_param;
418 6 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
419 5 : spdm_response->header.param2 = slot_id_param |
420 5 : (content_changed &
421 : SPDM_MEASUREMENTS_RESPONSE_CONTENT_CHANGE_MASK);
422 : }
423 : }
424 : }
425 :
426 123 : fill_response_ptr =
427 123 : (uint8_t*)response + sizeof(spdm_measurements_response_t) + measurements_size;
428 :
429 123 : if (!libspdm_get_random_number(SPDM_NONCE_SIZE, fill_response_ptr)) {
430 0 : libspdm_reset_message_m(spdm_context, session_info);
431 0 : return libspdm_generate_error_response(spdm_context,
432 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
433 : response_size, response);
434 : }
435 123 : fill_response_ptr += SPDM_NONCE_SIZE;
436 :
437 123 : libspdm_write_uint16(fill_response_ptr, (uint16_t)opaque_data_size);
438 123 : fill_response_ptr += sizeof(uint16_t);
439 :
440 123 : fill_response_ptr += opaque_data_size;
441 :
442 123 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
443 1 : libspdm_copy_mem(fill_response_ptr, SPDM_REQ_CONTEXT_SIZE,
444 1 : (const uint8_t *)spdm_request + spdm_request_size - SPDM_REQ_CONTEXT_SIZE,
445 : SPDM_REQ_CONTEXT_SIZE);
446 1 : fill_response_ptr += SPDM_REQ_CONTEXT_SIZE;
447 : }
448 :
449 123 : libspdm_reset_message_buffer_via_request_code(spdm_context, session_info,
450 123 : spdm_request->header.request_response_code);
451 :
452 123 : status = libspdm_append_message_m(spdm_context, session_info, spdm_request, spdm_request_size);
453 123 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
454 0 : libspdm_reset_message_m(spdm_context, session_info);
455 0 : return libspdm_generate_error_response(spdm_context,
456 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
457 : response_size, response);
458 : }
459 :
460 123 : status = libspdm_append_message_m(spdm_context, session_info,
461 123 : spdm_response, *response_size - signature_size);
462 123 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
463 0 : libspdm_reset_message_m(spdm_context, session_info);
464 0 : return libspdm_generate_error_response(spdm_context,
465 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
466 : response_size, response);
467 : }
468 :
469 123 : if ((spdm_request->header.param1 &
470 : SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE) != 0) {
471 :
472 16 : ret = libspdm_generate_measurement_signature(spdm_context, session_info, fill_response_ptr);
473 :
474 16 : if (!ret) {
475 0 : libspdm_reset_message_m(spdm_context, session_info);
476 0 : return libspdm_generate_error_response(
477 : spdm_context,
478 : SPDM_ERROR_CODE_UNSPECIFIED,
479 : 0,
480 : response_size, response);
481 : }
482 : /*reset*/
483 16 : libspdm_reset_message_m(spdm_context, session_info);
484 : }
485 :
486 123 : return LIBSPDM_STATUS_SUCCESS;
487 : }
488 :
489 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP*/
|