From 1f239db37036b3e08823360e451394c84da6d6bd Mon Sep 17 00:00:00 2001 From: Wilfred Mallawa Date: Tue, 19 Nov 2024 16:35:26 +1000 Subject: [PATCH 1/5] libspdm_common_lib: support bswap functionality Add support for bswap16 and 32. Also rename the existing `libspdm_le_to_be_64` to `libspdm_byte_swap_64` for consistency. Signed-off-by: Wilfred Mallawa --- include/internal/libspdm_common_lib.h | 16 +++++++++++++++- unit_test/test_spdm_common/support.c | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/include/internal/libspdm_common_lib.h b/include/internal/libspdm_common_lib.h index bcebfde2e7d..8c43fc3c510 100644 --- a/include/internal/libspdm_common_lib.h +++ b/include/internal/libspdm_common_lib.h @@ -1702,7 +1702,7 @@ static inline bool libspdm_onehot0(uint32_t mask) return !mask || !(mask & (mask - 1)); } -static inline uint64_t libspdm_le_to_be_64(uint64_t value) +static inline uint64_t libspdm_byte_swap_64(uint64_t value) { return (((value & 0x00000000000000ff) << 56) | ((value & 0x000000000000ff00) << 40) | @@ -1714,6 +1714,20 @@ static inline uint64_t libspdm_le_to_be_64(uint64_t value) ((value & 0xff00000000000000) >> 56)); } +static inline uint32_t libspdm_byte_swap_32(uint32_t value) +{ + return ((value & 0x000000FF) << 24) | + ((value & 0x0000FF00) << 8) | + ((value & 0x00FF0000) >> 8) | + ((value & 0xFF000000) >> 24); +} + +static inline uint16_t libspdm_byte_swap_16(uint16_t value) +{ + return ((value & 0x00FF) << 8) | + ((value & 0xFF00) >> 8); +} + /** * Return capability flags that are masked by the negotiated SPDM version. * diff --git a/unit_test/test_spdm_common/support.c b/unit_test/test_spdm_common/support.c index 3ffe0a16e72..63617c65112 100644 --- a/unit_test/test_spdm_common/support.c +++ b/unit_test/test_spdm_common/support.c @@ -6,7 +6,7 @@ **/ static void libspdm_test_common_context_data_case1(void **state) { - assert_int_equal(0x0001020304050607, libspdm_le_to_be_64(UINT64_C(0x0706050403020100))); + assert_int_equal(0x0001020304050607, libspdm_byte_swap_64(UINT64_C(0x0706050403020100))); } int libspdm_common_support_test_main(void) From f830d64e4b1c5c1d5e91bc83e5963d47bc0d8fc1 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 12 Mar 2024 10:51:10 +1000 Subject: [PATCH 2/5] library: Initial support for storage transport As defined by DSP0826, add support for SPDM storage transport. The transport layer uses a virtual storage header that encapsulates SPDM requests to allow the caller to generate the required parameters for a storage SPDM request. SPDM responses are not transport encoded, with this header, instead just the message is returned. Signed-off-by: Wilfred Mallawa Signed-off-by: Alistair Francis --- CMakeLists.txt | 3 + .../industry_standard/spdm_storage_binding.h | 45 + include/library/spdm_transport_storage_lib.h | 244 ++++++ .../libspdm_secmes_encode_decode.c | 2 +- .../spdm_transport_storage_lib/CMakeLists.txt | 9 + .../libspdm_storage.c | 792 ++++++++++++++++++ 6 files changed, 1094 insertions(+), 1 deletion(-) create mode 100644 include/industry_standard/spdm_storage_binding.h create mode 100644 include/library/spdm_transport_storage_lib.h create mode 100644 library/spdm_transport_storage_lib/CMakeLists.txt create mode 100644 library/spdm_transport_storage_lib/libspdm_storage.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 92a9789db87..9ff870b27e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -894,6 +894,7 @@ if(ENABLE_CODEQL STREQUAL "ON") add_subdirectory(library/spdm_secured_message_lib) add_subdirectory(library/spdm_transport_mctp_lib) add_subdirectory(library/spdm_transport_pcidoe_lib) + ADD_SUBDIRECTORY(library/spdm_transport_storage_lib) add_subdirectory(os_stub/memlib) add_subdirectory(os_stub/debuglib) add_subdirectory(os_stub/debuglib_null) @@ -931,6 +932,7 @@ else() add_subdirectory(library/spdm_secured_message_lib) add_subdirectory(library/spdm_transport_mctp_lib) add_subdirectory(library/spdm_transport_pcidoe_lib) + ADD_SUBDIRECTORY(library/spdm_transport_storage_lib) add_subdirectory(os_stub/memlib) add_subdirectory(os_stub/debuglib) add_subdirectory(os_stub/debuglib_null) @@ -1070,6 +1072,7 @@ else() $ $ $ + $ ) add_library(${LIB_NAME}_platform SHARED diff --git a/include/industry_standard/spdm_storage_binding.h b/include/industry_standard/spdm_storage_binding.h new file mode 100644 index 00000000000..af0cd1706a9 --- /dev/null +++ b/include/industry_standard/spdm_storage_binding.h @@ -0,0 +1,45 @@ +/** + * Copyright Notice: + * Copyright 2024 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md + **/ + +/** @file + * Definitions of SPDM over the Storage as defined in DSP0286 + **/ + +#ifndef SPDM_STORAGE_BINDING_H +#define SPDM_STORAGE_BINDING_H + +#pragma pack(1) + +typedef struct { + uint16_t data_length; + uint16_t storage_binding_version; + uint8_t connection_parameters; + uint8_t reserved1[3]; + uint8_t supported_operations; + uint8_t reserved2[7]; + uint8_t reserved3[16]; +} spdm_storage_discovery_response_t; + +typedef struct { + uint16_t data_length; + uint16_t storage_binding_version; + uint32_t pending_info_flag; + uint32_t response_length; +} spdm_storage_pending_info_response_t; + +#define SPDM_STORAGE_SECURITY_BINDING_VERSION 0x1000 +#define SPDM_STORAGE_SECURITY_PROTOCOL_DMTF 0xE8 + +#define SPDM_STORAGE_OPERATION_CODE_DISCOVERY 0x01 +#define SPDM_STORAGE_OPERATION_CODE_PENDING_INFO 0x02 +#define SPDM_STORAGE_OPERATION_CODE_MESSAGE 0x05 +#define SPDM_STORAGE_OPERATION_CODE_SECURED_MESSAGE 0x06 + +#define SPDM_STORAGE_MAX_CONNECTION_ID_MASK 0x3 + +#pragma pack() + +#endif /* STORAGE_BINDING_H */ diff --git a/include/library/spdm_transport_storage_lib.h b/include/library/spdm_transport_storage_lib.h new file mode 100644 index 00000000000..1c24d380ff8 --- /dev/null +++ b/include/library/spdm_transport_storage_lib.h @@ -0,0 +1,244 @@ +/** + * Copyright Notice: + * Copyright 2024 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md + **/ + +#ifndef STORAGE_TRANSPORT_LIB_H +#define STORAGE_TRANSPORT_LIB_H + +#include "library/spdm_common_lib.h" +#include "library/spdm_crypt_lib.h" + +#define LIBSPDM_STORAGE_SEQUENCE_NUMBER_COUNT 0 +#define LIBSPDM_STORAGE_MAX_RANDOM_NUMBER_COUNT 0 + +/* + * SPDM Storage transport binding header for request encoding as defined by + * DSP0286. This header is not specific to any particular storage type, i.e + * SCSI, NVMe or ATA. Instead, it is used to encode requests (host to controller), + * to provide transport specific SPDM information. This information shall then + * be used to generate the storage protocol specific command. Refer to the + * storage specification for field sizes, offsets and application. + * + * As such, this header *shall not* be transmitted as a part of the libspdm + * message, instead be used only as required to generate the storage specific + * command(s). + * + * +-----------------+--------+-------------------+---------+--------+--+ + * | TYPE |Security| Security | INC_512 | Length | | + * | |Protocol| Protocol Specific | | | | + * +-----------------+--------+-------------------+---------+--------+ + + * |Security Protocol| 1 | 2 | 1 | 4 | | + * +-----------------+--------+-------------------+---------+--------+--+ + * + * This structure is publicly defined to provide transport encoding information + * to the caller from transport_message buffer(s). + */ +#pragma pack(1) +typedef struct { + uint8_t security_protocol; + uint16_t security_protocol_specific; + bool inc_512; + uint32_t length; +} storage_spdm_transport_header; +#pragma pack() + +#define LIBSPDM_STORAGE_TRANSPORT_HEADER_SIZE (1 + 2 + 1 + 4) +#define LIBSPDM_STORAGE_TRANSPORT_TAIL_SIZE (0) + +#define LIBSPDM_STORAGE_CMD_DIRECTION_IF_SEND 0x01 +#define LIBSPDM_STORAGE_CMD_DIRECTION_IF_RECV 0x02 + +/** + * Decode an Security Protocol Command message to a normal message or secured message. + * + * @param session_id Indicates if it is a secured message protected via SPDM session. + * If *session_id is NULL, it is a normal message. + * If *session_id is NOT NULL, it is a secured message. + * @param connection_id Indicates the connection ID of the message. + * @param transport_message_size size in bytes of the transport message data buffer. + * @param transport_message A pointer to a source buffer to store the transport message. + * @param message_size size in bytes of the message data buffer. + * @param message A pointer to a destination buffer to store the message. + * + * @retval RETURN_SUCCESS The message is encoded successfully. + * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE The message is NULL or the transport_message_size is zero. + * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD The message field is incorrect. + **/ +libspdm_return_t libspdm_storage_decode_message(uint32_t **session_id, + uint8_t *connection_id, + size_t transport_message_size, + void *transport_message, + size_t *message_size, + void **message); +/** + * Decode an SPDM or APP message from a storage transport layer message. + * + * For normal SPDM message, it removes the transport layer wrapper, + * For secured SPDM message, it removes the transport layer wrapper, then decrypts and verifies a secured message. + * For secured APP message, it removes the transport layer wrapper, then decrypts and verifies a secured message. + * + * The APP message is decoded from a secured message directly in SPDM session. + * The APP message format is defined by the transport layer. + * Take MCTP as example: APP message == MCTP header (MCTP_MESSAGE_TYPE_SPDM) + SPDM message + * + * @param spdm_context A pointer to the SPDM context. + * @param session_id Indicates if it is a secured message protected via SPDM session. + * If session_id is NULL, it is a normal message. + * If session_id is not NULL, it is a secured message. + * @param is_app_message Indicates if it is an APP message or SPDM message. + * @param is_request_message Indicates if it is a request message. + * @param transport_message_size Size in bytes of the transport message data buffer. + * @param transport_message A pointer to a source buffer to store the transport message. + * For normal message or secured message, it shall point to acquired receiver buffer. + * @param message_size Size in bytes of the message data buffer. + * @param message A pointer to a destination buffer to store the message. + * On input, it shall point to the scratch buffer in spdm_context. + * On output, for normal message, it will point to the original receiver buffer. + * On output, for secured message, it will point to the scratch buffer in spdm_context. + * + * @retval RETURN_SUCCESS The message is decoded successfully. + * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE The message is NULL or the message_size is zero. + * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD The message field is incorrect. + * @retval LIBSPDM_STATUS_UNSUPPORTED_CAP The transport_message is unsupported. + **/ +libspdm_return_t libspdm_transport_storage_decode_message( + void *spdm_context, uint32_t **session_id, + bool *is_app_message, bool is_request_message, + size_t transport_message_size, void *transport_message, + size_t *message_size, void **message); + + +/** + * Encode a normal message or secured message to a storage transport message. + * + * @param session_id Indicates if it is a secured message protected via SPDM session. + * If *session_id is NULL, it is a normal message. + * If *session_id is NOT NULL, it is a secured message. + * @param connection_id Indicates the connection ID of the message. + * @param message_size size in bytes of the message data buffer. + * @param message A pointer to a destination buffer to store the message. + * @param transport_message_size Size in bytes of the transport message data buffer. + * On return, length of the transport message. + * @param transport_message A pointer to a source buffer to store the transport message. + * + * @retval RETURN_SUCCESS The message is encoded successfully. + * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE The message is NULL or the message_size/transport_message_size is zero. + * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD The message field is incorrect. + * @retval LIBSPDM_STATUS_BUFFER_TOO_SMALL Insufficient transport buffer size. + **/ +libspdm_return_t libspdm_storage_encode_message(const uint32_t *session_id, + uint8_t connection_id, + size_t message_size, void *message, + size_t *transport_message_size, + void **transport_message); + +/** + * Encode an SPDM or APP message into a transport layer message. + * + * @param spdm_context A pointer to the SPDM context. + * @param session_id Indicates if it is a secured message protected via SPDM session. + * If session_id is NULL, it is a normal message. + * If session_id is not NULL, it is a secured message. + * @param is_app_message Indicates if it is an APP message or SPDM message. + * @param is_request_message Indicates if it is a request message. + * @param message_size Size in bytes of the message data buffer. + * @param message A pointer to a destination buffer to store the message. + * On input, it shall point to the scratch buffer in spdm_context. + * On output, for normal message, it will point to the original receiver buffer. + * On output, for secured message, it will point to the scratch buffer in spdm_context. + * @param transport_message_size Size in bytes of the transport message data buffer. + * @param transport_message A pointer to a source buffer to store the transport message. + * For normal message or secured message, it shall point to acquired receiver buffer. + * + * @retval RETURN_SUCCESS The message is decoded successfully. + * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE The message is NULL or the message_size is zero. + * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD The message field is incorrect. + * @retval LIBSPDM_STATUS_UNSUPPORTED_CAP The transport_message is unsupported. + **/ +libspdm_return_t libspdm_transport_storage_encode_message( + void *spdm_context, const uint32_t *session_id, + bool is_app_message, + bool is_request_message, size_t message_size, void *message, + size_t *transport_message_size, void **transport_message); + +/** + * Decode a storage transport management command + * + * @param transport_message_size Size in bytes of the transport message data buffer. + * @param transport_message A pointer to an encoded transport message buffer. + * @param transport_command Storage transport command contained in transport message + * @param length On return, this specifies allocation length + * or transfer length. Depending of if the + * message was an IF_RECV or IF_SEND respectively. + * + * @retval RETURN_SUCCESS The message is decoded successfully. + * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE The message is NULL or the message_size is zero. + * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD The message field is incorrect. + * @retval LIBSPDM_STATUS_UNSUPPORTED_CAP The transport_message is unsupported. + **/ +libspdm_return_t libspdm_transport_storage_decode_management_cmd( + size_t transport_message_size, + const void *transport_message, + uint8_t *transport_command, + uint32_t *length); + +/** + * Encode a storage transport management command, supports only Discovery and + * Pending Info. + * + * @param cmd_direction Specify the direction of the command IF_SEND/RECV + * @param transport_operation Transport operation type, Discovery/Pending Info + * @param connection_id SPDM Connection ID + * @param transport_message_size Size in bytes of the transport message data buffer. + * On return, the length of the encoded message + * @param allocation_length Storage buffer allocation length + * @param transport_message A pointer to a transport message buffer. + * + * @retval RETURN_SUCCESS The message is encoded successfully. + * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE The message is NULL or the message_size is zero. + * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD The message field is incorrect. + * @retval LIBSPDM_STATUS_BUFFER_TOO_SMALL Insufficient transport buffer size + **/ +libspdm_return_t libspdm_transport_storage_encode_management_cmd( + uint8_t cmd_direction, uint8_t transport_operation, + uint8_t connection_id, size_t *transport_message_size, + size_t *allocation_length, void *transport_message); + +/** + * Encode a storage transport discovery response. As defined by the DMTF DSP0286 + * + * @param transport_message_size Size in bytes of the transport message data buffer. + * On return, the size of the response + * @param transport_message A pointer to a source buffer to store the transport message. + * + * @retval RETURN_SUCCESS The message is decoded successfully. + * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE The message is NULL or the message_size is zero. + * @retval LIBSPDM_STATUS_BUFFER_TOO_SMALL @transport_message is too small + **/ +libspdm_return_t libspdm_transport_storage_encode_discovery_response( + size_t *transport_message_size, + void *transport_message); + +/** + * Encode a storage transport pending response. As defined by the DMTF DSP0286 + * + * @param transport_message_size Size in bytes of the transport message data buffer. + * On return, the size of the response + * @param transport_message A pointer to a source buffer to store the transport message. + * @param response_pending If true, the responder has a pending response + * @param pending_response_length Valid only if @response_pending is true, + * specifies the length of the pending message + * in bytes. + * + * @retval RETURN_SUCCESS The message is decoded successfully. + * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE The message is NULL or the message_size is zero. + * @retval LIBSPDM_STATUS_BUFFER_TOO_SMALL @transport_message is too small + **/ +libspdm_return_t libspdm_transport_storage_encode_pending_info_response( + size_t *transport_message_size, + void *transport_message, bool response_pending, + uint32_t pending_response_length); + +#endif /* STORAGE_TRANSPORT_LIB_H */ diff --git a/library/spdm_secured_message_lib/libspdm_secmes_encode_decode.c b/library/spdm_secured_message_lib/libspdm_secmes_encode_decode.c index 1d91abe23f5..39feb49994d 100644 --- a/library/spdm_secured_message_lib/libspdm_secmes_encode_decode.c +++ b/library/spdm_secured_message_lib/libspdm_secmes_encode_decode.c @@ -29,7 +29,7 @@ static void generate_iv(uint64_t sequence_number, uint8_t *iv, const uint8_t *sa case LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_BIG_DEC_BOTH: /* If big-endian then the sequence number is zero-extended to the lower indices. * The sequence number ends at the highest index (aead_size - 1). */ - sequence_number = libspdm_le_to_be_64(sequence_number); + sequence_number = libspdm_byte_swap_64(sequence_number); libspdm_copy_mem(iv_temp + (aead_iv_size - sizeof(sequence_number)), aead_iv_size, &sequence_number, diff --git a/library/spdm_transport_storage_lib/CMakeLists.txt b/library/spdm_transport_storage_lib/CMakeLists.txt new file mode 100644 index 00000000000..a198df075f4 --- /dev/null +++ b/library/spdm_transport_storage_lib/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.5) + +INCLUDE_DIRECTORIES(${LIBSPDM_DIR}/include) + +SET(src_spdm_transport_storage_lib + libspdm_storage.c +) + +ADD_LIBRARY(spdm_transport_storage_lib STATIC ${src_spdm_transport_storage_lib}) diff --git a/library/spdm_transport_storage_lib/libspdm_storage.c b/library/spdm_transport_storage_lib/libspdm_storage.c new file mode 100644 index 00000000000..72a0b0d2b44 --- /dev/null +++ b/library/spdm_transport_storage_lib/libspdm_storage.c @@ -0,0 +1,792 @@ +/** + * Copyright Notice: + * Copyright 2024 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md + **/ + +#include "library/spdm_transport_storage_lib.h" +#include "industry_standard/spdm_storage_binding.h" +#include "internal/libspdm_common_lib.h" +#include "hal/library/debuglib.h" +#include "hal/library/memlib.h" + +/** + * This function translates the negotiated secured_message_version to a DSP0277 version. + * + * @param secured_message_version The version specified in binding specification and + * negotiated in KEY_EXCHANGE/KEY_EXCHANGE_RSP. + * + * @return The DSP0277 version specified in binding specification, + * which is bound to secured_message_version. + */ +spdm_version_number_t libspdm_storage_get_secured_spdm_version( + spdm_version_number_t secured_message_version) +{ + return secured_message_version; +} + +/** + * Return max random number count in an SPDM secure message. + * + * This value is transport layer specific. + * + * @return Max random number count in an SPDM secured message. + * 0 means no random number is required. + **/ +uint32_t libspdm_storage_get_max_random_number_count(void) +{ + return LIBSPDM_STORAGE_MAX_RANDOM_NUMBER_COUNT; +} + +/** + * Get sequence number in an SPDM secure message. + * + * This value is transport layer specific. + * + * @param sequence_number The current sequence number used to encode or decode message. + * @param sequence_number_buffer A buffer to hold the sequence number output used in the secured message. + * The size in byte of the output buffer shall be 8. + * + * @return size in byte of the sequence_number_buffer. + * It shall be no greater than 8. + * 0 means no sequence number is required. + **/ +uint8_t libspdm_storage_get_sequence_number(uint64_t sequence_number, + uint8_t *sequence_number_buffer) +{ + libspdm_copy_mem(sequence_number_buffer, LIBSPDM_STORAGE_SEQUENCE_NUMBER_COUNT, + &sequence_number, LIBSPDM_STORAGE_SEQUENCE_NUMBER_COUNT); + return LIBSPDM_STORAGE_SEQUENCE_NUMBER_COUNT; +} + +/** + * Decode an Security Protocol Command message to a normal message or secured message. + * + * @param session_id Indicates if it is a secured message protected via SPDM session. + * If *session_id is NULL, it is a normal message. + * If *session_id is NOT NULL, it is a secured message. + * @param connection_id Indicates the connection ID of the message. + * @param transport_message_size size in bytes of the transport message data buffer. + * @param transport_message A pointer to a source buffer to store the transport message. + * @param message_size size in bytes of the message data buffer. + * @param message A pointer to a destination buffer to store the message. + * + * @retval RETURN_SUCCESS The message is encoded successfully. + * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE The message is NULL or the transport_message_size is zero. + * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD The message field is incorrect. + **/ +libspdm_return_t libspdm_storage_decode_message(uint32_t **session_id, + uint8_t *connection_id, + size_t transport_message_size, + void *transport_message, + size_t *message_size, + void **message) +{ + const storage_spdm_transport_header *storage_header; + uint32_t storage_length; + uint16_t security_protocol_specific; + uint8_t spsp0, spsp1, spdm_operation; + + LIBSPDM_ASSERT(transport_message_size >= sizeof(storage_spdm_transport_header)); + if (transport_message_size <= sizeof(storage_spdm_transport_header)) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + + if (transport_message_size == 0) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + + storage_header = transport_message; + if (storage_header->security_protocol != SPDM_STORAGE_SECURITY_PROTOCOL_DMTF) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + +#if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ + security_protocol_specific = libspdm_byte_swap_16(storage_header->security_protocol_specific); +#else + security_protocol_specific = storage_header->security_protocol_specific; +#endif + spsp0 = security_protocol_specific & 0xFF; + spsp1 = security_protocol_specific >> 8; + + if (spsp1 != 0) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + + if (connection_id) { + *connection_id = spsp0 & 0x03; + } + spdm_operation = (spsp0 & 0xFC) >> 2; + + switch (spdm_operation) { + case SPDM_STORAGE_OPERATION_CODE_DISCOVERY: + case SPDM_STORAGE_OPERATION_CODE_PENDING_INFO: + case SPDM_STORAGE_OPERATION_CODE_MESSAGE: + if (session_id != NULL) { + *session_id = NULL; + } + break; + case SPDM_STORAGE_OPERATION_CODE_SECURED_MESSAGE: + LIBSPDM_ASSERT(session_id != NULL); + if (session_id == NULL) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + if (transport_message_size <= + sizeof(storage_spdm_transport_header) + sizeof(uint32_t)) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + *session_id = (void *)((uint8_t *)transport_message + + sizeof(storage_spdm_transport_header)); + break; + default: + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + +#if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ + storage_length = libspdm_byte_swap_32(storage_header->length); +#else + storage_length = storage_header->length; +#endif + if (storage_length != transport_message_size) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + + *message_size = transport_message_size - sizeof(storage_spdm_transport_header); + *message = (uint8_t *)transport_message + sizeof(storage_spdm_transport_header); + + return LIBSPDM_STATUS_SUCCESS; +} + +/** + * Decode an SPDM or APP message from a storage transport layer message. + * + * For normal SPDM message, it removes the transport layer wrapper, + * For secured SPDM message, it removes the transport layer wrapper, then decrypts and verifies a secured message. + * For secured APP message, it removes the transport layer wrapper, then decrypts and verifies a secured message. + * + * The APP message is decoded from a secured message directly in SPDM session. + * The APP message format is defined by the transport layer. + * Take MCTP as example: APP message == MCTP header (MCTP_MESSAGE_TYPE_SPDM) + SPDM message + * + * @param spdm_context A pointer to the SPDM context. + * @param session_id On entry, indicates if it is a secured message protected via SPDM session. + * If session_id is NULL, it is a normal message. + * If session_id is not NULL, it is a secured message. + * @param is_app_message Indicates if it is an APP message or SPDM message. + * @param is_request_message Indicates if it is a request message. + * @param transport_message_size Size in bytes of the transport message data buffer. + * @param transport_message A pointer to a source buffer to store the transport message. + * For normal message or secured message, it shall point to acquired receiver buffer. + * @param message_size Size in bytes of the message data buffer. + * @param message A pointer to a destination buffer to store the message. + * On input, it shall point to the scratch buffer in spdm_context. + * On output, for normal message, it will point to the original receiver buffer. + * On output, for secured message, it will point to the scratch buffer in spdm_context. + * + * @retval RETURN_SUCCESS The message is decoded successfully. + * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE The message is NULL or the message_size is zero. + * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD The message field is incorrect. + * @retval LIBSPDM_STATUS_UNSUPPORTED_CAP The transport_message is unsupported. + **/ +libspdm_return_t libspdm_transport_storage_decode_message( + void *spdm_context, uint32_t **session_id, + bool *is_app_message, bool is_request_message, + size_t transport_message_size, void *transport_message, + size_t *message_size, void **message) +{ + libspdm_return_t status; + uint32_t *secured_message_session_id; + uint8_t *secured_message; + size_t secured_message_size; + size_t secure_msg_reserved_bytes = sizeof(uint32_t); + libspdm_secured_message_callbacks_t spdm_secured_message_callbacks; + void *secured_message_context; + libspdm_error_struct_t spdm_error; + + spdm_error.error_code = 0; + spdm_error.session_id = 0; + libspdm_set_last_spdm_error_struct(spdm_context, &spdm_error); + + spdm_secured_message_callbacks.version = + LIBSPDM_SECURED_MESSAGE_CALLBACKS_VERSION; + spdm_secured_message_callbacks.get_sequence_number = + libspdm_storage_get_sequence_number; + spdm_secured_message_callbacks.get_max_random_number_count = + libspdm_storage_get_max_random_number_count; + spdm_secured_message_callbacks.get_secured_spdm_version = + libspdm_storage_get_secured_spdm_version; + + if ((session_id == NULL) || (is_app_message == NULL)) { + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + *is_app_message = false; + + secured_message_session_id = NULL; + + if (!is_request_message) { + /* + * Storage response messages are not transport encoded, this is the SPDM + * message, and shall be processed as such. Which also means that there + * is no way from the response to determine if it's secure or not, instead + * use internal state to determine. + */ + /* Expecting a secured message */ + if (*session_id != NULL) { + **session_id = + *((uint32_t *)(((uint8_t *)transport_message) + secure_msg_reserved_bytes)); + + secured_message_context = + libspdm_get_secured_message_context_via_session_id( + spdm_context, **session_id); + if (secured_message_context == NULL) { + spdm_error.error_code = SPDM_ERROR_CODE_INVALID_SESSION; + spdm_error.session_id = **session_id; + libspdm_set_last_spdm_error_struct(spdm_context, + &spdm_error); + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + + /* + * Secured message to message + * + * DSP0286 specifies 4 reserved bytes at the start of a secured + * message. Skip that for decoding. + */ + status = libspdm_decode_secured_message( + secured_message_context, **session_id, + is_request_message, transport_message_size - secure_msg_reserved_bytes, + ((uint8_t *)transport_message) + secure_msg_reserved_bytes, + message_size, message, &spdm_secured_message_callbacks); + + + if (LIBSPDM_STATUS_IS_ERROR(status)) { + LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, + "libspdm_decode_secured_message - %xu\n", status)); + libspdm_secured_message_get_last_spdm_error_struct( + secured_message_context, &spdm_error); + libspdm_set_last_spdm_error_struct(spdm_context, + &spdm_error); + return status; + } + + } else { + *message_size = transport_message_size; + *message = transport_message; + *session_id = NULL; + }; + return LIBSPDM_STATUS_SUCCESS; + } else { + /* Storage requests need to be transport encoded/decoded */ + status = libspdm_storage_decode_message( + &secured_message_session_id, 0, transport_message_size, + transport_message, &secured_message_size, (void **)&secured_message); + + if (LIBSPDM_STATUS_IS_ERROR(status)) { + LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "transport_decode_message - %xu\n", status)); + return status; + } + + if (secured_message_session_id != NULL) { + *session_id = secured_message_session_id; + + secured_message_context = + libspdm_get_secured_message_context_via_session_id( + spdm_context, *secured_message_session_id); + if (secured_message_context == NULL) { + spdm_error.error_code = SPDM_ERROR_CODE_INVALID_SESSION; + spdm_error.session_id = *secured_message_session_id; + libspdm_set_last_spdm_error_struct(spdm_context, + &spdm_error); + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + + /* Secured message to message*/ + status = libspdm_decode_secured_message( + secured_message_context, *secured_message_session_id, + is_request_message, secured_message_size, secured_message, + message_size, message, + &spdm_secured_message_callbacks); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, + "libspdm_decode_secured_message - %xu\n", status)); + libspdm_secured_message_get_last_spdm_error_struct( + secured_message_context, &spdm_error); + libspdm_set_last_spdm_error_struct(spdm_context, + &spdm_error); + return status; + } + return LIBSPDM_STATUS_SUCCESS; + } else { + /* get non-secured message*/ + status = libspdm_storage_decode_message(&secured_message_session_id, + 0, + transport_message_size, + transport_message, + message_size, message); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "transport_decode_message - %xu\n", + status)); + return status; + } + LIBSPDM_ASSERT(secured_message_session_id == NULL); + *session_id = NULL; + return LIBSPDM_STATUS_SUCCESS; + } + } +} + +/** + * Encode a normal message or secured message to a storage transport message. + * + * @param session_id Indicates if it is a secured message protected via SPDM session. + * If *session_id is NULL, it is a normal message. + * If *session_id is NOT NULL, it is a secured message. + * @param connection_id Indicates the connection ID of the message. + * @param message_size size in bytes of the message data buffer. + * @param message A pointer to a destination buffer to store the message. + * @param transport_message_size Size in bytes of the transport message data buffer. + * On return, length of the transport message. + * @param transport_message A pointer to a source buffer to store the transport message. + * + * @retval RETURN_SUCCESS The message is encoded successfully. + * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE The message is NULL or the message_size/transport_message_size is zero. + * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD The message field is incorrect. + * @retval LIBSPDM_STATUS_BUFFER_TOO_SMALL Insufficient transport buffer size. + **/ +libspdm_return_t libspdm_storage_encode_message(const uint32_t *session_id, + uint8_t connection_id, + size_t message_size, void *message, + size_t *transport_message_size, + void **transport_message) +{ + uint32_t data32; + storage_spdm_transport_header *storage_header; + + if (!transport_message_size || *transport_message_size == 0 + || message_size == 0) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + + LIBSPDM_ASSERT(*transport_message_size >= sizeof(storage_spdm_transport_header)); + + if (*transport_message_size < message_size + sizeof(storage_spdm_transport_header)) { + *transport_message_size = message_size + sizeof(storage_spdm_transport_header); + return LIBSPDM_STATUS_BUFFER_TOO_SMALL; + } + + if (!message || !transport_message) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + + if (connection_id & ~0x03) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + + *transport_message_size = message_size + sizeof(storage_spdm_transport_header); + *transport_message = (uint8_t *)message - sizeof(storage_spdm_transport_header); + storage_header = *transport_message; + storage_header->inc_512 = false; + + storage_header->security_protocol = SPDM_STORAGE_SECURITY_PROTOCOL_DMTF; + + if (session_id != NULL) { + storage_header->security_protocol_specific = SPDM_STORAGE_OPERATION_CODE_SECURED_MESSAGE << + 2; + storage_header->security_protocol_specific |= connection_id & + SPDM_STORAGE_MAX_CONNECTION_ID_MASK; + data32 = libspdm_read_uint32((const uint8_t *)message); + LIBSPDM_ASSERT(*session_id == data32); + if (*session_id != data32) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + } else { + storage_header->security_protocol_specific = SPDM_STORAGE_OPERATION_CODE_MESSAGE << 2; + storage_header->security_protocol_specific |= connection_id & + SPDM_STORAGE_MAX_CONNECTION_ID_MASK; + } + + storage_header->length = (uint32_t)*transport_message_size; + +#if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ + storage_header->length = libspdm_byte_swap_32(storage_header->length); + storage_header->security_protocol_specific = libspdm_byte_swap_16( + storage_header->security_protocol_specific); +#endif + + return LIBSPDM_STATUS_SUCCESS; +} + +/** + * Encode an SPDM or APP message into a transport layer message. + * + * @param spdm_context A pointer to the SPDM context. + * @param session_id Indicates if it is a secured message protected via SPDM session. + * If session_id is NULL, it is a normal message. + * If session_id is not NULL, it is a secured message. + * @param is_app_message Indicates if it is an APP message or SPDM message. + * @param is_request_message Indicates if it is a request message. + * @param message_size Size in bytes of the message data buffer. + * @param message A pointer to a destination buffer to store the message. + * On input, it shall point to the scratch buffer in spdm_context. + * On output, for normal message, it will point to the original receiver buffer. + * On output, for secured message, it will point to the scratch buffer in spdm_context. + * @param transport_message_size Size in bytes of the transport message data buffer. + * @param transport_message A pointer to a source buffer to store the transport message. + * For normal message or secured message, it shall point to acquired receiver buffer. + * + * @retval RETURN_SUCCESS The message is decoded successfully. + * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE The message is NULL or the message_size is zero. + * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD The message field is incorrect. + * @retval LIBSPDM_STATUS_UNSUPPORTED_CAP The transport_message is unsupported. + **/ +libspdm_return_t libspdm_transport_storage_encode_message( + void *spdm_context, const uint32_t *session_id, + bool is_app_message, + bool is_request_message, size_t message_size, void *message, + size_t *transport_message_size, void **transport_message) +{ + libspdm_return_t status; + uint8_t *secured_message; + size_t secured_message_size; + libspdm_secured_message_callbacks_t spdm_secured_message_callbacks; + void *secured_message_context; + size_t sec_trans_header_size; + + spdm_secured_message_callbacks.version = + LIBSPDM_SECURED_MESSAGE_CALLBACKS_VERSION; + spdm_secured_message_callbacks.get_sequence_number = + libspdm_storage_get_sequence_number; + spdm_secured_message_callbacks.get_max_random_number_count = + libspdm_storage_get_max_random_number_count; + spdm_secured_message_callbacks.get_secured_spdm_version = + libspdm_storage_get_secured_spdm_version; + + if (is_app_message) { + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + + if (!transport_message_size || !transport_message + || *transport_message_size == 0) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + + if (session_id != NULL) { + secured_message_context = + libspdm_get_secured_message_context_via_session_id( + spdm_context, *session_id); + if (secured_message_context == NULL) { + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + + /* Message to secured message*/ + sec_trans_header_size = is_request_message ? + sizeof(storage_spdm_transport_header): 0; + /* DSP0286 Specifies 4 Reserved bytes at the start of a secured message */ + sec_trans_header_size += sizeof(uint32_t); + secured_message = ((uint8_t *)(*transport_message)) + sec_trans_header_size; + secured_message_size = *transport_message_size - sec_trans_header_size; + status = libspdm_encode_secured_message( + secured_message_context, *session_id, is_request_message, + message_size, message, &secured_message_size, + secured_message, &spdm_secured_message_callbacks); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, + "libspdm_encode_secured_message - %xu\n", status)); + return status; + } + + if (!is_request_message) { + /* + * Storage response messages are not transport encoded, instead it + * is just the SPDM message response. + */ + *transport_message_size = secured_message_size + sec_trans_header_size; + /* Ensure we allow the 4 reserved bytes to be encapsulated */ + *transport_message = secured_message - sizeof(uint32_t);; + return LIBSPDM_STATUS_SUCCESS; + } + + /* secured message to secured storage message*/ + status = libspdm_storage_encode_message( + session_id, 0, secured_message_size, secured_message, + transport_message_size, transport_message); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "transport_encode_message - %xu\n", + status)); + return status; + } + } else { + if (!is_request_message) { + /* + * Storage response messages are not transport encoded, instead it + * is just the SPDM message response. + */ + *transport_message_size = message_size; + *transport_message = message; + return LIBSPDM_STATUS_SUCCESS; + } + + /* SPDM message to normal storage message*/ + status = libspdm_storage_encode_message(NULL, 0, + message_size, message, + transport_message_size, + transport_message); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "transport_encode_message - %xu\n", + status)); + return status; + } + } + + return LIBSPDM_STATUS_SUCCESS; +} + +/** + * Encode a storage transport management command, supports only Discovery and + * Pending Info. + * + * @param cmd_direction Specify the direction of the command IF_SEND/RECV + * @param transport_operation Transport operation type, Discovery/Pending Info + * @param connection_id SPDM Connection ID + * @param transport_message_size Size in bytes of the transport message data buffer. + * On return, the length of the encoded message + * @param allocation_length Storage buffer allocation length + * @param transport_message A pointer to a transport message buffer. + * + * @retval RETURN_SUCCESS The message is encoded successfully. + * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE The message is NULL or the message_size is zero. + * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD The message field is incorrect. + * @retval LIBSPDM_STATUS_BUFFER_TOO_SMALL Insufficient transport buffer size + **/ +libspdm_return_t libspdm_transport_storage_encode_management_cmd( + uint8_t cmd_direction, uint8_t transport_operation, + uint8_t connection_id, size_t *transport_message_size, + size_t *allocation_length, void *transport_message) +{ + storage_spdm_transport_header *storage_header; + + if (!transport_message_size || !allocation_length + || *transport_message_size == 0) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + + if (*transport_message_size < sizeof(storage_spdm_transport_header)) { + return LIBSPDM_STATUS_BUFFER_TOO_SMALL; + } + + if (connection_id & ~0x03) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + + if (!(cmd_direction == LIBSPDM_STORAGE_CMD_DIRECTION_IF_SEND || + cmd_direction == LIBSPDM_STORAGE_CMD_DIRECTION_IF_RECV)) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + + switch (transport_operation) { + case SPDM_STORAGE_OPERATION_CODE_DISCOVERY: + if (cmd_direction == LIBSPDM_STORAGE_CMD_DIRECTION_IF_RECV) { + *allocation_length = sizeof(spdm_storage_discovery_response_t); + if (*transport_message_size < sizeof(spdm_storage_discovery_response_t)) { + return LIBSPDM_STATUS_BUFFER_TOO_SMALL; + } + } + break; + case SPDM_STORAGE_OPERATION_CODE_PENDING_INFO: + if (cmd_direction == LIBSPDM_STORAGE_CMD_DIRECTION_IF_RECV) { + *allocation_length = sizeof(spdm_storage_pending_info_response_t); + if (*transport_message_size < sizeof(spdm_storage_pending_info_response_t)) { + return LIBSPDM_STATUS_BUFFER_TOO_SMALL; + } + } + break; + default: + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + + *transport_message_size = sizeof(storage_spdm_transport_header); + libspdm_zero_mem(transport_message, *transport_message_size); + + storage_header = transport_message; + storage_header->security_protocol = SPDM_STORAGE_SECURITY_PROTOCOL_DMTF; + storage_header->security_protocol_specific = transport_operation << 2; + storage_header->security_protocol_specific |= connection_id & + SPDM_STORAGE_MAX_CONNECTION_ID_MASK; + storage_header->inc_512 = false; + storage_header->length = (uint32_t)*transport_message_size; + +#if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ + storage_header->length = libspdm_byte_swap_32(storage_header->length); + storage_header->security_protocol_specific = libspdm_byte_swap_16( + storage_header->security_protocol_specific); +#endif + + return LIBSPDM_STATUS_SUCCESS; +} + +/** + * Encode a storage transport discovery response. As defined by the DMTF DSP0286 + * + * @param transport_message_size Size in bytes of the transport message data buffer. + * On return, the size of the response + * @param transport_message A pointer to a source buffer to store the transport message. + * + * @retval RETURN_SUCCESS The message is decoded successfully. + * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE The message is NULL or the message_size is zero. + * @retval LIBSPDM_STATUS_BUFFER_TOO_SMALL @transport_message is too small + **/ +libspdm_return_t libspdm_transport_storage_encode_discovery_response( + size_t *transport_message_size, + void *transport_message) +{ + spdm_storage_discovery_response_t *discovery_response; + + if (!transport_message || !transport_message_size + || *transport_message_size == 0) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + + if (*transport_message_size < sizeof(spdm_storage_discovery_response_t)) { + return LIBSPDM_STATUS_BUFFER_TOO_SMALL; + } + + if (!transport_message) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + + *transport_message_size = sizeof(spdm_storage_discovery_response_t); + libspdm_zero_mem(transport_message, *transport_message_size); + discovery_response = transport_message; + + discovery_response->data_length = (uint16_t)*transport_message_size; + discovery_response->storage_binding_version = SPDM_STORAGE_SECURITY_BINDING_VERSION; + /* 1 supported connection (0's based) */ + discovery_response->connection_parameters = 0; + discovery_response->supported_operations = (1 << SPDM_STORAGE_OPERATION_CODE_DISCOVERY) + | (1 << SPDM_STORAGE_OPERATION_CODE_PENDING_INFO) + | (1 << SPDM_STORAGE_OPERATION_CODE_MESSAGE) + | (1 << + SPDM_STORAGE_OPERATION_CODE_SECURED_MESSAGE); + + return LIBSPDM_STATUS_SUCCESS; +} + +/** + * Encode a storage transport pending response. As defined by the DMTF DSP0286 + * + * @param transport_message_size Size in bytes of the transport message data buffer. + * On return, the size of the response + * @param transport_message A pointer to a source buffer to store the transport message. + * @param response_pending If true, the responder has a pending response + * @param pending_response_length Valid only if @response_pending is true, + * specifies the length of the pending message + * in bytes. + * + * @retval RETURN_SUCCESS The message is decoded successfully. + * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE The message is NULL or the message_size is zero. + * @retval LIBSPDM_STATUS_BUFFER_TOO_SMALL @transport_message is too small + **/ +libspdm_return_t libspdm_transport_storage_encode_pending_info_response( + size_t *transport_message_size, + void *transport_message, bool response_pending, + uint32_t pending_response_length) +{ + spdm_storage_pending_info_response_t *pending_info_response; + + if (!transport_message || !transport_message_size + || *transport_message_size == 0) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + + if (*transport_message_size < sizeof(spdm_storage_pending_info_response_t)) { + return LIBSPDM_STATUS_BUFFER_TOO_SMALL; + } + + *transport_message_size = sizeof(spdm_storage_pending_info_response_t); + libspdm_zero_mem(transport_message, *transport_message_size); + pending_info_response = transport_message; + + pending_info_response->data_length = (uint16_t)*transport_message_size; + pending_info_response->storage_binding_version = SPDM_STORAGE_SECURITY_BINDING_VERSION; + + if (response_pending) { + pending_info_response->pending_info_flag = (1 << 0); + pending_info_response->response_length = pending_response_length; + } + + return LIBSPDM_STATUS_SUCCESS; +} + +/** + * Decode a storage transport management command + * + * @param transport_message_size Size in bytes of the transport message data buffer. + * @param transport_message A pointer to an encoded transport message buffer. + * @param transport_command Storage transport command contained in transport message + * @param length On return, this specifies allocation length + * or transfer length. Depending on if the + * message was an IF_RECV or IF_SEND respectively. + * + * @retval RETURN_SUCCESS The message is decoded successfully. + * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE The message is NULL or the message_size is zero. + * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD The message field is incorrect. + * @retval LIBSPDM_STATUS_UNSUPPORTED_CAP The transport_message is unsupported. + **/ +libspdm_return_t libspdm_transport_storage_decode_management_cmd( + size_t transport_message_size, + const void *transport_message, + uint8_t *transport_command, + uint32_t *length) +{ + const storage_spdm_transport_header *storage_header; + uint16_t security_protocol_specific; + uint8_t spsp0, spsp1, spdm_operation; + + if (!transport_message || transport_message_size == 0) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + + LIBSPDM_ASSERT(transport_message_size >= sizeof(storage_spdm_transport_header)); + + if (transport_message_size < sizeof(storage_spdm_transport_header)) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + + storage_header = transport_message; + if (storage_header->security_protocol != SPDM_STORAGE_SECURITY_PROTOCOL_DMTF) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + +#if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ + security_protocol_specific = libspdm_byte_swap_16(storage_header->security_protocol_specific); +#else + security_protocol_specific = storage_header->security_protocol_specific; +#endif + spsp0 = security_protocol_specific & 0xFF; + spsp1 = security_protocol_specific >> 8; + + if (spsp1 != 0) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + + spdm_operation = (spsp0 & 0xFC) >> 2; + + switch (spdm_operation) { + case SPDM_STORAGE_OPERATION_CODE_DISCOVERY: + case SPDM_STORAGE_OPERATION_CODE_PENDING_INFO: + case SPDM_STORAGE_OPERATION_CODE_MESSAGE: + case SPDM_STORAGE_OPERATION_CODE_SECURED_MESSAGE: + *transport_command = spdm_operation; + break; + default: + *transport_command = 0; + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + +#if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ + *length = libspdm_byte_swap_32(storage_header->length); +#else + *length = storage_header->length; +#endif + return LIBSPDM_STATUS_SUCCESS; +} From 871e2aa7cd1a058f59a9118428c5d312b00960a0 Mon Sep 17 00:00:00 2001 From: Wilfred Mallawa Date: Tue, 16 Jul 2024 18:07:37 +1000 Subject: [PATCH 3/5] req_communication: pass session ID to transport This allows transports such as Storage (DSP0286) to determine if the next response is protected via secured messages. Unlike other transport layers, storage does not encode the message type in a response header. As such, the requester must track the expected type. The issue [1] discusses this implementation requirement in further detail with regards to DSP0286. [1] https://github.com/DMTF/SPDM-WG/issues/3520 Signed-off-by: Wilfred Mallawa Signed-off-by: Alistair Francis --- .../libspdm_req_send_receive.c | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/library/spdm_requester_lib/libspdm_req_send_receive.c b/library/spdm_requester_lib/libspdm_req_send_receive.c index 4799b96f8f0..60350a9cc63 100644 --- a/library/spdm_requester_lib/libspdm_req_send_receive.c +++ b/library/spdm_requester_lib/libspdm_req_send_receive.c @@ -131,7 +131,7 @@ libspdm_return_t libspdm_receive_response(void *spdm_context, const uint32_t *se libspdm_return_t status; uint8_t *message; size_t message_size; - uint32_t *message_session_id; + uint32_t *message_session_id, message_id; bool is_message_app_message; uint64_t timeout; size_t transport_header_size; @@ -163,7 +163,22 @@ libspdm_return_t libspdm_receive_response(void *spdm_context, const uint32_t *se return status; } - message_session_id = NULL; + /* + * The storage transport encoding, defined by DSP0286, does not indicate + * if we are/are not in a secure session in the transport data. This is + * different to most other transport encodings, which includes session + * information in the encoding. + * + * As such if we are in a secure session, session_id != NULL, we set + * message_session_id to be non-NULL to indicate to the lower layer + * that we are in a secure session. + */ + if (session_id != NULL) { + message_session_id = &message_id; + message_id = *session_id; + } else { + message_session_id = NULL; + } is_message_app_message = false; /* always use scratch buffer to response. @@ -211,7 +226,11 @@ libspdm_return_t libspdm_receive_response(void *spdm_context, const uint32_t *se /* Retry decoding message with backup Requester key. * Must reset some of the parameters in case they were modified */ - message_session_id = NULL; + if (session_id != NULL) { + *message_session_id = *session_id; + } else { + message_session_id = NULL; + } is_message_app_message = false; *response = backup_response; *response_size = backup_response_size; From d2b370a8f461fa530fa63635e955131059b62ba9 Mon Sep 17 00:00:00 2001 From: Wilfred Mallawa Date: Mon, 25 Nov 2024 13:08:23 +1000 Subject: [PATCH 4/5] transport: storage: add tests Signed-off-by: Wilfred Mallawa --- CMakeLists.txt | 2 + .../CMakeLists.txt | 62 ++++ .../spdm_transport_storage_decode_message.c | 140 ++++++++ .../CMakeLists.txt | 62 ++++ .../spdm_transport_storage_encode_message.c | 317 ++++++++++++++++++ 5 files changed, 583 insertions(+) create mode 100644 unit_test/fuzzing/test_transport/test_spdm_transport_storage_decode_message/CMakeLists.txt create mode 100644 unit_test/fuzzing/test_transport/test_spdm_transport_storage_decode_message/spdm_transport_storage_decode_message.c create mode 100644 unit_test/fuzzing/test_transport/test_spdm_transport_storage_encode_message/CMakeLists.txt create mode 100644 unit_test/fuzzing/test_transport/test_spdm_transport_storage_encode_message/spdm_transport_storage_encode_message.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ff870b27e3..fd8ede07e67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1006,6 +1006,8 @@ else() add_subdirectory(unit_test/fuzzing/test_transport/test_spdm_transport_mctp_decode_message) add_subdirectory(unit_test/fuzzing/test_transport/test_spdm_transport_pci_doe_encode_message) add_subdirectory(unit_test/fuzzing/test_transport/test_spdm_transport_pci_doe_decode_message) + add_subdirectory(unit_test/fuzzing/test_transport/test_spdm_transport_storage_encode_message) + add_subdirectory(unit_test/fuzzing/test_transport/test_spdm_transport_storage_decode_message) add_subdirectory(unit_test/fuzzing/test_secured_message/test_spdm_decode_secured_message) add_subdirectory(unit_test/fuzzing/test_secured_message/test_spdm_encode_secured_message) add_subdirectory(unit_test/fuzzing/test_spdm_crypt/test_x509_certificate_check) diff --git a/unit_test/fuzzing/test_transport/test_spdm_transport_storage_decode_message/CMakeLists.txt b/unit_test/fuzzing/test_transport/test_spdm_transport_storage_decode_message/CMakeLists.txt new file mode 100644 index 00000000000..174896ef0f7 --- /dev/null +++ b/unit_test/fuzzing/test_transport/test_spdm_transport_storage_decode_message/CMakeLists.txt @@ -0,0 +1,62 @@ +cmake_minimum_required(VERSION 3.5) + +add_executable(test_spdm_transport_storage_decode_message) + +target_include_directories(test_spdm_transport_storage_decode_message + PRIVATE + ${LIBSPDM_DIR}/unit_test/fuzzing/test_transport/test_spdm_transport_storage_decode_message + ${LIBSPDM_DIR}/include + ${LIBSPDM_DIR}/include/library + ${LIBSPDM_DIR}/unit_test/include + ${LIBSPDM_DIR}/unit_test/fuzzing/spdm_unit_fuzzing_common + ${LIBSPDM_DIR}/os_stub/include +) + +if(TOOLCHAIN STREQUAL "KLEE") + target_include_directories(test_spdm_transport_storage_decode_message + PRIVATE + $ENV{KLEE_SRC_PATH}/include + ) +endif() + +target_sources(test_spdm_transport_storage_decode_message + PRIVATE + spdm_transport_storage_decode_message.c + ${PROJECT_SOURCE_DIR}/unit_test/fuzzing/spdm_unit_fuzzing_common/common.c + ${PROJECT_SOURCE_DIR}/unit_test/fuzzing/spdm_unit_fuzzing_common/toolchain_harness.c + ${PROJECT_SOURCE_DIR}/unit_test/fuzzing/spdm_unit_fuzzing_common/algo.c +) + +if((TOOLCHAIN STREQUAL "KLEE") OR (TOOLCHAIN STREQUAL "CBMC")) + target_link_libraries(test_spdm_transport_storage_decode_message + PRIVATE + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + ) +else() + target_link_libraries(test_spdm_transport_storage_decode_message + PRIVATE + memlib + debuglib + spdm_transport_storage_lib + spdm_common_lib + ${CRYPTO_LIB_PATHS} + rnglib + cryptlib_${CRYPTO} + malloclib + spdm_crypt_lib + spdm_secured_message_lib + spdm_transport_test_lib + spdm_device_secret_lib_null + ) +endif() diff --git a/unit_test/fuzzing/test_transport/test_spdm_transport_storage_decode_message/spdm_transport_storage_decode_message.c b/unit_test/fuzzing/test_transport/test_spdm_transport_storage_decode_message/spdm_transport_storage_decode_message.c new file mode 100644 index 00000000000..f5c155063e5 --- /dev/null +++ b/unit_test/fuzzing/test_transport/test_spdm_transport_storage_decode_message/spdm_transport_storage_decode_message.c @@ -0,0 +1,140 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 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_responder_lib.h" +#include "spdm_transport_storage_lib.h" +#include "industry_standard/spdm_storage_binding.h" +#include "industry_standard/pcidoe.h" +#include "spdm_unit_fuzzing.h" +#include "toolchain_harness.h" + +/* + * This is to workaround `set but not used warning for build configs without + * `LIBSPDM_ASSERT() support. + */ +#define USE_VAR(x) (void)(x) + +libspdm_test_context_t m_libspdm_transport_storage_test_context = { + LIBSPDM_TEST_CONTEXT_VERSION, + false, +}; + +size_t libspdm_get_max_buffer_size(void) +{ + return LIBSPDM_MAX_SPDM_MSG_SIZE; +} + +void libspdm_test_transport_storage_decode_message(void **state) +{ + libspdm_test_context_t *spdm_test_context = *state; + void *transport_message, *message, *dec_message; + size_t transport_message_size, message_size, dec_message_size; + uint32_t *session_id; + bool is_app_message, dec_is_app_message, is_request_message; + libspdm_return_t ret; + + if (m_libspdm_transport_storage_test_context.test_buffer_size < + sizeof(storage_spdm_transport_header)) { + LIBSPDM_ASSERT(false); + } + + /* Encode an SPDM Storage Message First (Test Setup) */ + transport_message_size = LIBSPDM_MAX_SENDER_RECEIVER_BUFFER_SIZE; + transport_message = spdm_test_context->test_buffer; + is_app_message = false; + is_request_message = true; + message_size = 12; + message = (uint8_t *)transport_message + sizeof(storage_spdm_transport_header); + + ret = libspdm_transport_storage_encode_message( + state, + NULL, + is_app_message, + is_request_message, + message_size, + message, + &transport_message_size, + &transport_message); + LIBSPDM_ASSERT(ret == LIBSPDM_STATUS_SUCCESS); + + ret = libspdm_transport_storage_decode_message( + state, + &session_id, + &dec_is_app_message, + is_request_message, + transport_message_size, + transport_message, + &dec_message_size, + &dec_message + ); + /* Trivial Assertions */ + LIBSPDM_ASSERT(ret == LIBSPDM_STATUS_SUCCESS); + LIBSPDM_ASSERT(dec_is_app_message == false); + LIBSPDM_ASSERT(dec_message_size == message_size); + USE_VAR(ret); +} + +void libspdm_test_transport_storage_decode_management_cmd(void **state) +{ + libspdm_test_context_t *spdm_test_context = *state; + void *transport_message; + size_t transport_message_size; + size_t alloc_len; + uint32_t decoded_alloc_len; + uint8_t cmd_direction; + uint8_t transport_operation, transport_command; + libspdm_return_t ret; + + if (m_libspdm_transport_storage_test_context.test_buffer_size < + sizeof(storage_spdm_transport_header)) { + LIBSPDM_ASSERT(false); + } + + transport_message_size = LIBSPDM_MAX_SENDER_RECEIVER_BUFFER_SIZE; + transport_message = spdm_test_context->test_buffer; + cmd_direction = LIBSPDM_STORAGE_CMD_DIRECTION_IF_RECV; + transport_operation = SPDM_STORAGE_OPERATION_CODE_DISCOVERY; + alloc_len = 0xFF; + + /* Encode a management command first (Test Setup) */ + ret = libspdm_transport_storage_encode_management_cmd( + cmd_direction, + transport_operation, + 0, + &transport_message_size, + &alloc_len, + transport_message); + LIBSPDM_ASSERT(ret == LIBSPDM_STATUS_SUCCESS); + + /* Attempt to decode with trivial assertions */ + ret = libspdm_transport_storage_decode_management_cmd( + transport_message_size, + transport_message, + &transport_command, + &decoded_alloc_len + ); + LIBSPDM_ASSERT(ret == LIBSPDM_STATUS_SUCCESS); + LIBSPDM_ASSERT(transport_command == SPDM_STORAGE_OPERATION_CODE_DISCOVERY); + LIBSPDM_ASSERT(decoded_alloc_len == sizeof(storage_spdm_transport_header)); + USE_VAR(ret); +} + +void libspdm_run_test_harness(void *test_buffer, size_t test_buffer_size) +{ + void *state; + + libspdm_setup_test_context(&m_libspdm_transport_storage_test_context); + + m_libspdm_transport_storage_test_context.test_buffer = test_buffer; + m_libspdm_transport_storage_test_context.test_buffer_size = test_buffer_size; + + libspdm_unit_test_group_setup(&state); + + libspdm_test_transport_storage_decode_management_cmd(&state); + libspdm_test_transport_storage_decode_message(&state); + + libspdm_unit_test_group_teardown(&state); +} diff --git a/unit_test/fuzzing/test_transport/test_spdm_transport_storage_encode_message/CMakeLists.txt b/unit_test/fuzzing/test_transport/test_spdm_transport_storage_encode_message/CMakeLists.txt new file mode 100644 index 00000000000..754f11c7144 --- /dev/null +++ b/unit_test/fuzzing/test_transport/test_spdm_transport_storage_encode_message/CMakeLists.txt @@ -0,0 +1,62 @@ +cmake_minimum_required(VERSION 3.5) + +add_executable(test_spdm_transport_storage_encode_message) + +target_include_directories(test_spdm_transport_storage_encode_message + PRIVATE + ${LIBSPDM_DIR}/unit_test/fuzzing/test_transport/test_spdm_transport_storage_encode_message + ${LIBSPDM_DIR}/include + ${LIBSPDM_DIR}/include/library + ${LIBSPDM_DIR}/unit_test/include + ${LIBSPDM_DIR}/unit_test/fuzzing/spdm_unit_fuzzing_common + ${LIBSPDM_DIR}/os_stub/include +) + +if(TOOLCHAIN STREQUAL "KLEE") + target_include_directories(test_spdm_transport_storage_encode_message + PRIVATE + $ENV{KLEE_SRC_PATH}/include + ) +endif() + +target_sources(test_spdm_transport_storage_encode_message + PRIVATE + spdm_transport_storage_encode_message.c + ${PROJECT_SOURCE_DIR}/unit_test/fuzzing/spdm_unit_fuzzing_common/common.c + ${PROJECT_SOURCE_DIR}/unit_test/fuzzing/spdm_unit_fuzzing_common/toolchain_harness.c + ${PROJECT_SOURCE_DIR}/unit_test/fuzzing/spdm_unit_fuzzing_common/algo.c +) + +if((TOOLCHAIN STREQUAL "KLEE") OR (TOOLCHAIN STREQUAL "CBMC")) + target_link_libraries(test_spdm_transport_storage_encode_message + PRIVATE + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + ) +else() + target_link_libraries(test_spdm_transport_storage_encode_message + PRIVATE + memlib + debuglib + spdm_transport_storage_lib + spdm_common_lib + ${CRYPTO_LIB_PATHS} + rnglib + cryptlib_${CRYPTO} + malloclib + spdm_crypt_lib + spdm_secured_message_lib + spdm_transport_test_lib + spdm_device_secret_lib_null + ) +endif() diff --git a/unit_test/fuzzing/test_transport/test_spdm_transport_storage_encode_message/spdm_transport_storage_encode_message.c b/unit_test/fuzzing/test_transport/test_spdm_transport_storage_encode_message/spdm_transport_storage_encode_message.c new file mode 100644 index 00000000000..c70368d52e8 --- /dev/null +++ b/unit_test/fuzzing/test_transport/test_spdm_transport_storage_encode_message/spdm_transport_storage_encode_message.c @@ -0,0 +1,317 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 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_responder_lib.h" +#include "spdm_transport_storage_lib.h" +#include "industry_standard/spdm_storage_binding.h" +#include "industry_standard/pcidoe.h" +#include "spdm_unit_fuzzing.h" +#include "toolchain_harness.h" + +/* + * This is to workaround `set but not used warning for build configs without + * `LIBSPDM_ASSERT() support. + */ +#define USE_VAR(x) (void)(x) + +libspdm_test_context_t m_libspdm_transport_storage_test_context = { + LIBSPDM_TEST_CONTEXT_VERSION, + false, +}; + +size_t libspdm_get_max_buffer_size(void) +{ + return LIBSPDM_MAX_SPDM_MSG_SIZE; +} + +void libspdm_test_transport_storage_encode_message(void **state) +{ + libspdm_test_context_t *spdm_test_context = *state; + storage_spdm_transport_header *hdr; + void *transport_message, *message; + size_t transport_message_size, message_size; + bool is_app_message, is_request_message; + libspdm_return_t ret; + + if (m_libspdm_transport_storage_test_context.test_buffer_size < + sizeof(storage_spdm_transport_header)) { + LIBSPDM_ASSERT(false); + } + + /* Valid Parameters: SPDM Storage Message */ + transport_message_size = LIBSPDM_MAX_SENDER_RECEIVER_BUFFER_SIZE; + transport_message = spdm_test_context->test_buffer; + is_app_message = false; + is_request_message = true; + message_size = 12; + message = (uint8_t *)transport_message + sizeof(storage_spdm_transport_header); + + ret = libspdm_transport_storage_encode_message(state, + NULL, + is_app_message, + is_request_message, + message_size, + message, + &transport_message_size, + &transport_message); + LIBSPDM_ASSERT(ret == LIBSPDM_STATUS_SUCCESS); + + /* Trivial assertions for transport virtual header encoding */ + hdr = transport_message; + LIBSPDM_ASSERT(hdr->security_protocol == SPDM_STORAGE_SECURITY_PROTOCOL_DMTF); + LIBSPDM_ASSERT((hdr->security_protocol_specific >> 8) == 0); /* SPSP1 */ + LIBSPDM_ASSERT((hdr->security_protocol_specific & 0xFF) != 0); /* SPSP0 */ + LIBSPDM_ASSERT(hdr->length == (message_size + sizeof(storage_spdm_transport_header))); + + /* Invalid Parameters: Message side exceeds transport buffer size */ + transport_message_size = 0; + ret = libspdm_transport_storage_encode_message(state, + NULL, + is_app_message, + is_request_message, + message_size, + message, + &transport_message_size, + &transport_message); + LIBSPDM_ASSERT(ret == LIBSPDM_STATUS_INVALID_MSG_SIZE); + USE_VAR(ret); + USE_VAR(hdr); +} + +void libspdm_test_transport_storage_encode_management_cmd(void **state) +{ + libspdm_test_context_t *spdm_test_context = *state; + storage_spdm_transport_header *hdr; + size_t transport_message_size; + void *transport_message; + size_t allocation_len = 0; + uint8_t cmd_direction; + uint8_t transport_operation; + libspdm_return_t ret; + + if (m_libspdm_transport_storage_test_context.test_buffer_size < + sizeof(storage_spdm_transport_header)) { + LIBSPDM_ASSERT(false); + } + + transport_message_size = LIBSPDM_MAX_SENDER_RECEIVER_BUFFER_SIZE; + transport_message = spdm_test_context->test_buffer; + cmd_direction = LIBSPDM_STORAGE_CMD_DIRECTION_IF_RECV; + transport_operation = SPDM_STORAGE_OPERATION_CODE_DISCOVERY; + + /* Valid Parameters: Test IF_RECV Discovery */ + ret = libspdm_transport_storage_encode_management_cmd( + cmd_direction, + transport_operation, + 0, + &transport_message_size, + &allocation_len, + transport_message); + LIBSPDM_ASSERT(ret == LIBSPDM_STATUS_SUCCESS); + LIBSPDM_ASSERT(allocation_len != 0); + + /* Trivial Compliance Assertions */ + hdr = transport_message; + LIBSPDM_ASSERT(hdr->security_protocol == SPDM_STORAGE_SECURITY_PROTOCOL_DMTF); + LIBSPDM_ASSERT((hdr->security_protocol_specific >> 8) == 0); /* SPSP1 */ + LIBSPDM_ASSERT((hdr->security_protocol_specific & 0xFF) != 0); /* SPSP0 */ + LIBSPDM_ASSERT(hdr->inc_512 == false); + LIBSPDM_ASSERT(hdr->length == sizeof(storage_spdm_transport_header)); + + /* Valid Parameters: Test IF_SEND Pending Info */ + transport_message_size = LIBSPDM_MAX_SENDER_RECEIVER_BUFFER_SIZE; + cmd_direction = LIBSPDM_STORAGE_CMD_DIRECTION_IF_SEND; + transport_operation = SPDM_STORAGE_OPERATION_CODE_PENDING_INFO; + allocation_len = 0; + + ret = libspdm_transport_storage_encode_management_cmd( + cmd_direction, + transport_operation, + 0, + &transport_message_size, + &allocation_len, + transport_message); + LIBSPDM_ASSERT(ret == LIBSPDM_STATUS_SUCCESS); + LIBSPDM_ASSERT(allocation_len == 0); + + /* Trivial Compliance Assertions */ + hdr = transport_message; + LIBSPDM_ASSERT(hdr->security_protocol == SPDM_STORAGE_SECURITY_PROTOCOL_DMTF); + LIBSPDM_ASSERT((hdr->security_protocol_specific >> 8) == 0); /* SPSP1 */ + LIBSPDM_ASSERT((hdr->security_protocol_specific & 0xFF) != 0); /* SPSP0 */ + LIBSPDM_ASSERT(hdr->inc_512 == false); + LIBSPDM_ASSERT(hdr->length == sizeof(storage_spdm_transport_header)); + + /* Bad Transport Message Size */ + transport_message_size = 0; + ret = libspdm_transport_storage_encode_management_cmd( + cmd_direction, + transport_operation, + 0, + &transport_message_size, + &allocation_len, + transport_message); + LIBSPDM_ASSERT(ret == LIBSPDM_STATUS_INVALID_MSG_SIZE); + + /* Invalid Command Direction */ + transport_message_size = LIBSPDM_MAX_SENDER_RECEIVER_BUFFER_SIZE; + cmd_direction = 0xFF; + + ret = libspdm_transport_storage_encode_management_cmd( + cmd_direction, + transport_operation, + 0, + &transport_message_size, + &allocation_len, + transport_message); + LIBSPDM_ASSERT(ret == LIBSPDM_STATUS_INVALID_MSG_FIELD); + + /* Invalid Transport Operation*/ + cmd_direction = LIBSPDM_STORAGE_CMD_DIRECTION_IF_SEND; + transport_operation = 0xDD; + + ret = libspdm_transport_storage_encode_management_cmd( + cmd_direction, + transport_operation, + 0, + &transport_message_size, + &allocation_len, + transport_message); + LIBSPDM_ASSERT(ret == LIBSPDM_STATUS_INVALID_MSG_FIELD); + USE_VAR(ret); + USE_VAR(hdr); +} + +void libspdm_test_transport_storage_encode_discovery_response(void **state) +{ + libspdm_test_context_t *spdm_test_context = *state; + spdm_storage_discovery_response_t *d_resp; + size_t transport_message_size; + void *transport_message; + libspdm_return_t ret; + + if (m_libspdm_transport_storage_test_context.test_buffer_size < + sizeof(spdm_storage_discovery_response_t)) { + LIBSPDM_ASSERT(false); + } + + transport_message_size = LIBSPDM_MAX_SENDER_RECEIVER_BUFFER_SIZE; + transport_message = spdm_test_context->test_buffer; + + /* Valid Parameters */ + ret = libspdm_transport_storage_encode_discovery_response( + &transport_message_size, + transport_message); + LIBSPDM_ASSERT(ret == LIBSPDM_STATUS_SUCCESS); + + d_resp = transport_message; + LIBSPDM_ASSERT(transport_message_size == sizeof(spdm_storage_discovery_response_t)); + LIBSPDM_ASSERT(d_resp->data_length == sizeof(spdm_storage_discovery_response_t)); + LIBSPDM_ASSERT(d_resp->storage_binding_version == SPDM_STORAGE_SECURITY_BINDING_VERSION); + LIBSPDM_ASSERT(d_resp->supported_operations != 0); + + /* Invalid Input Buffer Size */ + transport_message_size = 1; + + ret = libspdm_transport_storage_encode_discovery_response( + &transport_message_size, + transport_message); + LIBSPDM_ASSERT(ret == LIBSPDM_STATUS_BUFFER_TOO_SMALL); + USE_VAR(ret); + USE_VAR(d_resp); +} + +void libspdm_test_transport_storage_encode_pending_resp(void **state) +{ + libspdm_test_context_t *spdm_test_context = *state; + spdm_storage_pending_info_response_t *p_resp; + size_t transport_message_size; + void *transport_message; + bool resp_pending; + uint32_t pending_response_length; + libspdm_return_t ret; + + if (m_libspdm_transport_storage_test_context.test_buffer_size < + sizeof(spdm_storage_pending_info_response_t)) { + LIBSPDM_ASSERT(false); + } + + /* Valid Parameters: Response Pending */ + transport_message_size = LIBSPDM_MAX_SENDER_RECEIVER_BUFFER_SIZE; + transport_message = spdm_test_context->test_buffer; + resp_pending = true; + pending_response_length = 32; + ret = libspdm_transport_storage_encode_pending_info_response( + &transport_message_size, + transport_message, + resp_pending, + pending_response_length + ); + LIBSPDM_ASSERT(ret == LIBSPDM_STATUS_SUCCESS); + + p_resp = transport_message; + LIBSPDM_ASSERT(transport_message_size == sizeof(spdm_storage_pending_info_response_t)); + LIBSPDM_ASSERT(p_resp->data_length == sizeof(spdm_storage_pending_info_response_t)); + LIBSPDM_ASSERT(p_resp->storage_binding_version == SPDM_STORAGE_SECURITY_BINDING_VERSION); + LIBSPDM_ASSERT(p_resp->pending_info_flag == 1); + LIBSPDM_ASSERT(p_resp->response_length == pending_response_length); + + /* Valid Parameters: No Response Pending */ + resp_pending = false; + ret = libspdm_transport_storage_encode_pending_info_response( + &transport_message_size, + transport_message, + resp_pending, + pending_response_length + ); + LIBSPDM_ASSERT(ret == LIBSPDM_STATUS_SUCCESS); + + p_resp = transport_message; + LIBSPDM_ASSERT(transport_message_size == sizeof(spdm_storage_pending_info_response_t)); + LIBSPDM_ASSERT(p_resp->data_length == sizeof(spdm_storage_pending_info_response_t)); + LIBSPDM_ASSERT(p_resp->storage_binding_version == SPDM_STORAGE_SECURITY_BINDING_VERSION); + LIBSPDM_ASSERT(p_resp->pending_info_flag == 0); + LIBSPDM_ASSERT(p_resp->response_length == 0); + + /* Invalid Transport Message Size */ + transport_message_size = 1; + ret = libspdm_transport_storage_encode_pending_info_response( + &transport_message_size, + transport_message, + resp_pending, + pending_response_length + ); + LIBSPDM_ASSERT(ret == LIBSPDM_STATUS_BUFFER_TOO_SMALL); + + ret = libspdm_transport_storage_encode_pending_info_response( + NULL, + transport_message, + resp_pending, + pending_response_length + ); + LIBSPDM_ASSERT(ret == LIBSPDM_STATUS_INVALID_MSG_SIZE); + USE_VAR(ret); + USE_VAR(p_resp); +} + +void libspdm_run_test_harness(void *test_buffer, size_t test_buffer_size) +{ + void *state; + + libspdm_setup_test_context(&m_libspdm_transport_storage_test_context); + + m_libspdm_transport_storage_test_context.test_buffer = test_buffer; + m_libspdm_transport_storage_test_context.test_buffer_size = test_buffer_size; + + libspdm_unit_test_group_setup(&state); + + libspdm_test_transport_storage_encode_message(&state); + libspdm_test_transport_storage_encode_management_cmd(&state); + libspdm_test_transport_storage_encode_discovery_response(&state); + libspdm_test_transport_storage_encode_pending_resp(&state); + + libspdm_unit_test_group_teardown(&state); +} From 10033fd2e7fe203814db07396b20ecb2c6e9fb70 Mon Sep 17 00:00:00 2001 From: Wilfred Mallawa Date: Wed, 27 Nov 2024 16:13:55 +1000 Subject: [PATCH 5/5] fuzzing: connect spdm storage tests Signed-off-by: Wilfred Mallawa --- unit_test/fuzzing/fuzzing_AFL.sh | 2 ++ unit_test/fuzzing/fuzzing_AFLTurbo.sh | 2 ++ unit_test/fuzzing/fuzzing_AFLplusplus.sh | 2 ++ unit_test/fuzzing/fuzzing_LibFuzzer.sh | 2 ++ unit_test/fuzzing/oss_fuzz.sh | 2 ++ unit_test/fuzzing/run_initial_seed.sh | 2 ++ .../spdm_transport_storage_decode_message.raw | 1 + .../spdm_transport_storage_encode_message.raw | 1 + 8 files changed, 14 insertions(+) create mode 100644 unit_test/fuzzing/seeds/test_spdm_transport_storage_decode_message/spdm_transport_storage_decode_message.raw create mode 100644 unit_test/fuzzing/seeds/test_spdm_transport_storage_encode_message/spdm_transport_storage_encode_message.raw diff --git a/unit_test/fuzzing/fuzzing_AFL.sh b/unit_test/fuzzing/fuzzing_AFL.sh index 5e08fa75926..f044033d5b7 100755 --- a/unit_test/fuzzing/fuzzing_AFL.sh +++ b/unit_test/fuzzing/fuzzing_AFL.sh @@ -105,6 +105,8 @@ test_spdm_transport_mctp_encode_message test_spdm_transport_mctp_decode_message test_spdm_transport_pci_doe_encode_message test_spdm_transport_pci_doe_decode_message +test_spdm_transport_storage_encode_message +test_spdm_transport_storage_decode_message test_spdm_decode_secured_message test_spdm_encode_secured_message test_spdm_requester_encap_digests diff --git a/unit_test/fuzzing/fuzzing_AFLTurbo.sh b/unit_test/fuzzing/fuzzing_AFLTurbo.sh index 55540a45c23..1c202f71184 100755 --- a/unit_test/fuzzing/fuzzing_AFLTurbo.sh +++ b/unit_test/fuzzing/fuzzing_AFLTurbo.sh @@ -106,6 +106,8 @@ test_spdm_transport_mctp_encode_message test_spdm_transport_mctp_decode_message test_spdm_transport_pci_doe_encode_message test_spdm_transport_pci_doe_decode_message +test_spdm_transport_storage_encode_message +test_spdm_transport_storage_decode_message test_spdm_decode_secured_message test_spdm_encode_secured_message test_spdm_requester_encap_digests diff --git a/unit_test/fuzzing/fuzzing_AFLplusplus.sh b/unit_test/fuzzing/fuzzing_AFLplusplus.sh index 6d60449bfcc..85872a0afaa 100644 --- a/unit_test/fuzzing/fuzzing_AFLplusplus.sh +++ b/unit_test/fuzzing/fuzzing_AFLplusplus.sh @@ -114,6 +114,8 @@ test_spdm_transport_mctp_encode_message test_spdm_transport_mctp_decode_message test_spdm_transport_pci_doe_encode_message test_spdm_transport_pci_doe_decode_message +test_spdm_transport_storage_encode_message +test_spdm_transport_storage_decode_message test_spdm_decode_secured_message test_spdm_encode_secured_message test_spdm_requester_encap_digests diff --git a/unit_test/fuzzing/fuzzing_LibFuzzer.sh b/unit_test/fuzzing/fuzzing_LibFuzzer.sh index 56c19d4f75f..fbc94773ce4 100755 --- a/unit_test/fuzzing/fuzzing_LibFuzzer.sh +++ b/unit_test/fuzzing/fuzzing_LibFuzzer.sh @@ -76,6 +76,8 @@ test_spdm_transport_mctp_encode_message test_spdm_transport_mctp_decode_message test_spdm_transport_pci_doe_encode_message test_spdm_transport_pci_doe_decode_message +test_spdm_transport_storage_encode_message +test_spdm_transport_storage_decode_message test_spdm_decode_secured_message test_spdm_encode_secured_message test_spdm_requester_encap_digests diff --git a/unit_test/fuzzing/oss_fuzz.sh b/unit_test/fuzzing/oss_fuzz.sh index 70068bf30df..44da4396751 100755 --- a/unit_test/fuzzing/oss_fuzz.sh +++ b/unit_test/fuzzing/oss_fuzz.sh @@ -72,6 +72,8 @@ test_spdm_transport_mctp_encode_message test_spdm_transport_mctp_decode_message test_spdm_transport_pci_doe_encode_message test_spdm_transport_pci_doe_decode_message +test_spdm_transport_storage_encode_message +test_spdm_transport_storage_decode_message test_spdm_decode_secured_message test_spdm_encode_secured_message test_spdm_requester_encap_digests diff --git a/unit_test/fuzzing/run_initial_seed.sh b/unit_test/fuzzing/run_initial_seed.sh index e3081835b1e..ba9ce28ee35 100755 --- a/unit_test/fuzzing/run_initial_seed.sh +++ b/unit_test/fuzzing/run_initial_seed.sh @@ -7,6 +7,8 @@ test_spdm_transport_mctp_encode_message test_spdm_transport_mctp_decode_message test_spdm_transport_pci_doe_encode_message test_spdm_transport_pci_doe_decode_message +test_spdm_transport_storage_encode_message +test_spdm_transport_storage_decode_message test_spdm_decode_secured_message test_spdm_encode_secured_message test_spdm_requester_encap_digests diff --git a/unit_test/fuzzing/seeds/test_spdm_transport_storage_decode_message/spdm_transport_storage_decode_message.raw b/unit_test/fuzzing/seeds/test_spdm_transport_storage_decode_message/spdm_transport_storage_decode_message.raw new file mode 100644 index 00000000000..c9b94c20b1a --- /dev/null +++ b/unit_test/fuzzing/seeds/test_spdm_transport_storage_decode_message/spdm_transport_storage_decode_message.raw @@ -0,0 +1 @@ +3.D#ɝQm,ET \ No newline at end of file diff --git a/unit_test/fuzzing/seeds/test_spdm_transport_storage_encode_message/spdm_transport_storage_encode_message.raw b/unit_test/fuzzing/seeds/test_spdm_transport_storage_encode_message/spdm_transport_storage_encode_message.raw new file mode 100644 index 00000000000..b48ba620ea9 --- /dev/null +++ b/unit_test/fuzzing/seeds/test_spdm_transport_storage_encode_message/spdm_transport_storage_encode_message.raw @@ -0,0 +1 @@ +`Pז(=6I)vwײ) \ No newline at end of file