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