diff --git a/include/library/spdm_requester_lib.h b/include/library/spdm_requester_lib.h index d7d24889117..770ff604c7c 100644 --- a/include/library/spdm_requester_lib.h +++ b/include/library/spdm_requester_lib.h @@ -1112,6 +1112,27 @@ libspdm_return_t libspdm_vendor_send_request_receive_response( #endif /* LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES */ +/** + * This function parses a measurement transaction data buffer and extracts the measurement blocks. + * + * This is useful to allow parsing of full transaction blobs from calls such as Redfish's SPDMGetSignedMeasurements. + * This might move into a utility library at a later date. + * + * @param data The measurement transaction data buffer + * @param data_size The size of the measurement transaction data buffer + * @param measurements A pointer to an array of measurement blocks. This must be freed by the caller. + * @param measurement_count A pointer to the number of measurement blocks + * + * @return LIBSPDM_STATUS_SUCCESS if the measurement blocks were successfully extracted + * @return LIBSPDM_STATUS_INVALID_PARAMETER if the parameters are invalid + * @return LIBSPDM_STATUS_BUFFER_TOO_SMALL if the input buffer is too small + **/ +libspdm_return_t libspdm_parse_measurement_transaction_data( + void* data, + size_t data_size, + spdm_measurement_block_common_header_t** measurements, + size_t* measurement_count); + #ifdef __cplusplus } #endif diff --git a/library/spdm_requester_lib/CMakeLists.txt b/library/spdm_requester_lib/CMakeLists.txt index 3cda286ca18..24328af7067 100644 --- a/library/spdm_requester_lib/CMakeLists.txt +++ b/library/spdm_requester_lib/CMakeLists.txt @@ -47,4 +47,5 @@ target_sources(spdm_requester_lib libspdm_req_get_measurement_extension_log.c libspdm_req_get_key_pair_info.c libspdm_req_set_key_pair_info.c + libspdm_req_parse_measurement_transaction_data.c ) diff --git a/library/spdm_requester_lib/libspdm_req_parse_measurement_transaction_data.c b/library/spdm_requester_lib/libspdm_req_parse_measurement_transaction_data.c new file mode 100644 index 00000000000..73fb34cb33a --- /dev/null +++ b/library/spdm_requester_lib/libspdm_req_parse_measurement_transaction_data.c @@ -0,0 +1,470 @@ +/** + * Copyright Notice: + * Copyright 2021-2026 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md + **/ + +#include "internal/libspdm_requester_lib.h" + +/* Forward declaration - resolved at link time from the integrator's malloc implementation. */ +extern void *allocate_pool(size_t size); + +/** + * Calculate the size of a GET_MEASUREMENTS request based on SPDM version and attributes. + * + * @param spdm_version The SPDM version byte (e.g., SPDM_MESSAGE_VERSION_10). + * @param attributes The param1 field of the GET_MEASUREMENTS request header. + * + * @return The size of the GET_MEASUREMENTS request in bytes. + **/ +static size_t libspdm_get_measurement_request_msg_size(uint8_t spdm_version, uint8_t attributes) +{ + bool signature_requested; + + signature_requested = (attributes & + SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE) != 0; + + if (signature_requested) { + if (spdm_version >= SPDM_MESSAGE_VERSION_13) { + return sizeof(spdm_get_measurements_request_t) + SPDM_REQ_CONTEXT_SIZE; + } else if (spdm_version >= SPDM_MESSAGE_VERSION_11) { + return sizeof(spdm_get_measurements_request_t); + } else { + /* SPDM 1.0: no slot_id_param field */ + return sizeof(spdm_get_measurements_request_t) - + sizeof(((spdm_get_measurements_request_t *)0)->slot_id_param); + } + } else { + if (spdm_version >= SPDM_MESSAGE_VERSION_13) { + return sizeof(spdm_message_header_t) + SPDM_REQ_CONTEXT_SIZE; + } else { + return sizeof(spdm_message_header_t); + } + } +} + +/** + * Skip past the VCA (Version, Capabilities, Algorithms) messages at the start of + * a measurement transaction data buffer for SPDM 1.2 and later. + * + * @param data The buffer containing the transaction data. + * @param data_size The size of the buffer. + * @param spdm_version Output: the negotiated SPDM version from the VCA. + * @param offset_out Output: the offset past the end of VCA data. + * + * @return LIBSPDM_STATUS_SUCCESS on success, or an error status. + **/ +static libspdm_return_t libspdm_skip_vca( + const uint8_t *data, size_t data_size, + uint8_t *spdm_version, size_t *offset_out) +{ + size_t offset; + const spdm_message_header_t *header; + uint8_t version_count; + size_t version_msg_size; + uint16_t length; + size_t caps_size; + + offset = 0; + + /* GET_VERSION request: always sizeof(spdm_message_header_t) = 4 bytes */ + if (offset + sizeof(spdm_message_header_t) > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + header = (const spdm_message_header_t *)(data + offset); + if (header->request_response_code != SPDM_GET_VERSION) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + offset += sizeof(spdm_message_header_t); + + /* VERSION response: 4 (header) + 1 (reserved) + 1 (version_count) + 2*count (entries) */ + if (offset + 6 > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + header = (const spdm_message_header_t *)(data + offset); + if (header->request_response_code != SPDM_VERSION) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + version_count = data[offset + 5]; + version_msg_size = 6 + 2 * (size_t)version_count; + if (offset + version_msg_size > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + offset += version_msg_size; + + /* GET_CAPABILITIES request: sizeof(spdm_get_capabilities_request_t) = 20 bytes for 1.2+ */ + if (offset + sizeof(spdm_get_capabilities_request_t) > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + header = (const spdm_message_header_t *)(data + offset); + if (header->request_response_code != SPDM_GET_CAPABILITIES) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + *spdm_version = header->spdm_version; + offset += sizeof(spdm_get_capabilities_request_t); + + /* CAPABILITIES response: 20 bytes base + optional supported_algorithms block (1.3+) */ + if (offset + sizeof(spdm_capabilities_response_t) > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + header = (const spdm_message_header_t *)(data + offset); + if (header->request_response_code != SPDM_CAPABILITIES) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + caps_size = sizeof(spdm_capabilities_response_t); + if (header->param1 & SPDM_CAPABILITIES_RESPONSE_PARAM1_SUPPORTED_ALGORITHMS) { + /* The supported_algorithms block follows the base struct. + * It has a length field at offset 2 within the block. */ + if (offset + caps_size + 4 > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + length = libspdm_read_uint16(data + offset + caps_size + 2); + if (length < 4 || offset + caps_size + length > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + caps_size += length; + } + offset += caps_size; + + /* NEGOTIATE_ALGORITHMS request: use the length field at offset 4 */ + if (offset + 6 > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + header = (const spdm_message_header_t *)(data + offset); + if (header->request_response_code != SPDM_NEGOTIATE_ALGORITHMS) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + length = libspdm_read_uint16(data + offset + 4); + if (length < sizeof(spdm_message_header_t) || offset + length > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + offset += length; + + /* ALGORITHMS response: use the length field at offset 4 */ + if (offset + 6 > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + header = (const spdm_message_header_t *)(data + offset); + if (header->request_response_code != SPDM_ALGORITHMS) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + length = libspdm_read_uint16(data + offset + 4); + if (length < sizeof(spdm_message_header_t) || offset + length > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + offset += length; + + *offset_out = offset; + return LIBSPDM_STATUS_SUCCESS; +} + +/** + * Advance past a MEASUREMENTS response in the buffer. + * + * @param data The transaction data buffer. + * @param data_size The size of the buffer. + * @param offset The current offset (start of the MEASUREMENTS response). + * @param spdm_version The negotiated SPDM version. + * @param signature_requested Whether the corresponding request had SignatureRequested set. + * @param record_out Output: pointer to the measurement record data (may be NULL if 0 length). + * @param record_length_out Output: the measurement record length. + * @param num_blocks_out Output: the number_of_blocks field from the response. + * @param next_offset_out Output: the offset past this response. + * + * @return LIBSPDM_STATUS_SUCCESS on success, or an error status. + **/ +static libspdm_return_t libspdm_parse_measurements_response( + const uint8_t *data, size_t data_size, size_t offset, + uint8_t spdm_version, bool signature_requested, + const uint8_t **record_out, uint32_t *record_length_out, + uint8_t *num_blocks_out, size_t *next_offset_out) +{ + const spdm_measurements_response_t *response; + uint32_t record_length; + size_t ptr; + uint16_t opaque_length; + + if (offset + sizeof(spdm_measurements_response_t) > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + response = (const spdm_measurements_response_t *)(data + offset); + if (response->header.request_response_code != SPDM_MEASUREMENTS) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + + *num_blocks_out = response->number_of_blocks; + record_length = libspdm_read_uint24(response->measurement_record_length); + *record_length_out = record_length; + + ptr = offset + sizeof(spdm_measurements_response_t); + + /* Measurement record */ + if (ptr + record_length > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + if (record_length > 0) { + *record_out = data + ptr; + } else { + *record_out = NULL; + } + ptr += record_length; + + /* Nonce (always present in MEASUREMENTS response) */ + if (ptr + SPDM_NONCE_SIZE > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + ptr += SPDM_NONCE_SIZE; + + /* Opaque length + data */ + if (ptr + sizeof(uint16_t) > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + opaque_length = libspdm_read_uint16(data + ptr); + ptr += sizeof(uint16_t); + if (ptr + opaque_length > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + ptr += opaque_length; + + /* Requester context (SPDM 1.3+) */ + if (spdm_version >= SPDM_MESSAGE_VERSION_13) { + if (ptr + SPDM_REQ_CONTEXT_SIZE > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + ptr += SPDM_REQ_CONTEXT_SIZE; + } + + if (signature_requested) { + /* Signature is the last field. We do not need to know its size + * since this must be the final response in the transcript. */ + *next_offset_out = data_size; + } else { + *next_offset_out = ptr; + } + + return LIBSPDM_STATUS_SUCCESS; +} + +/** + * Walk measurement blocks within a measurement record, validating structure and counting blocks. + * + * @param record Pointer to the measurement record data. + * @param record_length Length of the measurement record. + * @param block_count Output: the number of measurement blocks found. + * + * @return LIBSPDM_STATUS_SUCCESS on success, or an error status. + **/ +static libspdm_return_t libspdm_count_measurement_blocks( + const uint8_t *record, uint32_t record_length, size_t *block_count) +{ + size_t offset; + const spdm_measurement_block_common_header_t *block; + size_t block_size; + size_t count; + + offset = 0; + count = 0; + + while (offset < record_length) { + if (offset + sizeof(spdm_measurement_block_common_header_t) > record_length) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + block = (const spdm_measurement_block_common_header_t *)(record + offset); + block_size = sizeof(spdm_measurement_block_common_header_t) + block->measurement_size; + if (offset + block_size > record_length) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + count++; + offset += block_size; + } + + if (offset != record_length) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + + *block_count = count; + return LIBSPDM_STATUS_SUCCESS; +} + +libspdm_return_t libspdm_parse_measurement_transaction_data( + void *data, size_t data_size, + spdm_measurement_block_common_header_t **measurements, + size_t *measurement_count) +{ + const uint8_t *buf; + size_t offset; + uint8_t spdm_version; + libspdm_return_t status; + const spdm_message_header_t *first_header; + const spdm_message_header_t *req_header; + uint8_t attributes; + bool signature_requested; + size_t req_size; + const uint8_t *record; + uint32_t record_length; + uint8_t num_blocks; + size_t next_offset; + size_t block_count; + + size_t total_blocks; + size_t total_record_size; + size_t pass_offset; + size_t meas_start; + uint8_t *out_buf; + size_t copy_offset; + + /* Validate parameters */ + if (data == NULL || measurements == NULL || measurement_count == NULL || data_size == 0) { + return LIBSPDM_STATUS_INVALID_PARAMETER; + } + + buf = (const uint8_t *)data; + *measurements = NULL; + *measurement_count = 0; + + /* Check first message to determine if VCA is present */ + if (data_size < sizeof(spdm_message_header_t)) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + + first_header = (const spdm_message_header_t *)buf; + + if (first_header->request_response_code == SPDM_GET_VERSION) { + /* VCA is present (SPDM 1.2+). Skip past it and get negotiated version. */ + status = libspdm_skip_vca(buf, data_size, &spdm_version, &offset); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + return status; + } + } else if (first_header->request_response_code == SPDM_GET_MEASUREMENTS) { + /* No VCA (SPDM 1.0 or 1.1). Version is in the first message header. */ + spdm_version = first_header->spdm_version; + offset = 0; + } else { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + + meas_start = offset; + + /* + * First pass: Walk through all GET_MEASUREMENTS/MEASUREMENTS pairs + * to count total measurement blocks and total measurement record size. + */ + total_blocks = 0; + total_record_size = 0; + pass_offset = meas_start; + + while (pass_offset < data_size) { + /* Parse GET_MEASUREMENTS request header */ + if (pass_offset + sizeof(spdm_message_header_t) > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + req_header = (const spdm_message_header_t *)(buf + pass_offset); + if (req_header->request_response_code != SPDM_GET_MEASUREMENTS) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + + attributes = req_header->param1; + signature_requested = (attributes & + SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE) != 0; + + req_size = libspdm_get_measurement_request_msg_size(spdm_version, attributes); + if (pass_offset + req_size > data_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + pass_offset += req_size; + + /* Check if a MEASUREMENTS response follows. If the next message is not + * a MEASUREMENTS response (e.g., another GET_MEASUREMENTS request, or + * end of buffer), treat this as an unpaired request and skip it. */ + if (pass_offset + sizeof(spdm_message_header_t) > data_size) { + break; + } + req_header = (const spdm_message_header_t *)(buf + pass_offset); + if (req_header->request_response_code != SPDM_MEASUREMENTS) { + continue; + } + + /* Parse MEASUREMENTS response */ + status = libspdm_parse_measurements_response( + buf, data_size, pass_offset, spdm_version, signature_requested, + &record, &record_length, &num_blocks, &next_offset); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + return status; + } + + /* Validate and count measurement blocks within this response's record */ + if (record_length > 0 && record != NULL) { + status = libspdm_count_measurement_blocks(record, record_length, &block_count); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + return status; + } + if (block_count != num_blocks) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + total_blocks += block_count; + total_record_size += record_length; + } + + pass_offset = next_offset; + } + + /* If no measurement blocks were found, return success with empty output */ + if (total_blocks == 0 || total_record_size == 0) { + *measurements = NULL; + *measurement_count = 0; + return LIBSPDM_STATUS_SUCCESS; + } + + /* Allocate output buffer for concatenated measurement blocks */ + out_buf = (uint8_t *)allocate_pool(total_record_size); + if (out_buf == NULL) { + return LIBSPDM_STATUS_BUFFER_FULL; + } + + /* + * Second pass: Copy measurement records into the output buffer. + * The first pass already validated everything, so we can skip validation. + */ + pass_offset = meas_start; + copy_offset = 0; + + while (pass_offset < data_size) { + req_header = (const spdm_message_header_t *)(buf + pass_offset); + attributes = req_header->param1; + signature_requested = (attributes & + SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE) != 0; + + req_size = libspdm_get_measurement_request_msg_size(spdm_version, attributes); + pass_offset += req_size; + + /* Skip unpaired requests (same logic as first pass) */ + if (pass_offset + sizeof(spdm_message_header_t) > data_size) { + break; + } + req_header = (const spdm_message_header_t *)(buf + pass_offset); + if (req_header->request_response_code != SPDM_MEASUREMENTS) { + continue; + } + + /* Parse response (already validated) */ + status = libspdm_parse_measurements_response( + buf, data_size, pass_offset, spdm_version, signature_requested, + &record, &record_length, &num_blocks, &next_offset); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + /* Should not happen since first pass validated. */ + return status; + } + + if (record_length > 0 && record != NULL) { + libspdm_copy_mem(out_buf + copy_offset, total_record_size - copy_offset, + record, record_length); + copy_offset += record_length; + } + + pass_offset = next_offset; + } + + *measurements = (spdm_measurement_block_common_header_t *)out_buf; + *measurement_count = total_blocks; + return LIBSPDM_STATUS_SUCCESS; +} diff --git a/unit_test/test_spdm_requester/CMakeLists.txt b/unit_test/test_spdm_requester/CMakeLists.txt index f1d158f1051..bf882c42475 100644 --- a/unit_test/test_spdm_requester/CMakeLists.txt +++ b/unit_test/test_spdm_requester/CMakeLists.txt @@ -26,6 +26,7 @@ target_sources(test_spdm_requester get_supported_event_types.c subscribe_event_types.c get_measurements.c + parse_measurement_transaction_data.c get_measurement_extension_log.c key_exchange.c finish.c diff --git a/unit_test/test_spdm_requester/parse_measurement_transaction_data.c b/unit_test/test_spdm_requester/parse_measurement_transaction_data.c new file mode 100644 index 00000000000..ec7082aa8b5 --- /dev/null +++ b/unit_test/test_spdm_requester/parse_measurement_transaction_data.c @@ -0,0 +1,1122 @@ +/** + * Copyright Notice: + * Copyright 2021-2026 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md + **/ + +#include "spdm_unit_test.h" +#include "internal/libspdm_requester_lib.h" + +/* + * Test helpers for building SPDM transaction data buffers. + */ +#define TEST_MEAS_VALUE_SIZE 8 +#define TEST_FAKE_SIGNATURE_SIZE 64 +#define TEST_MAX_BUFFER_SIZE 4096 + +static uint8_t m_test_buffer[TEST_MAX_BUFFER_SIZE]; +static size_t m_test_offset; + +static void test_buf_reset(void) +{ + memset(m_test_buffer, 0, sizeof(m_test_buffer)); + m_test_offset = 0; +} + +static void test_buf_write_uint8(uint8_t val) +{ + assert(m_test_offset + 1 <= TEST_MAX_BUFFER_SIZE); + m_test_buffer[m_test_offset++] = val; +} + +static void test_buf_write_uint16_le(uint16_t val) +{ + assert(m_test_offset + 2 <= TEST_MAX_BUFFER_SIZE); + m_test_buffer[m_test_offset++] = (uint8_t)(val & 0xFF); + m_test_buffer[m_test_offset++] = (uint8_t)((val >> 8) & 0xFF); +} + +static void test_buf_write_uint24_le(uint32_t val) +{ + assert(m_test_offset + 3 <= TEST_MAX_BUFFER_SIZE); + m_test_buffer[m_test_offset++] = (uint8_t)(val & 0xFF); + m_test_buffer[m_test_offset++] = (uint8_t)((val >> 8) & 0xFF); + m_test_buffer[m_test_offset++] = (uint8_t)((val >> 16) & 0xFF); +} + +static void test_buf_write_uint32_le(uint32_t val) +{ + assert(m_test_offset + 4 <= TEST_MAX_BUFFER_SIZE); + m_test_buffer[m_test_offset++] = (uint8_t)(val & 0xFF); + m_test_buffer[m_test_offset++] = (uint8_t)((val >> 8) & 0xFF); + m_test_buffer[m_test_offset++] = (uint8_t)((val >> 16) & 0xFF); + m_test_buffer[m_test_offset++] = (uint8_t)((val >> 24) & 0xFF); +} + +static void test_buf_write_zeros(size_t count) +{ + assert(m_test_offset + count <= TEST_MAX_BUFFER_SIZE); + memset(m_test_buffer + m_test_offset, 0, count); + m_test_offset += count; +} + +static void test_buf_write_bytes(const uint8_t *data, size_t size) +{ + assert(m_test_offset + size <= TEST_MAX_BUFFER_SIZE); + memcpy(m_test_buffer + m_test_offset, data, size); + m_test_offset += size; +} + +static void test_buf_write_header(uint8_t version, uint8_t code, uint8_t param1, uint8_t param2) +{ + test_buf_write_uint8(version); + test_buf_write_uint8(code); + test_buf_write_uint8(param1); + test_buf_write_uint8(param2); +} + +/* + * Build a single DMTF measurement block with a given index and fill value. + * Returns the total block size written. + */ +static size_t test_build_measurement_block(uint8_t index, uint8_t fill_value) +{ + size_t start = m_test_offset; + uint16_t meas_size = sizeof(spdm_measurement_block_dmtf_header_t) + TEST_MEAS_VALUE_SIZE; + + /* Common header */ + test_buf_write_uint8(index); + test_buf_write_uint8(SPDM_MEASUREMENT_SPECIFICATION_DMTF); + test_buf_write_uint16_le(meas_size); + + /* DMTF header */ + test_buf_write_uint8(SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_IMMUTABLE_ROM); + test_buf_write_uint16_le(TEST_MEAS_VALUE_SIZE); + + /* Measurement value */ + memset(m_test_buffer + m_test_offset, fill_value, TEST_MEAS_VALUE_SIZE); + m_test_offset += TEST_MEAS_VALUE_SIZE; + + return m_test_offset - start; +} + +/* + * Build VCA for SPDM 1.2+. Constructs minimal valid VCA data. + */ +static void test_build_vca(uint8_t spdm_version) +{ + uint16_t neg_alg_length; + uint16_t alg_length; + + /* GET_VERSION: header only (version=0x10, code=0x84) */ + test_buf_write_header(SPDM_MESSAGE_VERSION_10, SPDM_GET_VERSION, 0, 0); + + /* VERSION: header + reserved + version_count + version entries */ + test_buf_write_header(SPDM_MESSAGE_VERSION_10, SPDM_VERSION, 0, 0); + test_buf_write_uint8(0); /* reserved */ + test_buf_write_uint8(2); /* version_number_entry_count */ + test_buf_write_uint16_le(0x0010); /* version 1.0 */ + test_buf_write_uint16_le(((uint16_t)spdm_version << 8) | spdm_version); + + /* GET_CAPABILITIES (1.2+): 20 bytes */ + test_buf_write_header(spdm_version, SPDM_GET_CAPABILITIES, 0, 0); + test_buf_write_uint8(0); /* reserved */ + test_buf_write_uint8(0); /* ct_exponent */ + test_buf_write_uint16_le(0); /* ext_flags (reserved pre-1.4) */ + test_buf_write_uint32_le(0); /* flags */ + test_buf_write_uint32_le(0x100); /* data_transfer_size */ + test_buf_write_uint32_le(0x1200); /* max_spdm_msg_size */ + + /* CAPABILITIES (1.2+): 20 bytes (no supported_algorithms for simplicity) */ + test_buf_write_header(spdm_version, SPDM_CAPABILITIES, 0, 0); + test_buf_write_uint8(0); /* reserved */ + test_buf_write_uint8(0); /* ct_exponent */ + test_buf_write_uint16_le(0); /* ext_flags */ + test_buf_write_uint32_le( + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP_SIG); /* flags */ + test_buf_write_uint32_le(0x100); /* data_transfer_size */ + test_buf_write_uint32_le(0x1200); /* max_spdm_msg_size */ + + /* + * NEGOTIATE_ALGORITHMS: 32 bytes + * header(4) + length(2) + measurement_spec(1) + other_params(1) + * + base_asym_algo(4) + base_hash_algo(4) + pqc_asym_algo(4) + * + reserved2(8) + ext_asym_count(1) + ext_hash_count(1) + * + reserved3(1) + mel_spec(1) = 32 + */ + neg_alg_length = 32; + test_buf_write_header(spdm_version, SPDM_NEGOTIATE_ALGORITHMS, 0, 0); + test_buf_write_uint16_le(neg_alg_length); + test_buf_write_uint8(SPDM_MEASUREMENT_SPECIFICATION_DMTF); /* measurement_spec */ + test_buf_write_uint8(0); /* other_params_support */ + test_buf_write_uint32_le( + SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256); /* base_asym_algo */ + test_buf_write_uint32_le( + SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_256); /* base_hash_algo */ + test_buf_write_uint32_le(0); /* pqc_asym_algo (reserved in pre-1.4) */ + test_buf_write_zeros(8); /* reserved2 */ + test_buf_write_uint8(0); /* ext_asym_count */ + test_buf_write_uint8(0); /* ext_hash_count */ + test_buf_write_uint8(0); /* reserved3 */ + test_buf_write_uint8(0); /* mel_specification */ + + /* + * ALGORITHMS: 36 bytes + * header(4) + length(2) + measurement_spec_sel(1) + other_params_sel(1) + * + measurement_hash_algo(4) + base_asym_sel(4) + base_hash_sel(4) + * + pqc_asym_sel(4) + reserved2(7) + mel_spec_sel(1) + * + ext_asym_sel_count(1) + ext_hash_sel_count(1) + reserved3(2) = 36 + */ + alg_length = 36; + test_buf_write_header(spdm_version, SPDM_ALGORITHMS, 0, 0); + test_buf_write_uint16_le(alg_length); + test_buf_write_uint8(SPDM_MEASUREMENT_SPECIFICATION_DMTF); /* measurement_spec_sel */ + test_buf_write_uint8(0); /* other_params_selection */ + test_buf_write_uint32_le( + SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA_256); /* measurement_hash_algo */ + test_buf_write_uint32_le( + SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256); /* base_asym_sel */ + test_buf_write_uint32_le( + SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_256); /* base_hash_sel */ + test_buf_write_uint32_le(0); /* pqc_asym_sel */ + test_buf_write_zeros(7); /* reserved2 */ + test_buf_write_uint8(0); /* mel_specification_sel */ + test_buf_write_uint8(0); /* ext_asym_sel_count */ + test_buf_write_uint8(0); /* ext_hash_sel_count */ + test_buf_write_uint16_le(0); /* reserved3 */ +} + +/* + * Build a GET_MEASUREMENTS request. + */ +static void test_build_get_measurements_request( + uint8_t spdm_version, uint8_t attributes, uint8_t measurement_operation) +{ + bool signature_requested; + + signature_requested = (attributes & + SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE) != 0; + + test_buf_write_header(spdm_version, SPDM_GET_MEASUREMENTS, attributes, measurement_operation); + + if (signature_requested) { + test_buf_write_zeros(SPDM_NONCE_SIZE); /* nonce */ + if (spdm_version >= SPDM_MESSAGE_VERSION_11) { + test_buf_write_uint8(0); /* slot_id_param */ + } + } + if (spdm_version >= SPDM_MESSAGE_VERSION_13) { + test_buf_write_zeros(SPDM_REQ_CONTEXT_SIZE); /* requester_context */ + } +} + +/* + * Build a MEASUREMENTS response. + * If record_data and record_size are non-zero, the measurement record is included. + * nonce is filled with zeros. opaque_length is 0. + */ +static void test_build_measurements_response( + uint8_t spdm_version, uint8_t param1, uint8_t number_of_blocks, + const uint8_t *record_data, uint32_t record_size, + bool include_signature) +{ + test_buf_write_header(spdm_version, SPDM_MEASUREMENTS, param1, 0); + test_buf_write_uint8(number_of_blocks); + test_buf_write_uint24_le(record_size); + + if (record_size > 0 && record_data != NULL) { + test_buf_write_bytes(record_data, record_size); + } + + /* Nonce (always present) */ + test_buf_write_zeros(SPDM_NONCE_SIZE); + + /* Opaque length = 0 */ + test_buf_write_uint16_le(0); + + /* Requester context (v1.3+) */ + if (spdm_version >= SPDM_MESSAGE_VERSION_13) { + test_buf_write_zeros(SPDM_REQ_CONTEXT_SIZE); + } + + /* Fake signature */ + if (include_signature) { + test_buf_write_zeros(TEST_FAKE_SIGNATURE_SIZE); + } +} + +/* + * Helper: Build measurement record with N blocks, returning record data and size. + * Uses a temporary area at the end of the test buffer. + */ +static void test_build_measurement_record( + uint8_t start_index, uint8_t count, + uint8_t *record_buf, size_t record_buf_size, uint32_t *record_size_out) +{ + size_t saved_offset; + size_t block_size; + uint8_t i; + + saved_offset = m_test_offset; + + for (i = 0; i < count; i++) { + block_size = test_build_measurement_block(start_index + i, 0xAA + i); + (void)block_size; + } + + *record_size_out = (uint32_t)(m_test_offset - saved_offset); + assert(*record_size_out <= record_buf_size); + memcpy(record_buf, m_test_buffer + saved_offset, *record_size_out); + m_test_offset = saved_offset; +} + +/* + * Validate the parsed measurement blocks. + */ +static void test_validate_blocks( + const spdm_measurement_block_common_header_t *measurements, + size_t measurement_count, + uint8_t expected_start_index, size_t expected_count) +{ + const uint8_t *ptr; + size_t i; + const spdm_measurement_block_common_header_t *block; + size_t block_size; + + assert_non_null(measurements); + assert_int_equal(measurement_count, expected_count); + + ptr = (const uint8_t *)measurements; + for (i = 0; i < measurement_count; i++) { + block = (const spdm_measurement_block_common_header_t *)ptr; + assert_int_equal(block->index, expected_start_index + (uint8_t)i); + assert_int_equal(block->measurement_specification, SPDM_MEASUREMENT_SPECIFICATION_DMTF); + block_size = sizeof(spdm_measurement_block_common_header_t) + block->measurement_size; + ptr += block_size; + } +} + +/** + * Test 1: SPDM 1.0 single-request transcript with 2 measurement blocks and signature. + **/ +static void req_parse_measurement_transaction_data_case1(void **state) +{ + libspdm_return_t status; + spdm_measurement_block_common_header_t *measurements; + size_t measurement_count; + uint8_t record_buf[256]; + uint32_t record_size; + + test_buf_reset(); + + /* Build measurement record with 2 blocks */ + test_build_measurement_record(1, 2, record_buf, sizeof(record_buf), &record_size); + + /* GET_MEASUREMENTS (0xFF, with signature) */ + test_build_get_measurements_request( + SPDM_MESSAGE_VERSION_10, + SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE, + 0xFF); + + /* MEASUREMENTS response */ + test_build_measurements_response( + SPDM_MESSAGE_VERSION_10, 0, 2, record_buf, record_size, true); + + status = libspdm_parse_measurement_transaction_data( + m_test_buffer, m_test_offset, &measurements, &measurement_count); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + + test_validate_blocks(measurements, measurement_count, 1, 2); + + free(measurements); +} + +/** + * Test 2: SPDM 1.1 single-request transcript with 3 measurement blocks. + **/ +static void req_parse_measurement_transaction_data_case2(void **state) +{ + libspdm_return_t status; + spdm_measurement_block_common_header_t *measurements; + size_t measurement_count; + uint8_t record_buf[256]; + uint32_t record_size; + + test_buf_reset(); + + test_build_measurement_record(1, 3, record_buf, sizeof(record_buf), &record_size); + + test_build_get_measurements_request( + SPDM_MESSAGE_VERSION_11, + SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE, + 0xFF); + + test_build_measurements_response( + SPDM_MESSAGE_VERSION_11, 0, 3, record_buf, record_size, true); + + status = libspdm_parse_measurement_transaction_data( + m_test_buffer, m_test_offset, &measurements, &measurement_count); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + + test_validate_blocks(measurements, measurement_count, 1, 3); + + free(measurements); +} + +/** + * Test 3: SPDM 1.2 single-request transcript with VCA and 2 blocks. + **/ +static void req_parse_measurement_transaction_data_case3(void **state) +{ + libspdm_return_t status; + spdm_measurement_block_common_header_t *measurements; + size_t measurement_count; + uint8_t record_buf[256]; + uint32_t record_size; + + test_buf_reset(); + + /* Build VCA */ + test_build_vca(SPDM_MESSAGE_VERSION_12); + + test_build_measurement_record(1, 2, record_buf, sizeof(record_buf), &record_size); + + test_build_get_measurements_request( + SPDM_MESSAGE_VERSION_12, + SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE, + 0xFF); + + test_build_measurements_response( + SPDM_MESSAGE_VERSION_12, 0, 2, record_buf, record_size, true); + + status = libspdm_parse_measurement_transaction_data( + m_test_buffer, m_test_offset, &measurements, &measurement_count); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + + test_validate_blocks(measurements, measurement_count, 1, 2); + + free(measurements); +} + +/** + * Test 4: SPDM 1.2 multi-request transcript with VCA. + * Format: VCA + GET_MEASUREMENTS(0)/MEASUREMENTS(0) + GET_MEASUREMENTS(1)/MEASUREMENTS(1) + * + GET_MEASUREMENTS(2)/MEASUREMENTS(2) [signed] + **/ +static void req_parse_measurement_transaction_data_case4(void **state) +{ + libspdm_return_t status; + spdm_measurement_block_common_header_t *measurements; + size_t measurement_count; + uint8_t record_buf[256]; + uint32_t record_size; + + test_buf_reset(); + + /* Build VCA */ + test_build_vca(SPDM_MESSAGE_VERSION_12); + + /* GET_MEASUREMENTS(0): total number query, no signature */ + test_build_get_measurements_request( + SPDM_MESSAGE_VERSION_12, 0, 0); + + /* MEASUREMENTS(0): total number = 2, no blocks */ + test_build_measurements_response( + SPDM_MESSAGE_VERSION_12, 2, 0, NULL, 0, false); + + /* GET_MEASUREMENTS(1): index 1, no signature */ + test_build_get_measurements_request( + SPDM_MESSAGE_VERSION_12, 0, 1); + + /* MEASUREMENTS(1): 1 block with index 1 */ + test_build_measurement_record(1, 1, record_buf, sizeof(record_buf), &record_size); + test_build_measurements_response( + SPDM_MESSAGE_VERSION_12, 0, 1, record_buf, record_size, false); + + /* GET_MEASUREMENTS(2): index 2, with signature (last request) */ + test_build_get_measurements_request( + SPDM_MESSAGE_VERSION_12, + SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE, + 2); + + /* MEASUREMENTS(2): 1 block with index 2 */ + test_build_measurement_record(2, 1, record_buf, sizeof(record_buf), &record_size); + test_build_measurements_response( + SPDM_MESSAGE_VERSION_12, 0, 1, record_buf, record_size, true); + + status = libspdm_parse_measurement_transaction_data( + m_test_buffer, m_test_offset, &measurements, &measurement_count); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + + /* Should have 2 blocks total (from responses 1 and 2) */ + assert_int_equal(measurement_count, 2); + assert_non_null(measurements); + + /* Validate individual blocks */ + { + const uint8_t *ptr = (const uint8_t *)measurements; + const spdm_measurement_block_common_header_t *block; + + block = (const spdm_measurement_block_common_header_t *)ptr; + assert_int_equal(block->index, 1); + ptr += sizeof(spdm_measurement_block_common_header_t) + block->measurement_size; + + block = (const spdm_measurement_block_common_header_t *)ptr; + assert_int_equal(block->index, 2); + } + + free(measurements); +} + +/** + * Test 5: SPDM 1.3 single-request transcript with VCA and requester context. + **/ +static void req_parse_measurement_transaction_data_case5(void **state) +{ + libspdm_return_t status; + spdm_measurement_block_common_header_t *measurements; + size_t measurement_count; + uint8_t record_buf[256]; + uint32_t record_size; + + test_buf_reset(); + + test_build_vca(SPDM_MESSAGE_VERSION_13); + + test_build_measurement_record(1, 2, record_buf, sizeof(record_buf), &record_size); + + test_build_get_measurements_request( + SPDM_MESSAGE_VERSION_13, + SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE, + 0xFF); + + test_build_measurements_response( + SPDM_MESSAGE_VERSION_13, 0, 2, record_buf, record_size, true); + + status = libspdm_parse_measurement_transaction_data( + m_test_buffer, m_test_offset, &measurements, &measurement_count); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + + test_validate_blocks(measurements, measurement_count, 1, 2); + + free(measurements); +} + +/** + * Test 6: SPDM 1.4 single-request transcript with VCA. + **/ +static void req_parse_measurement_transaction_data_case6(void **state) +{ + libspdm_return_t status; + spdm_measurement_block_common_header_t *measurements; + size_t measurement_count; + uint8_t record_buf[256]; + uint32_t record_size; + + test_buf_reset(); + + test_build_vca(SPDM_MESSAGE_VERSION_14); + + test_build_measurement_record(1, 1, record_buf, sizeof(record_buf), &record_size); + + test_build_get_measurements_request( + SPDM_MESSAGE_VERSION_14, + SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE, + 0xFF); + + test_build_measurements_response( + SPDM_MESSAGE_VERSION_14, 0, 1, record_buf, record_size, true); + + status = libspdm_parse_measurement_transaction_data( + m_test_buffer, m_test_offset, &measurements, &measurement_count); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + + test_validate_blocks(measurements, measurement_count, 1, 1); + + free(measurements); +} + +/** + * Test 7: SPDM 1.0 multi-request transcript without any signature (MEAS_CAP != 10b). + **/ +static void req_parse_measurement_transaction_data_case7(void **state) +{ + libspdm_return_t status; + spdm_measurement_block_common_header_t *measurements; + size_t measurement_count; + uint8_t record_buf[256]; + uint32_t record_size; + + test_buf_reset(); + + /* GET_MEASUREMENTS(0): total number query, no signature */ + test_build_get_measurements_request(SPDM_MESSAGE_VERSION_10, 0, 0); + test_build_measurements_response(SPDM_MESSAGE_VERSION_10, 2, 0, NULL, 0, false); + + /* GET_MEASUREMENTS(1): index 1, no signature */ + test_build_get_measurements_request(SPDM_MESSAGE_VERSION_10, 0, 1); + test_build_measurement_record(1, 1, record_buf, sizeof(record_buf), &record_size); + test_build_measurements_response(SPDM_MESSAGE_VERSION_10, 0, 1, record_buf, record_size, false); + + /* GET_MEASUREMENTS(2): index 2, no signature */ + test_build_get_measurements_request(SPDM_MESSAGE_VERSION_10, 0, 2); + test_build_measurement_record(2, 1, record_buf, sizeof(record_buf), &record_size); + test_build_measurements_response(SPDM_MESSAGE_VERSION_10, 0, 1, record_buf, record_size, false); + + status = libspdm_parse_measurement_transaction_data( + m_test_buffer, m_test_offset, &measurements, &measurement_count); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + assert_int_equal(measurement_count, 2); + + free(measurements); +} + +/** + * Test 8: SPDM 1.3 multi-request transcript with requester context. + **/ +static void req_parse_measurement_transaction_data_case8(void **state) +{ + libspdm_return_t status; + spdm_measurement_block_common_header_t *measurements; + size_t measurement_count; + uint8_t record_buf[256]; + uint32_t record_size; + + test_buf_reset(); + + test_build_vca(SPDM_MESSAGE_VERSION_13); + + /* GET_MEASUREMENTS(0): total number, no signature */ + test_build_get_measurements_request(SPDM_MESSAGE_VERSION_13, 0, 0); + test_build_measurements_response(SPDM_MESSAGE_VERSION_13, 3, 0, NULL, 0, false); + + /* GET_MEASUREMENTS(1): index 1, no signature */ + test_build_get_measurements_request(SPDM_MESSAGE_VERSION_13, 0, 1); + test_build_measurement_record(1, 1, record_buf, sizeof(record_buf), &record_size); + test_build_measurements_response(SPDM_MESSAGE_VERSION_13, 0, 1, record_buf, record_size, false); + + /* GET_MEASUREMENTS(2): index 2, no signature */ + test_build_get_measurements_request(SPDM_MESSAGE_VERSION_13, 0, 2); + test_build_measurement_record(2, 1, record_buf, sizeof(record_buf), &record_size); + test_build_measurements_response(SPDM_MESSAGE_VERSION_13, 0, 1, record_buf, record_size, false); + + /* GET_MEASUREMENTS(3): index 3, with signature (last) */ + test_build_get_measurements_request( + SPDM_MESSAGE_VERSION_13, + SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE, 3); + test_build_measurement_record(3, 1, record_buf, sizeof(record_buf), &record_size); + test_build_measurements_response(SPDM_MESSAGE_VERSION_13, 0, 1, record_buf, record_size, true); + + status = libspdm_parse_measurement_transaction_data( + m_test_buffer, m_test_offset, &measurements, &measurement_count); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + assert_int_equal(measurement_count, 3); + + /* Verify block indices */ + { + const uint8_t *ptr = (const uint8_t *)measurements; + const spdm_measurement_block_common_header_t *block; + size_t i; + + for (i = 0; i < measurement_count; i++) { + block = (const spdm_measurement_block_common_header_t *)ptr; + assert_int_equal(block->index, i + 1); + ptr += sizeof(spdm_measurement_block_common_header_t) + block->measurement_size; + } + } + + free(measurements); +} + +/** + * Test 9: NULL parameter - data is NULL. + **/ +static void req_parse_measurement_transaction_data_case9(void **state) +{ + libspdm_return_t status; + spdm_measurement_block_common_header_t *measurements; + size_t measurement_count; + + status = libspdm_parse_measurement_transaction_data( + NULL, 100, &measurements, &measurement_count); + assert_int_equal(status, LIBSPDM_STATUS_INVALID_PARAMETER); +} + +/** + * Test 10: NULL parameter - measurements is NULL. + **/ +static void req_parse_measurement_transaction_data_case10(void **state) +{ + libspdm_return_t status; + size_t measurement_count; + uint8_t dummy = 0; + + status = libspdm_parse_measurement_transaction_data( + &dummy, 1, NULL, &measurement_count); + assert_int_equal(status, LIBSPDM_STATUS_INVALID_PARAMETER); +} + +/** + * Test 11: NULL parameter - measurement_count is NULL. + **/ +static void req_parse_measurement_transaction_data_case11(void **state) +{ + libspdm_return_t status; + spdm_measurement_block_common_header_t *measurements; + uint8_t dummy = 0; + + status = libspdm_parse_measurement_transaction_data( + &dummy, 1, &measurements, NULL); + assert_int_equal(status, LIBSPDM_STATUS_INVALID_PARAMETER); +} + +/** + * Test 12: data_size is 0. + **/ +static void req_parse_measurement_transaction_data_case12(void **state) +{ + libspdm_return_t status; + spdm_measurement_block_common_header_t *measurements; + size_t measurement_count; + uint8_t dummy = 0; + + status = libspdm_parse_measurement_transaction_data( + &dummy, 0, &measurements, &measurement_count); + assert_int_equal(status, LIBSPDM_STATUS_INVALID_PARAMETER); +} + +/** + * Test 13: Truncated buffer (too small for even a header). + **/ +static void req_parse_measurement_transaction_data_case13(void **state) +{ + libspdm_return_t status; + spdm_measurement_block_common_header_t *measurements; + size_t measurement_count; + uint8_t small_buf[2] = {SPDM_MESSAGE_VERSION_10, SPDM_GET_MEASUREMENTS}; + + status = libspdm_parse_measurement_transaction_data( + small_buf, sizeof(small_buf), &measurements, &measurement_count); + assert_int_equal(status, LIBSPDM_STATUS_INVALID_MSG_SIZE); +} + +/** + * Test 14: Invalid first message (not GET_VERSION or GET_MEASUREMENTS). + **/ +static void req_parse_measurement_transaction_data_case14(void **state) +{ + libspdm_return_t status; + spdm_measurement_block_common_header_t *measurements; + size_t measurement_count; + uint8_t bad_buf[4] = {SPDM_MESSAGE_VERSION_12, SPDM_GET_DIGESTS, 0, 0}; + + status = libspdm_parse_measurement_transaction_data( + bad_buf, sizeof(bad_buf), &measurements, &measurement_count); + assert_int_equal(status, LIBSPDM_STATUS_INVALID_MSG_FIELD); +} + +/** + * Test 15: Only total-number query, 0 measurement blocks returned. + **/ +static void req_parse_measurement_transaction_data_case15(void **state) +{ + libspdm_return_t status; + spdm_measurement_block_common_header_t *measurements; + size_t measurement_count; + + test_buf_reset(); + + /* Single GET_MEASUREMENTS(0) / MEASUREMENTS(0) pair, no signature */ + test_build_get_measurements_request(SPDM_MESSAGE_VERSION_11, 0, 0); + test_build_measurements_response(SPDM_MESSAGE_VERSION_11, 5, 0, NULL, 0, false); + + status = libspdm_parse_measurement_transaction_data( + m_test_buffer, m_test_offset, &measurements, &measurement_count); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + assert_int_equal(measurement_count, 0); + assert_null(measurements); +} + +/** + * Test 16: SPDM 1.1 single-request without signature (MEAS_CAP = 01b). + **/ +static void req_parse_measurement_transaction_data_case16(void **state) +{ + libspdm_return_t status; + spdm_measurement_block_common_header_t *measurements; + size_t measurement_count; + uint8_t record_buf[256]; + uint32_t record_size; + + test_buf_reset(); + + test_build_measurement_record(1, 2, record_buf, sizeof(record_buf), &record_size); + + /* No signature requested */ + test_build_get_measurements_request(SPDM_MESSAGE_VERSION_11, 0, 0xFF); + test_build_measurements_response(SPDM_MESSAGE_VERSION_11, 0, 2, record_buf, record_size, false); + + status = libspdm_parse_measurement_transaction_data( + m_test_buffer, m_test_offset, &measurements, &measurement_count); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + + test_validate_blocks(measurements, measurement_count, 1, 2); + + free(measurements); +} + +/** + * Real-world Broadcom NIC transaction data blob. + * SPDM 1.2 with VCA, multi-request (including an unpaired GET_MEASUREMENTS(0xFD)), + * 4 measurement blocks (indices 1-4), 64-byte ECDSA P-256 signature on the final request. + **/ +static const uint8_t broadcom_nic_blob[] = { + 0x10, 0x84, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, + 0x12, 0xe1, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0xc0, 0xf2, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x12, 0x61, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x16, 0x00, 0x04, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0xe3, 0x04, 0x00, 0x30, 0x00, 0x01, 0x02, + 0xfc, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x12, 0x00, 0x03, 0x20, 0x02, 0x00, + 0x04, 0x20, 0xac, 0x00, 0x05, 0x20, 0x01, 0x00, 0x12, 0x63, 0x04, 0x00, 0x34, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, + 0x03, 0x20, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x12, 0xe0, 0x00, 0x00, + 0x12, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xce, 0xba, 0x0a, 0x7a, 0x74, 0x5a, 0xb4, + 0xb1, 0xef, 0x97, 0x4d, 0x25, 0xd9, 0x69, 0x70, 0x67, 0xaa, 0xad, 0x34, 0x9e, 0x5b, 0xe4, 0xc2, + 0x6a, 0xd7, 0x53, 0xb4, 0xaa, 0xbe, 0x8b, 0x67, 0x00, 0x00, 0x12, 0xe0, 0x00, 0xfd, 0x12, 0xe0, + 0x00, 0x01, 0x12, 0x60, 0x00, 0x00, 0x01, 0x27, 0x00, 0x00, 0x01, 0x01, 0x23, 0x00, 0x00, 0x20, + 0x00, 0x4b, 0x8f, 0x6b, 0x7a, 0xf4, 0x00, 0x89, 0x54, 0x47, 0x35, 0x79, 0x2b, 0x3a, 0xac, 0x12, + 0xca, 0xd6, 0x40, 0x27, 0x1b, 0xdc, 0x6e, 0x80, 0x11, 0x07, 0x50, 0xd4, 0x0c, 0x87, 0xd2, 0xdd, + 0x21, 0x36, 0xab, 0x43, 0x85, 0x55, 0x78, 0x73, 0x6f, 0x7c, 0x99, 0x90, 0xa0, 0x71, 0x90, 0xda, + 0xd7, 0x1f, 0x69, 0xa1, 0x76, 0xe0, 0x87, 0x62, 0x7f, 0x4d, 0x41, 0x04, 0x6c, 0xe4, 0x25, 0xa3, + 0x87, 0x00, 0x00, 0x12, 0xe0, 0x00, 0x02, 0x12, 0x60, 0x00, 0x00, 0x01, 0x27, 0x00, 0x00, 0x02, + 0x01, 0x23, 0x00, 0x01, 0x20, 0x00, 0xff, 0x52, 0x13, 0xc5, 0xab, 0xa3, 0xd8, 0x59, 0xef, 0x66, + 0x2e, 0xe3, 0xd8, 0x65, 0x28, 0xa5, 0x15, 0xe1, 0x54, 0x31, 0x05, 0x10, 0xc9, 0x25, 0xc9, 0xd4, + 0xac, 0x55, 0xa3, 0x10, 0x98, 0x17, 0xdc, 0x4e, 0xb4, 0x84, 0xf6, 0xa1, 0x67, 0x62, 0xb0, 0x8b, + 0x53, 0x1e, 0xa0, 0x81, 0x59, 0xe2, 0xea, 0x7e, 0xe1, 0xeb, 0x35, 0xd5, 0xc7, 0x01, 0x33, 0x72, + 0x51, 0x45, 0xcb, 0x4a, 0x0b, 0x0a, 0x00, 0x00, 0x12, 0xe0, 0x00, 0x03, 0x12, 0x60, 0x00, 0x00, + 0x01, 0x27, 0x00, 0x00, 0x03, 0x01, 0x23, 0x00, 0x01, 0x20, 0x00, 0x97, 0xea, 0x86, 0x38, 0x6b, + 0x78, 0x2d, 0xf3, 0x2e, 0x66, 0xed, 0x06, 0x8b, 0x10, 0x66, 0xd7, 0x54, 0x17, 0xc7, 0x6d, 0xc4, + 0x05, 0x20, 0x7c, 0x94, 0xbf, 0x0e, 0x75, 0x19, 0xb4, 0x39, 0xca, 0xd8, 0x1f, 0xf4, 0xc1, 0xa6, + 0xb5, 0x4f, 0xd0, 0x1b, 0xb8, 0xa2, 0x55, 0xe4, 0xe5, 0x58, 0x93, 0xae, 0x0e, 0x42, 0xde, 0xa8, + 0x62, 0xd6, 0xf3, 0xe5, 0x82, 0x35, 0x57, 0x38, 0xa5, 0xad, 0xe8, 0x00, 0x00, 0x12, 0xe0, 0x01, + 0x04, 0x6d, 0x88, 0x3e, 0x8b, 0xbf, 0x73, 0xab, 0x1a, 0xb9, 0x57, 0xc9, 0xee, 0x4f, 0xe2, 0xef, + 0x54, 0x9f, 0x7d, 0xad, 0xc5, 0x3a, 0x3b, 0x70, 0xe5, 0x34, 0x21, 0x21, 0xea, 0x11, 0xaf, 0xda, + 0x79, 0x00, 0x12, 0x60, 0x00, 0x00, 0x01, 0x27, 0x00, 0x00, 0x04, 0x01, 0x23, 0x00, 0x03, 0x20, + 0x00, 0xde, 0x47, 0x5f, 0x36, 0xaf, 0x5f, 0x4b, 0x43, 0x6c, 0x95, 0x7d, 0x7b, 0x30, 0x41, 0xba, + 0x63, 0xf4, 0xf0, 0x6b, 0xff, 0xbb, 0xe7, 0x82, 0xe8, 0x7b, 0x56, 0x54, 0x5a, 0x63, 0x5f, 0x12, + 0x31, 0xc7, 0x5b, 0xb1, 0xfa, 0x27, 0x4a, 0x31, 0xf0, 0x96, 0x72, 0x91, 0x85, 0xfb, 0x1f, 0x4e, + 0x20, 0x9c, 0x0d, 0x36, 0x13, 0xac, 0x7a, 0x4b, 0x08, 0x88, 0x93, 0xdb, 0x79, 0xcf, 0xb1, 0x66, + 0x2e, 0x00, 0x00, 0xe0, 0xf6, 0x58, 0xee, 0x1f, 0x9f, 0xed, 0xec, 0x4e, 0x27, 0xb5, 0x43, 0xfd, + 0x01, 0xa1, 0xda, 0x17, 0x50, 0x2f, 0x2b, 0xb9, 0x4f, 0x34, 0x09, 0x19, 0xcf, 0x74, 0xbc, 0xdc, + 0x9e, 0x3b, 0x48, 0x5f, 0x87, 0x18, 0xbf, 0xcb, 0x25, 0xca, 0xb2, 0x2b, 0x2a, 0x06, 0x92, 0xf9, + 0xfb, 0x45, 0x59, 0x48, 0xa3, 0x04, 0xca, 0x5e, 0x31, 0x4b, 0xe2, 0x15, 0x84, 0xa3, 0xf5, 0xde, + 0x48, 0x00, 0xe4, +}; + +/** + * Real-world NVIDIA FPGA transaction data blob. + * SPDM 1.1, no VCA, single signed GET_MEASUREMENTS(0xFF), + * 64 measurement blocks, 96-byte ECDSA P-384 signature. + **/ +static const uint8_t nvidia_fpga_blob[] = { + 0x11, 0xe0, 0x01, 0xff, 0xc0, 0xda, 0x48, 0x76, 0x39, 0xaa, 0xea, 0x6e, 0x4d, 0x2e, 0x49, 0xa4, + 0xd5, 0x08, 0xce, 0x09, 0xba, 0x69, 0x8e, 0x8a, 0xdd, 0xa1, 0xcd, 0x3e, 0x24, 0x65, 0x28, 0xad, + 0xcb, 0xbd, 0x71, 0xc2, 0x00, 0x11, 0x60, 0x00, 0x00, 0x40, 0x09, 0x09, 0x00, 0x01, 0x01, 0x07, + 0x00, 0x83, 0x04, 0x00, 0x00, 0x01, 0x00, 0x04, 0x02, 0x01, 0x07, 0x00, 0x83, 0x04, 0x00, 0x46, + 0x50, 0x47, 0x00, 0x03, 0x01, 0x04, 0x00, 0x83, 0x01, 0x00, 0xff, 0x04, 0x01, 0x33, 0x00, 0x01, + 0x30, 0x00, 0x29, 0x41, 0x07, 0xa5, 0x16, 0x35, 0x69, 0x94, 0xff, 0x1c, 0x21, 0x1c, 0x8c, 0x67, + 0x03, 0x21, 0x20, 0xa8, 0x0e, 0xac, 0xce, 0x06, 0xf5, 0x64, 0x54, 0xeb, 0xb7, 0x0c, 0xd4, 0x1f, + 0x70, 0xd1, 0x3e, 0xd5, 0x20, 0xe2, 0x99, 0x96, 0x5b, 0x89, 0xbf, 0x20, 0x34, 0x94, 0x49, 0x0c, + 0x51, 0x3e, 0x05, 0x01, 0x33, 0x00, 0x01, 0x30, 0x00, 0x29, 0x41, 0x07, 0xa5, 0x16, 0x35, 0x69, + 0x94, 0xff, 0x1c, 0x21, 0x1c, 0x8c, 0x67, 0x03, 0x21, 0x20, 0xa8, 0x0e, 0xac, 0xce, 0x06, 0xf5, + 0x64, 0x54, 0xeb, 0xb7, 0x0c, 0xd4, 0x1f, 0x70, 0xd1, 0x3e, 0xd5, 0x20, 0xe2, 0x99, 0x96, 0x5b, + 0x89, 0xbf, 0x20, 0x34, 0x94, 0x49, 0x0c, 0x51, 0x3e, 0x06, 0x01, 0x33, 0x00, 0x01, 0x30, 0x00, + 0x29, 0x41, 0x07, 0xa5, 0x16, 0x35, 0x69, 0x94, 0xff, 0x1c, 0x21, 0x1c, 0x8c, 0x67, 0x03, 0x21, + 0x20, 0xa8, 0x0e, 0xac, 0xce, 0x06, 0xf5, 0x64, 0x54, 0xeb, 0xb7, 0x0c, 0xd4, 0x1f, 0x70, 0xd1, + 0x3e, 0xd5, 0x20, 0xe2, 0x99, 0x96, 0x5b, 0x89, 0xbf, 0x20, 0x34, 0x94, 0x49, 0x0c, 0x51, 0x3e, + 0x07, 0x01, 0x33, 0x00, 0x01, 0x30, 0x00, 0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0x0e, 0x0f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x33, 0x00, 0x01, 0x30, 0x00, 0x0d, 0x0e, + 0x0a, 0x0d, 0x0b, 0x0e, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x01, + 0x33, 0x00, 0x01, 0x30, 0x00, 0x45, 0xb8, 0x93, 0xe0, 0x46, 0xe3, 0xd4, 0x10, 0xbd, 0x39, 0x7f, + 0xcf, 0x97, 0x4d, 0x83, 0xf2, 0x77, 0xe5, 0x48, 0x84, 0xc2, 0x7d, 0x7c, 0x67, 0x62, 0xc1, 0xfa, + 0x6c, 0x0e, 0x43, 0xdd, 0xe7, 0x2f, 0x4f, 0xe9, 0x4d, 0x5c, 0x18, 0x1f, 0x1f, 0x12, 0xdb, 0x41, + 0xbf, 0x46, 0xdc, 0x58, 0x9b, 0x0a, 0x01, 0x33, 0x00, 0x01, 0x30, 0x00, 0x45, 0xb8, 0x93, 0xe0, + 0x46, 0xe3, 0xd4, 0x10, 0xbd, 0x39, 0x7f, 0xcf, 0x97, 0x4d, 0x83, 0xf2, 0x77, 0xe5, 0x48, 0x84, + 0xc2, 0x7d, 0x7c, 0x67, 0x62, 0xc1, 0xfa, 0x6c, 0x0e, 0x43, 0xdd, 0xe7, 0x2f, 0x4f, 0xe9, 0x4d, + 0x5c, 0x18, 0x1f, 0x1f, 0x12, 0xdb, 0x41, 0xbf, 0x46, 0xdc, 0x58, 0x9b, 0x0b, 0x01, 0x33, 0x00, + 0x01, 0x30, 0x00, 0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x01, 0x33, 0x00, 0x01, 0x30, 0x00, 0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, + 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x01, 0x33, 0x00, 0x02, 0x30, + 0x00, 0xa9, 0xbf, 0x6c, 0xac, 0x76, 0x0e, 0x01, 0x1a, 0x1f, 0xee, 0x9f, 0xb9, 0x8b, 0x53, 0x4d, + 0x8b, 0xbb, 0x66, 0x47, 0xf6, 0x45, 0xa0, 0xf8, 0xfe, 0x4a, 0x0a, 0x26, 0xc8, 0x95, 0xd6, 0x5a, + 0x4c, 0xbb, 0x49, 0x71, 0x34, 0xc3, 0xc8, 0x5b, 0xcc, 0xc1, 0xd1, 0x38, 0x41, 0xf4, 0xce, 0xa8, + 0x29, 0x0e, 0x01, 0x33, 0x00, 0x02, 0x30, 0x00, 0xae, 0x40, 0x65, 0x9d, 0xa1, 0x19, 0x3c, 0xde, + 0xc8, 0xdf, 0x47, 0x4b, 0x5e, 0x36, 0x41, 0x6a, 0x82, 0x47, 0x3b, 0x83, 0xd3, 0x2d, 0xbb, 0xe1, + 0xdd, 0x6d, 0xf8, 0xec, 0x94, 0x99, 0xd2, 0x49, 0x02, 0xca, 0x08, 0xc3, 0x34, 0x87, 0x6b, 0xc8, + 0xe6, 0x9e, 0x81, 0x8b, 0xee, 0xcc, 0x04, 0x6a, 0x0f, 0x01, 0x33, 0x00, 0x02, 0x30, 0x00, 0x8d, + 0x2c, 0xe8, 0x7d, 0x86, 0xf5, 0x5f, 0xcf, 0xab, 0x77, 0x0a, 0x04, 0x7b, 0x09, 0x0d, 0xa2, 0x32, + 0x70, 0xfa, 0x20, 0x68, 0x32, 0xdf, 0xea, 0x7e, 0x0c, 0x94, 0x6f, 0xff, 0x45, 0x1f, 0x81, 0x9a, + 0xdd, 0x24, 0x23, 0x74, 0xbe, 0x55, 0x1b, 0x0d, 0x63, 0x18, 0xed, 0x6c, 0x7d, 0x41, 0xd8, 0x10, + 0x01, 0x33, 0x00, 0x02, 0x30, 0x00, 0x29, 0x34, 0x23, 0x0b, 0x3b, 0x71, 0xcb, 0xa3, 0xd4, 0xed, + 0x36, 0xcf, 0x4d, 0xd8, 0xd7, 0x83, 0x57, 0x12, 0x6e, 0xf6, 0x29, 0x96, 0xf7, 0x93, 0xfb, 0x70, + 0xf8, 0xca, 0x82, 0x32, 0x89, 0xdd, 0xfe, 0xa8, 0xbf, 0xd6, 0x7f, 0x59, 0x69, 0x93, 0x21, 0x2f, + 0x56, 0x1b, 0x28, 0xcc, 0x5c, 0xa4, 0x11, 0x01, 0x33, 0x00, 0x02, 0x30, 0x00, 0x28, 0xd7, 0x68, + 0x77, 0x89, 0xc8, 0x9a, 0xe2, 0x8e, 0xf8, 0x6f, 0xa4, 0xc1, 0x7a, 0x42, 0xce, 0xc4, 0x9c, 0x1c, + 0x7f, 0x2e, 0xaa, 0x80, 0x8a, 0x00, 0x3e, 0xa4, 0x2f, 0xde, 0x40, 0xa1, 0x58, 0x63, 0x12, 0xf4, + 0x69, 0x5c, 0xd9, 0x12, 0x43, 0x65, 0x16, 0xc9, 0xea, 0x0e, 0x37, 0xb4, 0x38, 0x12, 0x01, 0x04, + 0x00, 0x81, 0x01, 0x00, 0x01, 0x13, 0x01, 0x04, 0x00, 0x81, 0x01, 0x00, 0x01, 0x14, 0x01, 0x04, + 0x00, 0x83, 0x01, 0x00, 0x01, 0x15, 0x01, 0x04, 0x00, 0x82, 0x01, 0x00, 0xff, 0x16, 0x01, 0x04, + 0x00, 0x82, 0x01, 0x00, 0xff, 0x17, 0x01, 0x04, 0x00, 0x82, 0x01, 0x00, 0xff, 0x18, 0x01, 0x04, + 0x00, 0x82, 0x01, 0x00, 0xff, 0x19, 0x01, 0x04, 0x00, 0x82, 0x01, 0x00, 0xff, 0x1a, 0x01, 0x0b, + 0x00, 0x82, 0x08, 0x00, 0x06, 0x11, 0x04, 0x08, 0x19, 0x07, 0x33, 0x3a, 0x1b, 0x01, 0x33, 0x00, + 0x03, 0x30, 0x00, 0x8a, 0x6f, 0x43, 0x1d, 0xe4, 0xd3, 0x37, 0x1e, 0x86, 0x5a, 0xe0, 0xbc, 0xca, + 0x64, 0x7b, 0xf5, 0x5a, 0x64, 0x39, 0x2a, 0xcf, 0x41, 0x1c, 0x51, 0xe0, 0x38, 0x6b, 0x14, 0x2f, + 0x34, 0xae, 0xbf, 0x86, 0x05, 0x8f, 0x5d, 0x94, 0x2c, 0xd2, 0xb0, 0x7f, 0x66, 0xcc, 0xb9, 0x2b, + 0x8d, 0x81, 0x59, 0x1c, 0x01, 0x33, 0x00, 0x03, 0x30, 0x00, 0x8a, 0x6f, 0x43, 0x1d, 0xe4, 0xd3, + 0x37, 0x1e, 0x86, 0x5a, 0xe0, 0xbc, 0xca, 0x64, 0x7b, 0xf5, 0x5a, 0x64, 0x39, 0x2a, 0xcf, 0x41, + 0x1c, 0x51, 0xe0, 0x38, 0x6b, 0x14, 0x2f, 0x34, 0xae, 0xbf, 0x86, 0x05, 0x8f, 0x5d, 0x94, 0x2c, + 0xd2, 0xb0, 0x7f, 0x66, 0xcc, 0xb9, 0x2b, 0x8d, 0x81, 0x59, 0x1d, 0x01, 0x33, 0x00, 0x03, 0x30, + 0x00, 0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1e, 0x01, 0x33, 0x00, 0x03, 0x30, 0x00, 0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0x0e, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x01, 0x33, 0x00, 0x03, 0x30, 0x00, 0x27, + 0xfd, 0xe1, 0x26, 0x72, 0xda, 0x1b, 0x73, 0xc2, 0x97, 0x9f, 0xe7, 0x12, 0x2c, 0xe9, 0xf6, 0xa6, + 0xda, 0x4b, 0xeb, 0xf1, 0x7f, 0x2f, 0x7f, 0xf8, 0xe7, 0xec, 0xe4, 0x4b, 0xa9, 0xc8, 0x19, 0xd9, + 0x81, 0xf8, 0x05, 0xd3, 0x72, 0x35, 0xc5, 0x94, 0x64, 0x7a, 0x7e, 0xcb, 0xdd, 0x34, 0x3d, 0x20, + 0x01, 0x33, 0x00, 0x03, 0x30, 0x00, 0x27, 0xfd, 0xe1, 0x26, 0x72, 0xda, 0x1b, 0x73, 0xc2, 0x97, + 0x9f, 0xe7, 0x12, 0x2c, 0xe9, 0xf6, 0xa6, 0xda, 0x4b, 0xeb, 0xf1, 0x7f, 0x2f, 0x7f, 0xf8, 0xe7, + 0xec, 0xe4, 0x4b, 0xa9, 0xc8, 0x19, 0xd9, 0x81, 0xf8, 0x05, 0xd3, 0x72, 0x35, 0xc5, 0x94, 0x64, + 0x7a, 0x7e, 0xcb, 0xdd, 0x34, 0x3d, 0x21, 0x01, 0x33, 0x00, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x01, 0x07, + 0x00, 0x83, 0x04, 0x00, 0xff, 0xff, 0xff, 0xff, 0x23, 0x01, 0x04, 0x00, 0x83, 0x01, 0x00, 0x01, + 0x24, 0x01, 0x07, 0x00, 0x83, 0x04, 0x00, 0x34, 0x35, 0x2e, 0x31, 0x25, 0x01, 0x07, 0x00, 0x83, + 0x04, 0x00, 0x34, 0x35, 0x2e, 0x31, 0x26, 0x01, 0x07, 0x00, 0x83, 0x04, 0x00, 0x2e, 0x00, 0x04, + 0x01, 0x27, 0x01, 0x07, 0x00, 0x83, 0x04, 0x00, 0x2e, 0x00, 0x04, 0x01, 0x28, 0x01, 0x07, 0x00, + 0x83, 0x04, 0x00, 0xe9, 0x07, 0x06, 0x0b, 0x29, 0x01, 0x07, 0x00, 0x83, 0x04, 0x00, 0xe9, 0x07, + 0x08, 0x08, 0x2a, 0x01, 0x07, 0x00, 0x83, 0x04, 0x00, 0xe9, 0x07, 0x08, 0x08, 0x2b, 0x01, 0x07, + 0x00, 0x83, 0x04, 0x00, 0x89, 0x08, 0xfd, 0x03, 0x2c, 0x01, 0x13, 0x00, 0x83, 0x10, 0x00, 0x5f, + 0x7f, 0x6a, 0x51, 0x3f, 0x28, 0x4c, 0xc0, 0xbe, 0x5d, 0x49, 0x85, 0xd4, 0xc5, 0x2a, 0x0c, 0x2d, + 0x01, 0x04, 0x00, 0x83, 0x01, 0x00, 0x50, 0x2e, 0x01, 0x33, 0x00, 0x03, 0x30, 0x00, 0xad, 0x17, + 0x05, 0xbc, 0xfb, 0x0a, 0x0e, 0xe3, 0xd9, 0x18, 0xfe, 0xda, 0x1d, 0xc5, 0x62, 0xce, 0xf5, 0xc7, + 0xad, 0x8d, 0xda, 0xdf, 0xe0, 0xe5, 0x34, 0xac, 0xa6, 0x41, 0x69, 0xb7, 0x39, 0x55, 0xf2, 0x18, + 0x50, 0xbc, 0xd2, 0xef, 0x72, 0x51, 0x41, 0x76, 0x59, 0x37, 0xd8, 0x6e, 0xf1, 0x0a, 0x2f, 0x01, + 0x33, 0x00, 0x03, 0x30, 0x00, 0xad, 0x17, 0x05, 0xbc, 0xfb, 0x0a, 0x0e, 0xe3, 0xd9, 0x18, 0xfe, + 0xda, 0x1d, 0xc5, 0x62, 0xce, 0xf5, 0xc7, 0xad, 0x8d, 0xda, 0xdf, 0xe0, 0xe5, 0x34, 0xac, 0xa6, + 0x41, 0x69, 0xb7, 0x39, 0x55, 0xf2, 0x18, 0x50, 0xbc, 0xd2, 0xef, 0x72, 0x51, 0x41, 0x76, 0x59, + 0x37, 0xd8, 0x6e, 0xf1, 0x0a, 0x30, 0x01, 0x33, 0x00, 0x03, 0x30, 0x00, 0x81, 0x4e, 0xe7, 0x4a, + 0x50, 0xeb, 0x88, 0x6d, 0xc9, 0xdf, 0x46, 0xc1, 0x7a, 0xb5, 0x2e, 0xe5, 0x65, 0x15, 0x84, 0x20, + 0x60, 0x90, 0x29, 0x67, 0xb0, 0xea, 0xca, 0xb0, 0x63, 0xde, 0x0d, 0x35, 0x2e, 0xa1, 0x08, 0x28, + 0x34, 0x23, 0x7d, 0xf3, 0x04, 0x83, 0x4f, 0x4d, 0x5d, 0x1b, 0xac, 0x97, 0x31, 0x01, 0x33, 0x00, + 0x03, 0x30, 0x00, 0x81, 0x4e, 0xe7, 0x4a, 0x50, 0xeb, 0x88, 0x6d, 0xc9, 0xdf, 0x46, 0xc1, 0x7a, + 0xb5, 0x2e, 0xe5, 0x65, 0x15, 0x84, 0x20, 0x60, 0x90, 0x29, 0x67, 0xb0, 0xea, 0xca, 0xb0, 0x63, + 0xde, 0x0d, 0x35, 0x2e, 0xa1, 0x08, 0x28, 0x34, 0x23, 0x7d, 0xf3, 0x04, 0x83, 0x4f, 0x4d, 0x5d, + 0x1b, 0xac, 0x97, 0x32, 0x01, 0x27, 0x00, 0x83, 0x24, 0x00, 0x02, 0x00, 0x24, 0x00, 0x2e, 0x00, + 0x04, 0x01, 0xbf, 0xee, 0x5a, 0x80, 0x63, 0x5b, 0x8b, 0x08, 0x6c, 0xc4, 0x00, 0xce, 0x31, 0xe0, + 0x45, 0xd1, 0x06, 0x11, 0x04, 0x08, 0x19, 0x07, 0x33, 0x3a, 0x01, 0x00, 0x01, 0x00, 0x33, 0x01, + 0x08, 0x00, 0x83, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x01, 0x09, 0x00, 0x83, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x01, 0x33, 0x00, 0x03, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x01, + 0x33, 0x00, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x01, 0x33, 0x00, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x01, 0x33, 0x00, + 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x39, 0x01, 0x05, 0x00, 0x83, 0x02, 0x00, 0x00, 0x00, 0x3a, 0x01, 0x27, 0x00, + 0x83, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x01, 0x27, 0x00, 0x83, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x01, 0x27, 0x00, 0x83, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x01, 0x27, + 0x00, 0x83, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x01, 0x33, 0x00, 0x01, 0x30, 0x00, 0x45, + 0xb8, 0x93, 0xe0, 0x46, 0xe3, 0xd4, 0x10, 0xbd, 0x39, 0x7f, 0xcf, 0x97, 0x4d, 0x83, 0xf2, 0x77, + 0xe5, 0x48, 0x84, 0xc2, 0x7d, 0x7c, 0x67, 0x62, 0xc1, 0xfa, 0x6c, 0x0e, 0x43, 0xdd, 0xe7, 0x2f, + 0x4f, 0xe9, 0x4d, 0x5c, 0x18, 0x1f, 0x1f, 0x12, 0xdb, 0x41, 0xbf, 0x46, 0xdc, 0x58, 0x9b, 0x3f, + 0x01, 0x33, 0x00, 0x03, 0x30, 0x00, 0x27, 0xfd, 0xe1, 0x26, 0x72, 0xda, 0x1b, 0x73, 0xc2, 0x97, + 0x9f, 0xe7, 0x12, 0x2c, 0xe9, 0xf6, 0xa6, 0xda, 0x4b, 0xeb, 0xf1, 0x7f, 0x2f, 0x7f, 0xf8, 0xe7, + 0xec, 0xe4, 0x4b, 0xa9, 0xc8, 0x19, 0xd9, 0x81, 0xf8, 0x05, 0xd3, 0x72, 0x35, 0xc5, 0x94, 0x64, + 0x7a, 0x7e, 0xcb, 0xdd, 0x34, 0x3d, 0x40, 0x01, 0x6c, 0x00, 0x81, 0x69, 0x00, 0x00, 0x63, 0x00, + 0x00, 0x00, 0x09, 0x01, 0x00, 0x04, 0x00, 0x47, 0x16, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, 0x16, + 0x20, 0x23, 0xc9, 0x3e, 0xc5, 0x41, 0x15, 0x95, 0xf4, 0x48, 0x70, 0x1d, 0x49, 0xd6, 0x75, 0xff, + 0xff, 0x0d, 0x00, 0x01, 0x0a, 0x47, 0x4c, 0x41, 0x43, 0x49, 0x45, 0x52, 0x44, 0x53, 0x44, 0x50, + 0xff, 0xff, 0x0b, 0x00, 0x01, 0x05, 0x41, 0x50, 0x53, 0x4b, 0x55, 0xef, 0xee, 0xbe, 0x50, 0xff, + 0xff, 0x0b, 0x00, 0x01, 0x05, 0x45, 0x43, 0x53, 0x4b, 0x55, 0x4d, 0x35, 0x36, 0x8b, 0x00, 0x00, + 0x02, 0x00, 0x72, 0x11, 0x00, 0x01, 0x02, 0x00, 0x21, 0x00, 0x01, 0x01, 0x02, 0x00, 0xde, 0x10, + 0x02, 0x01, 0x02, 0x00, 0x5e, 0x21, 0xfe, 0xed, 0xe7, 0xde, 0xbf, 0x89, 0xc0, 0xb2, 0x8d, 0x62, + 0x7f, 0x74, 0xc4, 0xee, 0xce, 0x36, 0x71, 0xb7, 0x36, 0xae, 0xcf, 0x04, 0xc2, 0x24, 0x6b, 0x6a, + 0xcf, 0xae, 0x87, 0xf7, 0x0a, 0x68, 0x00, 0x00, 0x41, 0x8f, 0xfd, 0x14, 0xb3, 0x42, 0x20, 0xe7, + 0x0f, 0x8f, 0x89, 0xdd, 0x68, 0xcf, 0x00, 0x10, 0x77, 0x31, 0xb0, 0x5a, 0x60, 0x69, 0xb3, 0x28, + 0xd5, 0x88, 0xf6, 0x3b, 0x6f, 0x01, 0xfd, 0x0e, 0xb8, 0x08, 0xf4, 0xfb, 0x85, 0x5b, 0xeb, 0xba, + 0x6e, 0x62, 0x25, 0x4e, 0xcf, 0xbc, 0xcc, 0x06, 0xca, 0x64, 0x3b, 0x8b, 0xeb, 0xe4, 0x6a, 0x92, + 0x05, 0x18, 0x54, 0x41, 0xdc, 0xc1, 0xf5, 0xd7, 0xac, 0x8c, 0x8e, 0x75, 0x33, 0xb1, 0xaf, 0x5d, + 0x6d, 0xf6, 0xc6, 0xe0, 0x1b, 0x1a, 0xb9, 0x1f, 0x87, 0xca, 0xb3, 0x98, 0x15, 0x8e, 0xab, 0x92, + 0x89, 0x68, 0x8a, 0x56, 0xba, 0x64, 0x29, 0x94, +}; + +/** + * Test 17: Real-world Broadcom NIC blob (SPDM 1.2, VCA, multi-request with + * unpaired GET_MEASUREMENTS, 4 measurement blocks, 64-byte signature). + **/ +static void req_parse_measurement_transaction_data_case17(void **state) +{ + libspdm_return_t status; + spdm_measurement_block_common_header_t *measurements; + size_t measurement_count; + const uint8_t *ptr; + const spdm_measurement_block_common_header_t *block; + const uint8_t expected_indices[] = {1, 2, 3, 4}; + const uint16_t expected_meas_sizes[] = {35, 35, 35, 35}; + size_t i; + + /* Copy to mutable buffer (function signature takes void *) */ + uint8_t broadcom_buf[sizeof(broadcom_nic_blob)]; + memcpy(broadcom_buf, broadcom_nic_blob, sizeof(broadcom_nic_blob)); + + status = libspdm_parse_measurement_transaction_data( + broadcom_buf, sizeof(broadcom_buf), + &measurements, &measurement_count); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + assert_int_equal(measurement_count, 4); + assert_non_null(measurements); + + ptr = (const uint8_t *)measurements; + for (i = 0; i < measurement_count; i++) { + block = (const spdm_measurement_block_common_header_t *)ptr; + assert_int_equal(block->index, expected_indices[i]); + assert_int_equal(block->measurement_specification, + SPDM_MEASUREMENT_SPECIFICATION_DMTF); + assert_int_equal(block->measurement_size, expected_meas_sizes[i]); + ptr += sizeof(spdm_measurement_block_common_header_t) + block->measurement_size; + } + + /* Verify first bytes of block 1 value (4b 8f 6b 7a) */ + ptr = (const uint8_t *)measurements; + block = (const spdm_measurement_block_common_header_t *)ptr; + /* DMTF header is 3 bytes (type + value_size), then the value starts */ + assert_int_equal(ptr[4 + 3], 0x4b); + assert_int_equal(ptr[4 + 4], 0x8f); + assert_int_equal(ptr[4 + 5], 0x6b); + assert_int_equal(ptr[4 + 6], 0x7a); + + free(measurements); +} + +/** + * Test 18: Real-world NVIDIA FPGA blob (SPDM 1.1, no VCA, single signed + * GET_MEASUREMENTS(0xFF), 64 measurement blocks, 96-byte signature). + **/ +static void req_parse_measurement_transaction_data_case18(void **state) +{ + libspdm_return_t status; + spdm_measurement_block_common_header_t *measurements; + size_t measurement_count; + const uint8_t *ptr; + const spdm_measurement_block_common_header_t *block; + size_t i; + + /* Copy to mutable buffer (function signature takes void *) */ + uint8_t nvidia_buf[sizeof(nvidia_fpga_blob)]; + memcpy(nvidia_buf, nvidia_fpga_blob, sizeof(nvidia_fpga_blob)); + + status = libspdm_parse_measurement_transaction_data( + nvidia_buf, sizeof(nvidia_buf), + &measurements, &measurement_count); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + assert_int_equal(measurement_count, 64); + assert_non_null(measurements); + + /* Verify all blocks have sequential indices 1..64 and DMTF spec */ + ptr = (const uint8_t *)measurements; + for (i = 0; i < measurement_count; i++) { + block = (const spdm_measurement_block_common_header_t *)ptr; + assert_int_equal(block->index, i + 1); + assert_int_equal(block->measurement_specification, + SPDM_MEASUREMENT_SPECIFICATION_DMTF); + ptr += sizeof(spdm_measurement_block_common_header_t) + block->measurement_size; + } + + /* Verify first block: index=1, meas_size=7, DMTF type=0x83, value_size=4 */ + block = (const spdm_measurement_block_common_header_t *)measurements; + assert_int_equal(block->measurement_size, 7); + ptr = (const uint8_t *)measurements + + sizeof(spdm_measurement_block_common_header_t); + assert_int_equal(ptr[0], 0x83); /* dmtf type */ + assert_int_equal(ptr[1], 0x04); /* value_size low byte */ + assert_int_equal(ptr[2], 0x00); /* value_size high byte */ + + free(measurements); +} + +static libspdm_return_t send_message(void *spdm_context, size_t request_size, + const void *request, uint64_t timeout) +{ + return LIBSPDM_STATUS_SUCCESS; +} + +static libspdm_return_t receive_message(void *spdm_context, size_t *response_size, + void **response, uint64_t timeout) +{ + return LIBSPDM_STATUS_SUCCESS; +} + +int libspdm_req_parse_measurement_transaction_data_test(void) +{ + const struct CMUnitTest test_cases[] = { + cmocka_unit_test(req_parse_measurement_transaction_data_case1), + cmocka_unit_test(req_parse_measurement_transaction_data_case2), + cmocka_unit_test(req_parse_measurement_transaction_data_case3), + cmocka_unit_test(req_parse_measurement_transaction_data_case4), + cmocka_unit_test(req_parse_measurement_transaction_data_case5), + cmocka_unit_test(req_parse_measurement_transaction_data_case6), + cmocka_unit_test(req_parse_measurement_transaction_data_case7), + cmocka_unit_test(req_parse_measurement_transaction_data_case8), + cmocka_unit_test(req_parse_measurement_transaction_data_case9), + cmocka_unit_test(req_parse_measurement_transaction_data_case10), + cmocka_unit_test(req_parse_measurement_transaction_data_case11), + cmocka_unit_test(req_parse_measurement_transaction_data_case12), + cmocka_unit_test(req_parse_measurement_transaction_data_case13), + cmocka_unit_test(req_parse_measurement_transaction_data_case14), + cmocka_unit_test(req_parse_measurement_transaction_data_case15), + cmocka_unit_test(req_parse_measurement_transaction_data_case16), + cmocka_unit_test(req_parse_measurement_transaction_data_case17), + cmocka_unit_test(req_parse_measurement_transaction_data_case18), + }; + + libspdm_test_context_t test_context = { + LIBSPDM_TEST_CONTEXT_VERSION, + true, + send_message, + receive_message, + }; + + libspdm_setup_test_context(&test_context); + + return cmocka_run_group_tests(test_cases, + libspdm_unit_test_group_setup, + libspdm_unit_test_group_teardown); +} diff --git a/unit_test/test_spdm_requester/test_spdm_requester.c b/unit_test/test_spdm_requester/test_spdm_requester.c index b8f44863d0b..89383fab5f1 100644 --- a/unit_test/test_spdm_requester/test_spdm_requester.c +++ b/unit_test/test_spdm_requester/test_spdm_requester.c @@ -29,6 +29,8 @@ int libspdm_req_get_measurements_test(void); int libspdm_req_get_measurements_error_test(void); #endif /* LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP*/ +int libspdm_req_parse_measurement_transaction_data_test(void); + #if LIBSPDM_ENABLE_CAPABILITY_MEL_CAP int libspdm_req_get_measurement_extension_log_test(void); #endif /* LIBSPDM_ENABLE_CAPABILITY_MEL_CAP*/ @@ -140,6 +142,10 @@ int main(void) return_value = 1; } + if (libspdm_req_parse_measurement_transaction_data_test() != 0) { + return_value = 1; + } + #if LIBSPDM_SEND_GET_CERTIFICATE_SUPPORT if (libspdm_req_get_digests_test() != 0) { return_value = 1;