diff --git a/CMakeLists.txt b/CMakeLists.txt index 92a9789db87..fd8ede07e67 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) @@ -1004,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) @@ -1070,6 +1074,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/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/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_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; 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; +} 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 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); +} 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)