diff --git a/include/hal/library/eventlib.h b/include/hal/library/eventlib.h index d322b4dd402..4966516c2fc 100644 --- a/include/hal/library/eventlib.h +++ b/include/hal/library/eventlib.h @@ -38,5 +38,29 @@ extern bool libspdm_event_get_types( void *supported_event_groups_list, uint32_t *supported_event_groups_list_len, uint8_t *event_group_count); + +/** + * Subscribe to the events given in SubscribeList. + * + * If subscribe_event_group_count is 0 then the event recipient unsubscribes from all events and + * subscribe_list_len is 0 and subscribe_list is NULL. For a given event group, if + * SPDM_SUBSCRIBE_EVENT_TYPES_REQUEST_ATTRIBUTE_ALL is set in the Attributes field then the event + * recipient subscribes to all events in that group. + * + * @param spdm_context A pointer to the SPDM context. + * @param spdm_version Indicates the negotiated version. + * @param subscribe_event_group_count Number of event groups in subscribe_list. + * @param subscribe_list_len Size, in bytes, of subscribe_list. + * @param subscribe_list Buffer that contains the event groups to be subscribed. + * + * @retval true All events were successfully subscribed or unsubscribed to. + * @retval false An error occurred when processing the event group list. + **/ +extern bool libspdm_event_subscribe( + void *spdm_context, + spdm_version_number_t spdm_version, + uint8_t subscribe_event_group_count, + uint32_t subscribe_list_len, + const void *subscribe_list); #endif /* LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP */ #endif /* EVENTLIB_H */ diff --git a/include/industry_standard/spdm.h b/include/industry_standard/spdm.h index ae7a0c617c3..c57592e53f6 100644 --- a/include/industry_standard/spdm.h +++ b/include/industry_standard/spdm.h @@ -56,6 +56,7 @@ /* SPDM response code (1.3) */ #define SPDM_SUPPORTED_EVENT_TYPES 0x62 +#define SPDM_SUBSCRIBE_EVENT_TYPES_ACK 0x70 #define SPDM_MEASUREMENT_EXTENSION_LOG 0x6F /* SPDM request code (1.0) */ @@ -88,6 +89,7 @@ /* SPDM request code (1.3) */ #define SPDM_GET_SUPPORTED_EVENT_TYPES 0xE2 +#define SPDM_SUBSCRIBE_EVENT_TYPES 0xF0 #define SPDM_GET_MEASUREMENT_EXTENSION_LOG 0xEF /* SPDM message header*/ @@ -1195,6 +1197,22 @@ typedef struct { /* uint8_t supported_event_groups_list[supported_event_groups_list_len] */ } spdm_supported_event_types_response_t; +typedef struct { + spdm_message_header_t header; + /* param1 == SubscribeEventGroupCount + * param2 == RSVD */ + uint32_t subscribe_list_len; + /* uint8_t subscribe_list[subscribe_list_len] */ +} spdm_subscribe_event_types_request_t; + +#define SPDM_SUBSCRIBE_EVENT_TYPES_REQUEST_ATTRIBUTE_ALL (1 << 0) + +typedef struct { + spdm_message_header_t header; + /* param1 == RSVD + * param2 == RSVD */ +} spdm_subscribe_event_types_ack_response_t; + /* SPDM GET_MEASUREMENT_EXTENSION_LOG request */ typedef struct { spdm_message_header_t header; diff --git a/include/internal/libspdm_responder_lib.h b/include/internal/libspdm_responder_lib.h index 5b9032e3da5..8c623b37eb5 100644 --- a/include/internal/libspdm_responder_lib.h +++ b/include/internal/libspdm_responder_lib.h @@ -778,14 +778,19 @@ libspdm_return_t libspdm_get_response_chunk_send(libspdm_context_t *spdm_context #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */ #if LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP -/** - * Process the SPDM GET_SUPPORTED_EVENT_TYPES request and return the response. - **/ +/* Process the SPDM GET_SUPPORTED_EVENT_TYPES request and return the response. */ libspdm_return_t libspdm_get_response_supported_event_types(libspdm_context_t *spdm_context, size_t request_size, const void *request, size_t *response_size, void *response); + +/* Process the SPDM SUBSCRIBE_EVENT_TYPES request and return the response. */ +libspdm_return_t libspdm_get_response_subscribe_event_types_ack(libspdm_context_t *spdm_context, + size_t request_size, + const void *request, + size_t *response_size, + void *response); #endif /* LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP */ #if LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES diff --git a/include/library/spdm_requester_lib.h b/include/library/spdm_requester_lib.h index 83c8f66d715..f7857e213fe 100644 --- a/include/library/spdm_requester_lib.h +++ b/include/library/spdm_requester_lib.h @@ -813,6 +813,25 @@ libspdm_return_t libspdm_get_event_types(void *spdm_context, uint8_t *event_group_count, uint32_t *supported_event_groups_list_len, void *supported_event_groups_list); + +/** This function subscribes to the specified event types. + * + * This function can only be called after a secure session has been established with the device. + * + * @param spdm_context A pointer to the SPDM context. + * @param session_id The session ID of the session. + * @param subscribe_event_group_count The number of event groups in subscribe_list. If this value + * is 0 then subscription to all events will be cleared and + * subscribe_list_len must be 0 and subscribe_list must be + * NULL. + * @param subscribe_list_len The size, in bytes, of subscribe_list. + * @param subscribe_list List of event types and event groups. + **/ +libspdm_return_t libspdm_subscribe_event_types(void *spdm_context, + uint32_t session_id, + uint8_t subscribe_event_group_count, + uint32_t subscribe_list_len, + void *subscribe_list); #endif /* LIBSPDM_EVENT_RECIPIENT_SUPPORT */ #if LIBSPDM_ENABLE_MSG_LOG diff --git a/library/spdm_requester_lib/CMakeLists.txt b/library/spdm_requester_lib/CMakeLists.txt index a49ad514053..916edbacf53 100644 --- a/library/spdm_requester_lib/CMakeLists.txt +++ b/library/spdm_requester_lib/CMakeLists.txt @@ -24,6 +24,7 @@ target_sources(spdm_requester_lib libspdm_req_get_certificate.c libspdm_req_get_digests.c libspdm_req_get_event_types.c + libspdm_req_subscribe_event_types.c libspdm_req_get_measurements.c libspdm_req_get_version.c libspdm_req_handle_error_response.c diff --git a/library/spdm_requester_lib/libspdm_req_subscribe_event_types.c b/library/spdm_requester_lib/libspdm_req_subscribe_event_types.c new file mode 100644 index 00000000000..f696f11bf7c --- /dev/null +++ b/library/spdm_requester_lib/libspdm_req_subscribe_event_types.c @@ -0,0 +1,176 @@ +/** + * 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 "internal/libspdm_requester_lib.h" + +#if LIBSPDM_EVENT_RECIPIENT_SUPPORT + +static libspdm_return_t try_libspdm_subscribe_event_types(libspdm_context_t *spdm_context, + uint32_t session_id, + uint8_t subscribe_event_group_count, + uint32_t subscribe_list_len, + void *subscribe_list) +{ + libspdm_return_t status; + libspdm_session_info_t *session_info; + spdm_subscribe_event_types_request_t *spdm_request; + size_t spdm_request_size; + spdm_supported_event_types_response_t *spdm_response; + size_t spdm_response_size; + size_t transport_header_size; + uint8_t *message; + size_t message_size; + + /* -=[Check Parameters Phase]=- */ + if (subscribe_event_group_count == 0) { + if ((subscribe_list_len != 0) || (subscribe_list != NULL)) { + return LIBSPDM_STATUS_INVALID_PARAMETER; + } + } else { + if ((subscribe_list_len == 0) || (subscribe_list == NULL)) { + return LIBSPDM_STATUS_INVALID_PARAMETER; + } + } + + session_info = libspdm_get_session_info_via_session_id(spdm_context, session_id); + + if (session_info == NULL) { + LIBSPDM_ASSERT(false); + return LIBSPDM_STATUS_INVALID_STATE_LOCAL; + } + if (libspdm_secured_message_get_session_state(session_info->secured_message_context) != + LIBSPDM_SESSION_STATE_ESTABLISHED) { + return LIBSPDM_STATUS_INVALID_STATE_LOCAL; + } + + /* -=[Verify State Phase]=- */ + if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_13) { + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + if (!libspdm_is_capabilities_flag_supported( + spdm_context, true, 0, + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_EVENT_CAP)) { + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + + /* -=[Construct Request Phase]=- */ + transport_header_size = spdm_context->local_context.capability.transport_header_size; + status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + return status; + } + LIBSPDM_ASSERT (message_size >= transport_header_size + + spdm_context->local_context.capability.transport_tail_size); + spdm_request = (void *)(message + transport_header_size); + spdm_request_size = message_size - transport_header_size - + spdm_context->local_context.capability.transport_tail_size; + LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_subscribe_event_types_request_t)); + + if (spdm_request_size < (sizeof(spdm_subscribe_event_types_request_t) + subscribe_list_len)) { + libspdm_release_sender_buffer(spdm_context); + return LIBSPDM_STATUS_BUFFER_TOO_SMALL; + } + + spdm_request->header.spdm_version = libspdm_get_connection_version(spdm_context); + spdm_request->header.request_response_code = SPDM_SUBSCRIBE_EVENT_TYPES; + spdm_request->header.param1 = subscribe_event_group_count; + spdm_request->header.param2 = 0; + spdm_request->subscribe_list_len = subscribe_list_len; + + if (subscribe_list != NULL) { + libspdm_copy_mem(spdm_request + 1, + spdm_request_size - sizeof(spdm_subscribe_event_types_request_t), + subscribe_list, + subscribe_list_len); + } + + spdm_request_size = sizeof(spdm_subscribe_event_types_request_t) + subscribe_list_len; + + /* -=[Send Request Phase]=- */ + status = libspdm_send_spdm_request(spdm_context, &session_id, spdm_request_size, spdm_request); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + libspdm_release_sender_buffer (spdm_context); + return status; + } + + libspdm_release_sender_buffer(spdm_context); + spdm_request = (void *)spdm_context->last_spdm_request; + + /* -=[Receive Response Phase]=- */ + status = libspdm_acquire_receiver_buffer(spdm_context, &message_size, (void **)&message); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + return status; + } + LIBSPDM_ASSERT (message_size >= transport_header_size); + spdm_response = (void *)(message); + spdm_response_size = message_size; + + status = libspdm_receive_spdm_response( + spdm_context, &session_id, &spdm_response_size, (void **)&spdm_response); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + goto receive_done; + } + + /* -=[Validate Response Phase]=- */ + if (spdm_response_size != sizeof(spdm_subscribe_event_types_ack_response_t)) { + status = LIBSPDM_STATUS_INVALID_MSG_SIZE; + goto receive_done; + } + if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) { + status = LIBSPDM_STATUS_INVALID_MSG_FIELD; + goto receive_done; + } + if (spdm_response->header.request_response_code == SPDM_ERROR) { + status = libspdm_handle_error_response_main( + spdm_context, &session_id, + &spdm_response_size, (void **)&spdm_response, + SPDM_SUBSCRIBE_EVENT_TYPES, SPDM_SUBSCRIBE_EVENT_TYPES_ACK); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + goto receive_done; + } + } else if (spdm_response->header.request_response_code != SPDM_SUBSCRIBE_EVENT_TYPES_ACK) { + status = LIBSPDM_STATUS_INVALID_MSG_FIELD; + goto receive_done; + } + +receive_done: + libspdm_release_receiver_buffer(spdm_context); + + return status; +} + +libspdm_return_t libspdm_subscribe_event_types(void *spdm_context, + uint32_t session_id, + uint8_t subscribe_event_group_count, + uint32_t subscribe_list_len, + void *subscribe_list) +{ + size_t retry; + uint64_t retry_delay_time; + libspdm_return_t status; + libspdm_context_t *context; + + context = spdm_context; + context->crypto_request = true; + retry = context->retry_times; + retry_delay_time = context->retry_delay_time; + do { + status = try_libspdm_subscribe_event_types(context, + session_id, + subscribe_event_group_count, + subscribe_list_len, + subscribe_list); + if ((status != LIBSPDM_STATUS_BUSY_PEER) || (retry == 0)) { + return status; + } + + libspdm_sleep(retry_delay_time); + } while (retry-- != 0); + + return status; +} + +#endif /* LIBSPDM_EVENT_RECIPIENT_SUPPORT */ diff --git a/library/spdm_responder_lib/CMakeLists.txt b/library/spdm_responder_lib/CMakeLists.txt index 03880eddc1d..22e21ed8cf7 100644 --- a/library/spdm_responder_lib/CMakeLists.txt +++ b/library/spdm_responder_lib/CMakeLists.txt @@ -37,6 +37,7 @@ target_sources(spdm_responder_lib libspdm_rsp_version.c libspdm_rsp_set_certificate.c libspdm_rsp_supported_event_types.c + libspdm_rsp_subscribe_event_types_ack.c libspdm_rsp_csr.c libspdm_rsp_chunk_send_ack.c libspdm_rsp_chunk_get.c diff --git a/library/spdm_responder_lib/libspdm_rsp_receive_send.c b/library/spdm_responder_lib/libspdm_rsp_receive_send.c index d4c3f228776..d669dc1960a 100644 --- a/library/spdm_responder_lib/libspdm_rsp_receive_send.c +++ b/library/spdm_responder_lib/libspdm_rsp_receive_send.c @@ -91,6 +91,7 @@ libspdm_get_spdm_response_func libspdm_get_response_func_via_request_code(uint8_ #if LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP { SPDM_SUPPORTED_EVENT_TYPES, libspdm_get_response_supported_event_types }, + { SPDM_SUBSCRIBE_EVENT_TYPES, libspdm_get_response_subscribe_event_types_ack }, #endif /* LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP */ #if LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES diff --git a/library/spdm_responder_lib/libspdm_rsp_subscribe_event_types_ack.c b/library/spdm_responder_lib/libspdm_rsp_subscribe_event_types_ack.c new file mode 100644 index 00000000000..720a95cbf56 --- /dev/null +++ b/library/spdm_responder_lib/libspdm_rsp_subscribe_event_types_ack.c @@ -0,0 +1,150 @@ +/** + * 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 "internal/libspdm_responder_lib.h" +#include "internal/libspdm_secured_message_lib.h" + +#if LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP + +libspdm_return_t libspdm_get_response_subscribe_event_types_ack(libspdm_context_t *spdm_context, + size_t request_size, + const void *request, + size_t *response_size, + void *response) +{ + spdm_subscribe_event_types_ack_response_t *spdm_response; + const spdm_subscribe_event_types_request_t *spdm_request; + const size_t response_buffer_size = *response_size; + uint32_t session_id; + libspdm_session_info_t *session_info; + libspdm_session_state_t session_state; + uint8_t subscribe_event_group_count; + uint32_t subscribe_list_len; + const void *subscribe_list; + + spdm_request = request; + + /* -=[Check Parameters Phase]=- */ + LIBSPDM_ASSERT(spdm_request->header.request_response_code == SPDM_SUBSCRIBE_EVENT_TYPES); + + /* -=[Verify State Phase]=- */ + if (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) { + return libspdm_responder_handle_response_state( + spdm_context, + spdm_request->header.request_response_code, + response_size, response); + } + if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) { + return libspdm_generate_error_response(spdm_context, + SPDM_ERROR_CODE_UNEXPECTED_REQUEST, + 0, response_size, response); + } + if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_13) { + return libspdm_generate_error_response(spdm_context, + SPDM_ERROR_CODE_UNSUPPORTED_REQUEST, + SPDM_SUBSCRIBE_EVENT_TYPES, + response_size, response); + } + if (!libspdm_is_capabilities_flag_supported( + spdm_context, false, + 0, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_EVENT_CAP)) { + return libspdm_generate_error_response( + spdm_context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST, + SPDM_SUBSCRIBE_EVENT_TYPES, response_size, response); + } + if (!spdm_context->last_spdm_request_session_id_valid) { + return libspdm_generate_error_response(spdm_context, + SPDM_ERROR_CODE_SESSION_REQUIRED, 0, + response_size, response); + } + session_id = spdm_context->last_spdm_request_session_id; + session_info = libspdm_get_session_info_via_session_id(spdm_context, session_id); + if (session_info == NULL) { + return libspdm_generate_error_response(spdm_context, + SPDM_ERROR_CODE_SESSION_REQUIRED, 0, + response_size, response); + } + session_state = libspdm_secured_message_get_session_state( + session_info->secured_message_context); + if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) { + return libspdm_generate_error_response(spdm_context, + SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0, + response_size, response); + } + + /* -=[Validate Request Phase]=- */ + if (request_size < sizeof(spdm_message_header_t)) { + return libspdm_generate_error_response(spdm_context, + SPDM_ERROR_CODE_INVALID_REQUEST, 0, + response_size, response); + } + if (spdm_request->header.spdm_version != libspdm_get_connection_version(spdm_context)) { + return libspdm_generate_error_response(spdm_context, + SPDM_ERROR_CODE_VERSION_MISMATCH, 0, + response_size, response); + } + + /* This message can only be in secured session. + * Thus don't need to consider transport layer padding, just check its exact size. */ + subscribe_event_group_count = spdm_request->header.param1; + + if (subscribe_event_group_count == 0) { + if (request_size != sizeof(spdm_message_header_t)) { + return libspdm_generate_error_response(spdm_context, + SPDM_ERROR_CODE_INVALID_REQUEST, 0, + response_size, response); + } + } else { + if (request_size < (sizeof(spdm_message_header_t) + sizeof(uint32_t))) { + return libspdm_generate_error_response(spdm_context, + SPDM_ERROR_CODE_INVALID_REQUEST, 0, + response_size, response); + } + if (request_size != (sizeof(spdm_subscribe_event_types_request_t) + + spdm_request->subscribe_list_len)) { + return libspdm_generate_error_response(spdm_context, + SPDM_ERROR_CODE_INVALID_REQUEST, 0, + response_size, response); + } + } + + if ((subscribe_event_group_count != 0) && (spdm_request->subscribe_list_len == 0)) { + return libspdm_generate_error_response(spdm_context, + SPDM_ERROR_CODE_INVALID_REQUEST, 0, + response_size, response); + } + + if (subscribe_event_group_count == 0) { + subscribe_list_len = 0; + subscribe_list = NULL; + } else { + subscribe_list_len = spdm_request->subscribe_list_len; + subscribe_list = (const void *)(spdm_request + 1); + } + + if (!libspdm_event_subscribe(spdm_context, spdm_context->connection_info.version, + subscribe_event_group_count, subscribe_list_len, subscribe_list)) { + return libspdm_generate_error_response(spdm_context, + SPDM_ERROR_CODE_INVALID_REQUEST, 0, + response_size, response); + } + + /* -=[Construct Response Phase]=- */ + LIBSPDM_ASSERT(response_buffer_size >= sizeof(spdm_subscribe_event_types_ack_response_t)); + libspdm_zero_mem(response, response_buffer_size); + spdm_response = response; + + spdm_response->header.spdm_version = libspdm_get_connection_version(spdm_context); + spdm_response->header.request_response_code = SPDM_SUBSCRIBE_EVENT_TYPES_ACK; + spdm_response->header.param1 = 0; + spdm_response->header.param2 = 0; + + *response_size = sizeof(spdm_subscribe_event_types_ack_response_t); + + return LIBSPDM_STATUS_SUCCESS; +} + +#endif /* LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP */ diff --git a/os_stub/spdm_device_secret_lib_null/lib.c b/os_stub/spdm_device_secret_lib_null/lib.c index e69d5efddae..1bafff842de 100644 --- a/os_stub/spdm_device_secret_lib_null/lib.c +++ b/os_stub/spdm_device_secret_lib_null/lib.c @@ -234,4 +234,14 @@ bool libspdm_event_get_types( { return false; } + +bool libspdm_event_subscribe( + void *spdm_context, + spdm_version_number_t spdm_version, + uint8_t subscribe_event_group_count, + uint32_t subscribe_list_len, + const void *subscribe_list) +{ + return false; +} #endif /* LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP */ diff --git a/os_stub/spdm_device_secret_lib_sample/lib.c b/os_stub/spdm_device_secret_lib_sample/lib.c index 417b60a6045..a88540402e9 100644 --- a/os_stub/spdm_device_secret_lib_sample/lib.c +++ b/os_stub/spdm_device_secret_lib_sample/lib.c @@ -2228,4 +2228,33 @@ bool libspdm_event_get_types( return true; } + +bool libspdm_event_subscribe( + void *spdm_context, + spdm_version_number_t spdm_version, + uint8_t subscribe_event_group_count, + uint32_t subscribe_list_len, + const void *subscribe_list) +{ + if (subscribe_event_group_count == 0) { + if ((subscribe_list_len != 0) || (subscribe_list != NULL)) { + return false; + } + } else { + if ((subscribe_list_len == 0) || (subscribe_list == NULL)) { + return false; + } + } + + LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, + "subscribe_event_group_count == %d, subscribe_list_len = %d\n", + subscribe_event_group_count, subscribe_list_len)); + + for (uint32_t index = 0; index < subscribe_list_len; index++) { + printf("%02x ", ((const char *)subscribe_list)[index]); + } + printf("\n"); + + return true; +} #endif /* LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP */ diff --git a/unit_test/spdm_unit_test_common/event_support.c b/unit_test/spdm_unit_test_common/event_support.c new file mode 100644 index 00000000000..4c24dab39bd --- /dev/null +++ b/unit_test/spdm_unit_test_common/event_support.c @@ -0,0 +1,99 @@ +/** + * 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 "spdm_unit_test.h" + +#pragma pack(1) +typedef struct { + uint8_t id; + uint8_t vendor_id_len; +} event_group_id_0byte_t; + +typedef struct { + uint8_t id; + uint8_t vendor_id_len; + uint16_t vendor_id; +} event_group_id_2byte_t; + +typedef struct { + uint16_t event_type_count; + uint16_t event_group_ver; + uint32_t attributes; + /* uint8_t event_type_list[] */ +} event_group_t; + +typedef struct { + uint16_t event_type_id; + uint16_t reserved; +} event_type_t; +#pragma pack() + +void generate_dmtf_event_group(void *buffer, uint8_t *total_bytes, uint32_t attributes, + bool inc_event_lost, bool inc_meas_changed, + bool inc_meas_pre_update, bool inc_cert_changed) +{ + uint8_t *ptr; + uint16_t event_type_count; + + LIBSPDM_ASSERT(!(attributes & SPDM_SUBSCRIBE_EVENT_TYPES_REQUEST_ATTRIBUTE_ALL) || + (!inc_event_lost && !inc_meas_changed && + !inc_meas_pre_update && !inc_cert_changed)); + + event_type_count = 0; + + if (inc_event_lost) { + event_type_count++; + } + if (inc_meas_changed) { + event_type_count++; + } + if (inc_meas_pre_update) { + event_type_count++; + } + if (inc_cert_changed) { + event_type_count++; + } + + ptr = buffer; + *total_bytes = 0; + + ((event_group_id_0byte_t *)ptr)->id = SPDM_REGISTRY_ID_DMTF; + ((event_group_id_0byte_t *)ptr)->vendor_id_len = 0; + + ptr += sizeof(event_group_id_0byte_t); + *total_bytes += (uint8_t)sizeof(event_group_id_0byte_t); + + ((event_group_t *)ptr)->event_type_count = event_type_count; + ((event_group_t *)ptr)->event_group_ver = 1; + ((event_group_t *)ptr)->attributes = attributes; + + ptr += sizeof(event_group_t); + *total_bytes += (uint8_t)sizeof(event_group_t); + + if (inc_event_lost) { + ((event_type_t *)ptr)->event_type_id = SPDM_DMTF_EVENT_TYPE_EVENT_LOST; + ((event_type_t *)ptr)->reserved = 0; + ptr += sizeof(event_type_t); + *total_bytes += (uint8_t)sizeof(event_type_t); + } + if (inc_meas_changed) { + ((event_type_t *)ptr)->event_type_id = SPDM_DMTF_EVENT_TYPE_MEASUREMENT_CHANGED; + ((event_type_t *)ptr)->reserved = 0; + ptr += sizeof(event_type_t); + *total_bytes += (uint8_t)sizeof(event_type_t); + } + if (inc_meas_pre_update) { + ((event_type_t *)ptr)->event_type_id = SPDM_DMTF_EVENT_TYPE_MEASUREMENT_PRE_UPDATE; + ((event_type_t *)ptr)->reserved = 0; + ptr += sizeof(event_type_t); + *total_bytes += (uint8_t)sizeof(event_type_t); + } + if (inc_cert_changed) { + ((event_type_t *)ptr)->event_type_id = SPDM_DMTF_EVENT_TYPE_CERTIFICATE_CHANGED; + ((event_type_t *)ptr)->reserved = 0; + *total_bytes += (uint8_t)sizeof(event_type_t); + } +} diff --git a/unit_test/spdm_unit_test_common/spdm_unit_test.h b/unit_test/spdm_unit_test_common/spdm_unit_test.h index 2e3eb5c7738..89649677f84 100644 --- a/unit_test/spdm_unit_test_common/spdm_unit_test.h +++ b/unit_test/spdm_unit_test_common/spdm_unit_test.h @@ -162,4 +162,8 @@ typedef enum void libspdm_force_error (libspdm_error_target_t target); void libspdm_release_error (libspdm_error_target_t target); +void generate_dmtf_event_group(void *buffer, uint8_t *total_bytes, uint32_t attributes, + bool inc_event_lost, bool inc_meas_changed, + bool inc_meas_pre_update, bool inc_cert_changed); + #endif diff --git a/unit_test/test_spdm_requester/CMakeLists.txt b/unit_test/test_spdm_requester/CMakeLists.txt index dd16ffc018e..7771c54c802 100644 --- a/unit_test/test_spdm_requester/CMakeLists.txt +++ b/unit_test/test_spdm_requester/CMakeLists.txt @@ -24,6 +24,7 @@ target_sources(test_spdm_requester get_certificate.c challenge.c get_event_types.c + subscribe_event_types.c get_measurements.c get_measurement_extension_log.c key_exchange.c @@ -50,10 +51,12 @@ target_sources(test_spdm_requester error_test/key_exchange_err.c error_test/get_measurements_err.c error_test/get_event_types_err.c + error_test/subscribe_event_types_err.c error_test/vendor_request_err.c ${LIBSPDM_DIR}/unit_test/spdm_unit_test_common/common.c ${LIBSPDM_DIR}/unit_test/spdm_unit_test_common/algo.c ${LIBSPDM_DIR}/unit_test/spdm_unit_test_common/support.c + ${LIBSPDM_DIR}/unit_test/spdm_unit_test_common/event_support.c ) if(CMAKE_SYSTEM_NAME MATCHES "Windows") diff --git a/unit_test/test_spdm_requester/error_test/get_event_types_err.c b/unit_test/test_spdm_requester/error_test/get_event_types_err.c index 0ba35042060..8b9ed5d00d5 100644 --- a/unit_test/test_spdm_requester/error_test/get_event_types_err.c +++ b/unit_test/test_spdm_requester/error_test/get_event_types_err.c @@ -15,31 +15,6 @@ static uint8_t m_spdm_request_buffer[0x1000]; static const uint32_t m_session_id = 0xffffffff; -#pragma pack(1) -typedef struct { - uint8_t id; - uint8_t vendor_id_len; -} event_group_id_0byte_t; - -typedef struct { - uint8_t id; - uint8_t vendor_id_len; - uint16_t vendor_id; -} event_group_id_2byte_t; - -typedef struct { - uint16_t event_type_count; - uint16_t event_group_ver; - uint32_t attributes; - /* uint8_t event_type_list[] */ -} event_group_t; - -typedef struct { - uint16_t event_type_id; - uint16_t reserved; -} event_type_t; -#pragma pack() - static void set_standard_state(libspdm_context_t *spdm_context, uint32_t *session_id) { libspdm_session_info_t *session_info; @@ -76,69 +51,6 @@ static void set_standard_state(libspdm_context_t *spdm_context, uint32_t *sessio session_info->secured_message_context, LIBSPDM_SESSION_STATE_ESTABLISHED); } -static void generate_dmtf_event_group(void *buffer, uint8_t *total_bytes, - bool inc_event_lost, bool inc_meas_changed, - bool inc_meas_pre_update, bool inc_cert_changed) -{ - uint8_t *ptr; - uint16_t event_type_count; - - event_type_count = 0; - - if (inc_event_lost) { - event_type_count++; - } - if (inc_meas_changed) { - event_type_count++; - } - if (inc_meas_pre_update) { - event_type_count++; - } - if (inc_cert_changed) { - event_type_count++; - } - - ptr = buffer; - *total_bytes = 0; - - ((event_group_id_0byte_t *)ptr)->id = SPDM_REGISTRY_ID_DMTF; - ((event_group_id_0byte_t *)ptr)->vendor_id_len = 0; - - ptr += sizeof(event_group_id_0byte_t); - *total_bytes += (uint8_t)sizeof(event_group_id_0byte_t); - - ((event_group_t *)ptr)->event_type_count = event_type_count; - ((event_group_t *)ptr)->event_group_ver = 1; - ((event_group_t *)ptr)->attributes = 0; - - ptr += sizeof(event_group_t); - *total_bytes += (uint8_t)sizeof(event_group_t); - - if (inc_event_lost) { - ((event_type_t *)ptr)->event_type_id = SPDM_DMTF_EVENT_TYPE_EVENT_LOST; - ((event_type_t *)ptr)->reserved = 0; - ptr += sizeof(event_type_t); - *total_bytes += (uint8_t)sizeof(event_type_t); - } - if (inc_meas_changed) { - ((event_type_t *)ptr)->event_type_id = SPDM_DMTF_EVENT_TYPE_MEASUREMENT_CHANGED; - ((event_type_t *)ptr)->reserved = 0; - ptr += sizeof(event_type_t); - *total_bytes += (uint8_t)sizeof(event_type_t); - } - if (inc_meas_pre_update) { - ((event_type_t *)ptr)->event_type_id = SPDM_DMTF_EVENT_TYPE_MEASUREMENT_PRE_UPDATE; - ((event_type_t *)ptr)->reserved = 0; - ptr += sizeof(event_type_t); - *total_bytes += (uint8_t)sizeof(event_type_t); - } - if (inc_cert_changed) { - ((event_type_t *)ptr)->event_type_id = SPDM_DMTF_EVENT_TYPE_CERTIFICATE_CHANGED; - ((event_type_t *)ptr)->reserved = 0; - *total_bytes += (uint8_t)sizeof(event_type_t); - } -} - static libspdm_return_t send_message( void *spdm_context, size_t request_size, const void *request, uint64_t timeout) { @@ -213,7 +125,7 @@ static libspdm_return_t receive_message( spdm_response->header.param1 = 0; spdm_response->header.param2 = 0; - generate_dmtf_event_group(spdm_response + 1, &event_group_total_bytes, + generate_dmtf_event_group(spdm_response + 1, &event_group_total_bytes, 0, true, true, true, true); spdm_response->supported_event_groups_list_len = event_group_total_bytes; diff --git a/unit_test/test_spdm_requester/error_test/subscribe_event_types_err.c b/unit_test/test_spdm_requester/error_test/subscribe_event_types_err.c new file mode 100644 index 00000000000..44ae225c3ed --- /dev/null +++ b/unit_test/test_spdm_requester/error_test/subscribe_event_types_err.c @@ -0,0 +1,257 @@ +/** + * 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 "spdm_unit_test.h" +#include "internal/libspdm_requester_lib.h" +#include "internal/libspdm_secured_message_lib.h" + +#if LIBSPDM_EVENT_RECIPIENT_SUPPORT + +static const uint32_t m_session_id = 0xffffffff; + +static uint8_t m_spdm_request_buffer[0x1000]; + +static struct test_params { + uint8_t subscribe_event_group_count; + uint32_t subscribe_list_len; + uint8_t subscribe_list[0x1000]; +} test_params; + +static void set_standard_state(libspdm_context_t *spdm_context, uint32_t *session_id) +{ + libspdm_session_info_t *session_info; + + spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_13 << + SPDM_VERSION_NUMBER_SHIFT_BIT; + spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_NEGOTIATED; + + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_EVENT_CAP; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ENCRYPT_CAP; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MAC_CAP; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP; + + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_ENCRYPT_CAP; + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MAC_CAP; + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_EX_CAP; + + spdm_context->connection_info.algorithm.base_hash_algo = m_libspdm_use_hash_algo; + spdm_context->connection_info.algorithm.base_asym_algo = m_libspdm_use_asym_algo; + spdm_context->connection_info.algorithm.dhe_named_group = m_libspdm_use_dhe_algo; + spdm_context->connection_info.algorithm.aead_cipher_suite = m_libspdm_use_aead_algo; + + *session_id = m_session_id; + session_info = &spdm_context->session_info[0]; + libspdm_session_info_init(spdm_context, session_info, *session_id, true); + libspdm_secured_message_set_session_state( + session_info->secured_message_context, LIBSPDM_SESSION_STATE_ESTABLISHED); +} + +static libspdm_return_t send_message( + void *spdm_context, size_t request_size, const void *request, uint64_t timeout) +{ + libspdm_return_t status; + uint32_t session_id; + uint32_t *message_session_id; + spdm_subscribe_event_types_request_t *spdm_message; + bool is_app_message; + void *spdm_request_buffer; + size_t spdm_request_size; + libspdm_session_info_t *session_info; + uint8_t request_buffer[0x1000]; + + /* Workaround request being const. */ + libspdm_copy_mem(request_buffer, sizeof(request_buffer), request, request_size); + + session_id = m_session_id; + session_info = libspdm_get_session_info_via_session_id(spdm_context, session_id); + LIBSPDM_ASSERT(session_info != NULL); + + ((libspdm_secured_message_context_t *)(session_info->secured_message_context))-> + application_secret.request_data_sequence_number--; + + spdm_request_buffer = m_spdm_request_buffer; + spdm_request_size = sizeof(m_spdm_request_buffer); + + status = libspdm_transport_test_decode_message(spdm_context, &message_session_id, + &is_app_message, true, + request_size, request_buffer, + &spdm_request_size, &spdm_request_buffer); + + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + assert_int_equal(sizeof(spdm_subscribe_event_types_request_t) + test_params.subscribe_list_len, + spdm_request_size); + + spdm_message = spdm_request_buffer; + + assert_int_equal(spdm_message->header.spdm_version, SPDM_MESSAGE_VERSION_13); + assert_int_equal(spdm_message->header.request_response_code, SPDM_SUBSCRIBE_EVENT_TYPES); + assert_int_equal(spdm_message->header.param1, test_params.subscribe_event_group_count); + assert_int_equal(spdm_message->header.param2, 0); + assert_int_equal(spdm_message->subscribe_list_len, test_params.subscribe_list_len); + + assert_memory_equal(spdm_message + 1, test_params.subscribe_list, + spdm_message->subscribe_list_len); + + return LIBSPDM_STATUS_SUCCESS; +} + +static libspdm_return_t receive_message( + void *spdm_context, size_t *response_size, void **response, uint64_t timeout) +{ + spdm_subscribe_event_types_ack_response_t *spdm_response; + size_t spdm_response_size; + size_t transport_header_size; + uint32_t session_id; + libspdm_session_info_t *session_info; + uint8_t *scratch_buffer; + size_t scratch_buffer_size; + + transport_header_size = LIBSPDM_TEST_TRANSPORT_HEADER_SIZE; + spdm_response = (void *)((uint8_t *)*response + transport_header_size); + + session_id = m_session_id; + session_info = libspdm_get_session_info_via_session_id(spdm_context, session_id); + LIBSPDM_ASSERT((session_info != NULL)); + + transport_header_size = LIBSPDM_TEST_TRANSPORT_HEADER_SIZE; + spdm_response = (void *)((uint8_t *)*response + transport_header_size); + + spdm_response_size = sizeof(spdm_subscribe_event_types_ack_response_t); + libspdm_zero_mem(spdm_response, spdm_response_size); + + spdm_response->header.spdm_version = SPDM_MESSAGE_VERSION_13; + spdm_response->header.request_response_code = SPDM_SUBSCRIBE_EVENT_TYPES_ACK; + spdm_response->header.param1 = 0; + spdm_response->header.param2 = 0; + + /* For secure message, message is in sender buffer, we need copy it to scratch buffer. + * transport_message is always in sender buffer. */ + libspdm_get_scratch_buffer(spdm_context, (void **)&scratch_buffer, &scratch_buffer_size); + libspdm_copy_mem(scratch_buffer + transport_header_size, + scratch_buffer_size - transport_header_size, + spdm_response, spdm_response_size); + + spdm_response = (void *)(scratch_buffer + transport_header_size); + + libspdm_transport_test_encode_message(spdm_context, &session_id, + false, false, spdm_response_size, + spdm_response, response_size, response); + + /* Workaround: Use single context to encode message and then decode message. */ + ((libspdm_secured_message_context_t *)(session_info->secured_message_context))-> + application_secret.response_data_sequence_number--; + + return LIBSPDM_STATUS_SUCCESS; +} + +/** + * Test 1: Test invalid arguments for subscribe_event_group_count, subscribe_list_len, and + * subscribe_list. + * Expected Behavior: Returns LIBSPDM_STATUS_INVALID_PARAMETER. + **/ +static void libspdm_test_requester_subscribe_event_types_err_case1(void **state) +{ + libspdm_return_t status; + libspdm_test_context_t *spdm_test_context; + libspdm_context_t *spdm_context; + uint32_t session_id; + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 0x1; + + set_standard_state(spdm_context, &session_id); + + /* subscribe_event_group_count is zero but subscribe_list_len is non-zero and subscribe_list is + * not NULL. */ + status = libspdm_subscribe_event_types(spdm_context, session_id, 0, 10, &session_id); + assert_int_equal(status, LIBSPDM_STATUS_INVALID_PARAMETER); + + /* subscribe_event_group_count is non-zero but subscribe_list_len is zero and subscribe_list is + * NULL. */ + status = libspdm_subscribe_event_types(spdm_context, session_id, 5, 0, NULL); + assert_int_equal(status, LIBSPDM_STATUS_INVALID_PARAMETER); +} + +/** + * Test 2: Test invalid state with SPDM version less than 1.3. + * Expected Behavior: Returns LIBSPDM_STATUS_UNSUPPORTED_CAP. + **/ +static void libspdm_test_requester_subscribe_event_types_err_case2(void **state) +{ + libspdm_return_t status; + libspdm_test_context_t *spdm_test_context; + libspdm_context_t *spdm_context; + uint32_t session_id; + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 0x2; + + set_standard_state(spdm_context, &session_id); + /* Invalid version. */ + spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 << + SPDM_VERSION_NUMBER_SHIFT_BIT; + + status = libspdm_subscribe_event_types(spdm_context, session_id, 0, 0, NULL); + assert_int_equal(status, LIBSPDM_STATUS_UNSUPPORTED_CAP); +} + +/** + * Test 3: Successful response to subscribe event types that includes one event group and all event + * types using the AllEventTypes attribute. + * Expected Behavior: Returns LIBSPDM_STATUS_UNSUPPORTED_CAP. + **/ +static void libspdm_test_requester_subscribe_event_types_err_case3(void **state) +{ + libspdm_return_t status; + libspdm_test_context_t *spdm_test_context; + libspdm_context_t *spdm_context; + uint32_t session_id; + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 0x3; + + set_standard_state(spdm_context, &session_id); + /* Responder does not support event mechanism. */ + spdm_context->connection_info.capability.flags &= + ~SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_EVENT_CAP; + + status = libspdm_subscribe_event_types(spdm_context, session_id, 0, 0, NULL); + assert_int_equal(status, LIBSPDM_STATUS_UNSUPPORTED_CAP); +} + +int libspdm_requester_subscribe_event_types_error_test_main(void) +{ + libspdm_test_context_t test_context = { + LIBSPDM_TEST_CONTEXT_VERSION, + true, + send_message, + receive_message, + }; + + const struct CMUnitTest spdm_requester_get_event_types_tests[] = { + cmocka_unit_test(libspdm_test_requester_subscribe_event_types_err_case1), + cmocka_unit_test(libspdm_test_requester_subscribe_event_types_err_case2), + cmocka_unit_test(libspdm_test_requester_subscribe_event_types_err_case3) + }; + + libspdm_setup_test_context(&test_context); + + return cmocka_run_group_tests(spdm_requester_get_event_types_tests, + libspdm_unit_test_group_setup, + libspdm_unit_test_group_teardown); +} + +#endif /* LIBSPDM_EVENT_RECIPIENT_SUPPORT */ diff --git a/unit_test/test_spdm_requester/get_event_types.c b/unit_test/test_spdm_requester/get_event_types.c index 689d3af2638..456da69b7ea 100644 --- a/unit_test/test_spdm_requester/get_event_types.c +++ b/unit_test/test_spdm_requester/get_event_types.c @@ -15,31 +15,6 @@ static uint8_t m_spdm_request_buffer[0x1000]; static const uint32_t m_session_id = 0xffffffff; -#pragma pack(1) -typedef struct { - uint8_t id; - uint8_t vendor_id_len; -} event_group_id_0byte_t; - -typedef struct { - uint8_t id; - uint8_t vendor_id_len; - uint16_t vendor_id; -} event_group_id_2byte_t; - -typedef struct { - uint16_t event_type_count; - uint16_t event_group_ver; - uint32_t attributes; - /* uint8_t event_type_list[] */ -} event_group_t; - -typedef struct { - uint16_t event_type_id; - uint16_t reserved; -} event_type_t; -#pragma pack() - static void set_standard_state(libspdm_context_t *spdm_context, uint32_t *session_id) { libspdm_session_info_t *session_info; @@ -76,69 +51,6 @@ static void set_standard_state(libspdm_context_t *spdm_context, uint32_t *sessio session_info->secured_message_context, LIBSPDM_SESSION_STATE_ESTABLISHED); } -static void generate_dmtf_event_group(void *buffer, uint8_t *total_bytes, - bool inc_event_lost, bool inc_meas_changed, - bool inc_meas_pre_update, bool inc_cert_changed) -{ - uint8_t *ptr; - uint16_t event_type_count; - - event_type_count = 0; - - if (inc_event_lost) { - event_type_count++; - } - if (inc_meas_changed) { - event_type_count++; - } - if (inc_meas_pre_update) { - event_type_count++; - } - if (inc_cert_changed) { - event_type_count++; - } - - ptr = buffer; - *total_bytes = 0; - - ((event_group_id_0byte_t *)ptr)->id = SPDM_REGISTRY_ID_DMTF; - ((event_group_id_0byte_t *)ptr)->vendor_id_len = 0; - - ptr += sizeof(event_group_id_0byte_t); - *total_bytes += (uint8_t)sizeof(event_group_id_0byte_t); - - ((event_group_t *)ptr)->event_type_count = event_type_count; - ((event_group_t *)ptr)->event_group_ver = 1; - ((event_group_t *)ptr)->attributes = 0; - - ptr += sizeof(event_group_t); - *total_bytes += (uint8_t)sizeof(event_group_t); - - if (inc_event_lost) { - ((event_type_t *)ptr)->event_type_id = SPDM_DMTF_EVENT_TYPE_EVENT_LOST; - ((event_type_t *)ptr)->reserved = 0; - ptr += sizeof(event_type_t); - *total_bytes += (uint8_t)sizeof(event_type_t); - } - if (inc_meas_changed) { - ((event_type_t *)ptr)->event_type_id = SPDM_DMTF_EVENT_TYPE_MEASUREMENT_CHANGED; - ((event_type_t *)ptr)->reserved = 0; - ptr += sizeof(event_type_t); - *total_bytes += (uint8_t)sizeof(event_type_t); - } - if (inc_meas_pre_update) { - ((event_type_t *)ptr)->event_type_id = SPDM_DMTF_EVENT_TYPE_MEASUREMENT_PRE_UPDATE; - ((event_type_t *)ptr)->reserved = 0; - ptr += sizeof(event_type_t); - *total_bytes += (uint8_t)sizeof(event_type_t); - } - if (inc_cert_changed) { - ((event_type_t *)ptr)->event_type_id = SPDM_DMTF_EVENT_TYPE_CERTIFICATE_CHANGED; - ((event_type_t *)ptr)->reserved = 0; - *total_bytes += (uint8_t)sizeof(event_type_t); - } -} - static libspdm_return_t send_message( void *spdm_context, size_t request_size, const void *request, uint64_t timeout) { @@ -212,7 +124,7 @@ static libspdm_return_t receive_message( spdm_response->header.param1 = 1; spdm_response->header.param2 = 0; - generate_dmtf_event_group(spdm_response + 1, &event_group_total_bytes, + generate_dmtf_event_group(spdm_response + 1, &event_group_total_bytes, 0, true, true, true, true); spdm_response->supported_event_groups_list_len = event_group_total_bytes; diff --git a/unit_test/test_spdm_requester/subscribe_event_types.c b/unit_test/test_spdm_requester/subscribe_event_types.c new file mode 100644 index 00000000000..0934b65b769 --- /dev/null +++ b/unit_test/test_spdm_requester/subscribe_event_types.c @@ -0,0 +1,268 @@ +/** + * 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 "spdm_unit_test.h" +#include "internal/libspdm_requester_lib.h" +#include "internal/libspdm_secured_message_lib.h" + +#if LIBSPDM_EVENT_RECIPIENT_SUPPORT + +static const uint32_t m_session_id = 0xffffffff; + +static uint8_t m_spdm_request_buffer[0x1000]; + +static struct test_params { + uint8_t subscribe_event_group_count; + uint32_t subscribe_list_len; + uint8_t subscribe_list[0x1000]; +} test_params; + +static void set_standard_state(libspdm_context_t *spdm_context, uint32_t *session_id) +{ + libspdm_session_info_t *session_info; + + spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_13 << + SPDM_VERSION_NUMBER_SHIFT_BIT; + spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_NEGOTIATED; + + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_EVENT_CAP; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ENCRYPT_CAP; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MAC_CAP; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP; + + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_ENCRYPT_CAP; + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MAC_CAP; + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_EX_CAP; + + spdm_context->connection_info.algorithm.base_hash_algo = m_libspdm_use_hash_algo; + spdm_context->connection_info.algorithm.base_asym_algo = m_libspdm_use_asym_algo; + spdm_context->connection_info.algorithm.dhe_named_group = m_libspdm_use_dhe_algo; + spdm_context->connection_info.algorithm.aead_cipher_suite = m_libspdm_use_aead_algo; + + *session_id = m_session_id; + session_info = &spdm_context->session_info[0]; + libspdm_session_info_init(spdm_context, session_info, *session_id, true); + libspdm_secured_message_set_session_state( + session_info->secured_message_context, LIBSPDM_SESSION_STATE_ESTABLISHED); +} + +static libspdm_return_t send_message( + void *spdm_context, size_t request_size, const void *request, uint64_t timeout) +{ + libspdm_return_t status; + uint32_t session_id; + uint32_t *message_session_id; + spdm_subscribe_event_types_request_t *spdm_message; + bool is_app_message; + void *spdm_request_buffer; + size_t spdm_request_size; + libspdm_session_info_t *session_info; + uint8_t request_buffer[0x1000]; + + /* Workaround request being const. */ + libspdm_copy_mem(request_buffer, sizeof(request_buffer), request, request_size); + + session_id = m_session_id; + session_info = libspdm_get_session_info_via_session_id(spdm_context, session_id); + LIBSPDM_ASSERT(session_info != NULL); + + ((libspdm_secured_message_context_t *)(session_info->secured_message_context))-> + application_secret.request_data_sequence_number--; + + spdm_request_buffer = m_spdm_request_buffer; + spdm_request_size = sizeof(m_spdm_request_buffer); + + status = libspdm_transport_test_decode_message(spdm_context, &message_session_id, + &is_app_message, true, + request_size, request_buffer, + &spdm_request_size, &spdm_request_buffer); + + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + assert_int_equal(sizeof(spdm_subscribe_event_types_request_t) + test_params.subscribe_list_len, + spdm_request_size); + + spdm_message = spdm_request_buffer; + + assert_int_equal(spdm_message->header.spdm_version, SPDM_MESSAGE_VERSION_13); + assert_int_equal(spdm_message->header.request_response_code, SPDM_SUBSCRIBE_EVENT_TYPES); + assert_int_equal(spdm_message->header.param1, test_params.subscribe_event_group_count); + assert_int_equal(spdm_message->header.param2, 0); + assert_int_equal(spdm_message->subscribe_list_len, test_params.subscribe_list_len); + + assert_memory_equal(spdm_message + 1, test_params.subscribe_list, + spdm_message->subscribe_list_len); + + return LIBSPDM_STATUS_SUCCESS; +} + +static libspdm_return_t receive_message( + void *spdm_context, size_t *response_size, void **response, uint64_t timeout) +{ + spdm_subscribe_event_types_ack_response_t *spdm_response; + size_t spdm_response_size; + size_t transport_header_size; + uint32_t session_id; + libspdm_session_info_t *session_info; + uint8_t *scratch_buffer; + size_t scratch_buffer_size; + + transport_header_size = LIBSPDM_TEST_TRANSPORT_HEADER_SIZE; + spdm_response = (void *)((uint8_t *)*response + transport_header_size); + + session_id = m_session_id; + session_info = libspdm_get_session_info_via_session_id(spdm_context, session_id); + LIBSPDM_ASSERT((session_info != NULL)); + + transport_header_size = LIBSPDM_TEST_TRANSPORT_HEADER_SIZE; + spdm_response = (void *)((uint8_t *)*response + transport_header_size); + + spdm_response_size = sizeof(spdm_subscribe_event_types_ack_response_t); + libspdm_zero_mem(spdm_response, spdm_response_size); + + spdm_response->header.spdm_version = SPDM_MESSAGE_VERSION_13; + spdm_response->header.request_response_code = SPDM_SUBSCRIBE_EVENT_TYPES_ACK; + spdm_response->header.param1 = 0; + spdm_response->header.param2 = 0; + + /* For secure message, message is in sender buffer, we need copy it to scratch buffer. + * transport_message is always in sender buffer. */ + libspdm_get_scratch_buffer(spdm_context, (void **)&scratch_buffer, &scratch_buffer_size); + libspdm_copy_mem(scratch_buffer + transport_header_size, + scratch_buffer_size - transport_header_size, + spdm_response, spdm_response_size); + + spdm_response = (void *)(scratch_buffer + transport_header_size); + + libspdm_transport_test_encode_message(spdm_context, &session_id, + false, false, spdm_response_size, + spdm_response, response_size, response); + + /* Workaround: Use single context to encode message and then decode message. */ + ((libspdm_secured_message_context_t *)(session_info->secured_message_context))-> + application_secret.response_data_sequence_number--; + + return LIBSPDM_STATUS_SUCCESS; +} + +/** + * Test 1: Successful response to subscribe event types that clears all subscriptions. + * Expected Behavior: Returns LIBSPDM_STATUS_SUCCESS. + **/ +static void libspdm_test_requester_subscribe_event_types_case1(void **state) +{ + libspdm_return_t status; + libspdm_test_context_t *spdm_test_context; + libspdm_context_t *spdm_context; + uint32_t session_id; + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 0x1; + + set_standard_state(spdm_context, &session_id); + test_params.subscribe_event_group_count = 0; + test_params.subscribe_list_len = 0; + + status = libspdm_subscribe_event_types(spdm_context, session_id, + test_params.subscribe_event_group_count, + test_params.subscribe_list_len, NULL); + + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); +} + +/** + * Test 2: Successful response to subscribe event types that includes one event group and two event + * types. + * Expected Behavior: Returns LIBSPDM_STATUS_SUCCESS. + **/ +static void libspdm_test_requester_subscribe_event_types_case2(void **state) +{ + libspdm_return_t status; + libspdm_test_context_t *spdm_test_context; + libspdm_context_t *spdm_context; + uint32_t session_id; + uint8_t event_group_size; + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 0x2; + + set_standard_state(spdm_context, &session_id); + generate_dmtf_event_group(test_params.subscribe_list, &event_group_size, 0, + true, true, false, false); + test_params.subscribe_event_group_count = 1; + test_params.subscribe_list_len = event_group_size; + + status = libspdm_subscribe_event_types(spdm_context, session_id, + test_params.subscribe_event_group_count, + test_params.subscribe_list_len, + test_params.subscribe_list); + + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); +} + +/** + * Test 3: Successful response to subscribe event types that includes one event group and all event + * types using the AllEventTypes attribute. + * Expected Behavior: Returns LIBSPDM_STATUS_SUCCESS. + **/ +static void libspdm_test_requester_subscribe_event_types_case3(void **state) +{ + libspdm_return_t status; + libspdm_test_context_t *spdm_test_context; + libspdm_context_t *spdm_context; + uint32_t session_id; + uint8_t event_group_size; + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 0x3; + + set_standard_state(spdm_context, &session_id); + generate_dmtf_event_group(test_params.subscribe_list, &event_group_size, + SPDM_SUBSCRIBE_EVENT_TYPES_REQUEST_ATTRIBUTE_ALL, + false, false, false, false); + test_params.subscribe_event_group_count = 1; + test_params.subscribe_list_len = event_group_size; + + status = libspdm_subscribe_event_types(spdm_context, session_id, + test_params.subscribe_event_group_count, + test_params.subscribe_list_len, + test_params.subscribe_list); + + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); +} + +int libspdm_requester_subscribe_event_types_test_main(void) +{ + libspdm_test_context_t test_context = { + LIBSPDM_TEST_CONTEXT_VERSION, + true, + send_message, + receive_message, + }; + + const struct CMUnitTest spdm_requester_get_event_types_tests[] = { + cmocka_unit_test(libspdm_test_requester_subscribe_event_types_case1), + cmocka_unit_test(libspdm_test_requester_subscribe_event_types_case2), + cmocka_unit_test(libspdm_test_requester_subscribe_event_types_case3) + }; + + libspdm_setup_test_context(&test_context); + + return cmocka_run_group_tests(spdm_requester_get_event_types_tests, + libspdm_unit_test_group_setup, + libspdm_unit_test_group_teardown); +} + +#endif /* LIBSPDM_EVENT_RECIPIENT_SUPPORT */ diff --git a/unit_test/test_spdm_requester/test_spdm_requester.c b/unit_test/test_spdm_requester/test_spdm_requester.c index 257f5039b50..dc566b59755 100644 --- a/unit_test/test_spdm_requester/test_spdm_requester.c +++ b/unit_test/test_spdm_requester/test_spdm_requester.c @@ -75,6 +75,8 @@ int libspdm_requester_chunk_send_test_main(void); #if LIBSPDM_EVENT_RECIPIENT_SUPPORT int libspdm_requester_get_event_types_test_main(void); int libspdm_requester_get_event_types_error_test_main(void); +int libspdm_requester_subscribe_event_types_test_main(void); +int libspdm_requester_subscribe_event_types_error_test_main(void); #endif /* LIBSPDM_EVENT_RECIPIENT_SUPPORT */ #if LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES @@ -230,6 +232,12 @@ int main(void) if (libspdm_requester_get_event_types_error_test_main() != 0) { return_value = 1; } + if (libspdm_requester_subscribe_event_types_test_main() != 0) { + return_value = 1; + } + if (libspdm_requester_subscribe_event_types_error_test_main() != 0) { + return_value = 1; + } #endif /* LIBSPDM_EVENT_RECIPIENT_SUPPORT */ #if LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES diff --git a/unit_test/test_spdm_responder/CMakeLists.txt b/unit_test/test_spdm_responder/CMakeLists.txt index 5a053d12dd1..67205ffb4af 100644 --- a/unit_test/test_spdm_responder/CMakeLists.txt +++ b/unit_test/test_spdm_responder/CMakeLists.txt @@ -40,7 +40,9 @@ target_sources(test_spdm_responder encap_challenge.c encap_response.c supported_event_types.c + subscribe_event_types_ack.c error_test/supported_event_types_err.c + error_test/subscribe_event_types_ack_err.c error_test/vendor_response_err.c set_certificate_rsp.c csr.c @@ -50,6 +52,7 @@ target_sources(test_spdm_responder ${LIBSPDM_DIR}/unit_test/spdm_unit_test_common/common.c ${LIBSPDM_DIR}/unit_test/spdm_unit_test_common/algo.c ${LIBSPDM_DIR}/unit_test/spdm_unit_test_common/support.c + ${LIBSPDM_DIR}/unit_test/spdm_unit_test_common/event_support.c ) diff --git a/unit_test/test_spdm_responder/error_test/subscribe_event_types_ack_err.c b/unit_test/test_spdm_responder/error_test/subscribe_event_types_ack_err.c new file mode 100644 index 00000000000..27085f64dad --- /dev/null +++ b/unit_test/test_spdm_responder/error_test/subscribe_event_types_ack_err.c @@ -0,0 +1,161 @@ +/** + * 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 "spdm_unit_test.h" +#include "internal/libspdm_responder_lib.h" + +#if LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP + +static void set_standard_state(libspdm_context_t *spdm_context) +{ + libspdm_session_info_t *session_info; + uint32_t session_id; + + spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_13 << + SPDM_VERSION_NUMBER_SHIFT_BIT; + spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_NEGOTIATED; + spdm_context->response_state = LIBSPDM_RESPONSE_STATE_NORMAL; + + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_EVENT_CAP; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ENCRYPT_CAP; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MAC_CAP; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP; + + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ENCRYPT_CAP; + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MAC_CAP; + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP; + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_EVENT_CAP; + + spdm_context->connection_info.algorithm.base_hash_algo = m_libspdm_use_hash_algo; + spdm_context->connection_info.algorithm.base_asym_algo = m_libspdm_use_asym_algo; + spdm_context->connection_info.algorithm.dhe_named_group = m_libspdm_use_dhe_algo; + spdm_context->connection_info.algorithm.aead_cipher_suite = m_libspdm_use_aead_algo; + + session_id = 0xFFFFFFFF; + spdm_context->latest_session_id = session_id; + spdm_context->last_spdm_request_session_id_valid = true; + spdm_context->last_spdm_request_session_id = session_id; + session_info = &spdm_context->session_info[0]; + libspdm_session_info_init(spdm_context, session_info, session_id, true); + libspdm_secured_message_set_session_state( + session_info->secured_message_context, + LIBSPDM_SESSION_STATE_ESTABLISHED); +} + +/** + * Test 1: Responder does not support event mechanism. + * Expected Behavior: Returns SPDM_ERROR_CODE_UNSUPPORTED_REQUEST. + **/ +static void libspdm_test_responder_subscribe_event_types_ack_err_case1(void **state) +{ + libspdm_return_t status; + libspdm_test_context_t *spdm_test_context; + libspdm_context_t *spdm_context; + spdm_subscribe_event_types_request_t spdm_request; + size_t spdm_request_size; + uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE]; + size_t response_size = sizeof(response); + spdm_subscribe_event_types_ack_response_t *spdm_response; + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 1; + + set_standard_state(spdm_context); + + /* Responder does not support event mechanism. */ + spdm_context->local_context.capability.flags &= ~SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_EVENT_CAP; + + spdm_request.header.spdm_version = SPDM_MESSAGE_VERSION_13; + spdm_request.header.request_response_code = SPDM_SUBSCRIBE_EVENT_TYPES; + spdm_request.header.param1 = 0; + spdm_request.header.param2 = 0; + + spdm_request_size = sizeof(spdm_message_header_t); + + status = libspdm_get_response_subscribe_event_types_ack(spdm_context, + spdm_request_size, &spdm_request, + &response_size, response); + spdm_response = (spdm_subscribe_event_types_ack_response_t *)response; + + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + assert_int_equal(spdm_response->header.spdm_version, SPDM_MESSAGE_VERSION_13); + assert_int_equal(spdm_response->header.request_response_code, SPDM_ERROR); + assert_int_equal(spdm_response->header.param1, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST); + assert_int_equal(spdm_response->header.param2, SPDM_SUBSCRIBE_EVENT_TYPES); +} + +/** + * Test 2: Negotiated version is less than 1.3. + * Expected Behavior: Returns SPDM_ERROR_CODE_UNSUPPORTED_REQUEST. + **/ +static void libspdm_test_responder_subscribe_event_types_ack_err_case2(void **state) +{ + libspdm_return_t status; + libspdm_test_context_t *spdm_test_context; + libspdm_context_t *spdm_context; + spdm_subscribe_event_types_request_t spdm_request; + size_t spdm_request_size; + uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE]; + size_t response_size = sizeof(response); + spdm_subscribe_event_types_ack_response_t *spdm_response; + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 1; + + set_standard_state(spdm_context); + spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 << + SPDM_VERSION_NUMBER_SHIFT_BIT; + + /* Unsupported version for subscribe event types. */ + spdm_request.header.spdm_version = SPDM_MESSAGE_VERSION_12; + spdm_request.header.request_response_code = SPDM_SUBSCRIBE_EVENT_TYPES; + spdm_request.header.param1 = 0; + spdm_request.header.param2 = 0; + + spdm_request_size = sizeof(spdm_message_header_t); + + status = libspdm_get_response_subscribe_event_types_ack(spdm_context, + spdm_request_size, &spdm_request, + &response_size, response); + spdm_response = (spdm_subscribe_event_types_ack_response_t *)response; + + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + assert_int_equal(spdm_response->header.spdm_version, SPDM_MESSAGE_VERSION_12); + assert_int_equal(spdm_response->header.request_response_code, SPDM_ERROR); + assert_int_equal(spdm_response->header.param1, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST); + assert_int_equal(spdm_response->header.param2, SPDM_SUBSCRIBE_EVENT_TYPES); +} + +int libspdm_responder_subscribe_event_types_ack_error_test_main(void) +{ + libspdm_test_context_t m_test_context = { + LIBSPDM_TEST_CONTEXT_VERSION, + false, + }; + + const struct CMUnitTest spdm_responder_supported_event_types_err_tests[] = { + cmocka_unit_test(libspdm_test_responder_subscribe_event_types_ack_err_case1), + cmocka_unit_test(libspdm_test_responder_subscribe_event_types_ack_err_case2) + }; + + libspdm_setup_test_context(&m_test_context); + + return cmocka_run_group_tests(spdm_responder_supported_event_types_err_tests, + libspdm_unit_test_group_setup, + libspdm_unit_test_group_teardown); +} + +#endif /* LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP */ diff --git a/unit_test/test_spdm_responder/error_test/supported_event_types_err.c b/unit_test/test_spdm_responder/error_test/supported_event_types_err.c index 39eb9618b6c..2b5276aa74e 100644 --- a/unit_test/test_spdm_responder/error_test/supported_event_types_err.c +++ b/unit_test/test_spdm_responder/error_test/supported_event_types_err.c @@ -9,9 +9,6 @@ #if LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP -extern uint32_t g_supported_event_groups_list_len; -extern uint8_t g_event_group_count; - static void set_standard_state(libspdm_context_t *spdm_context) { libspdm_session_info_t *session_info; diff --git a/unit_test/test_spdm_responder/subscribe_event_types_ack.c b/unit_test/test_spdm_responder/subscribe_event_types_ack.c new file mode 100644 index 00000000000..ed2da1c87ac --- /dev/null +++ b/unit_test/test_spdm_responder/subscribe_event_types_ack.c @@ -0,0 +1,165 @@ +/** + * 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 "spdm_unit_test.h" +#include "internal/libspdm_responder_lib.h" + +#if LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP + +static void set_standard_state(libspdm_context_t *spdm_context) +{ + libspdm_session_info_t *session_info; + uint32_t session_id; + + spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_13 << + SPDM_VERSION_NUMBER_SHIFT_BIT; + spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_NEGOTIATED; + spdm_context->response_state = LIBSPDM_RESPONSE_STATE_NORMAL; + + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_EVENT_CAP; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ENCRYPT_CAP; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MAC_CAP; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP; + + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ENCRYPT_CAP; + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MAC_CAP; + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP; + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_EVENT_CAP; + + spdm_context->connection_info.algorithm.base_hash_algo = m_libspdm_use_hash_algo; + spdm_context->connection_info.algorithm.base_asym_algo = m_libspdm_use_asym_algo; + spdm_context->connection_info.algorithm.dhe_named_group = m_libspdm_use_dhe_algo; + spdm_context->connection_info.algorithm.aead_cipher_suite = m_libspdm_use_aead_algo; + + session_id = 0xFFFFFFFF; + spdm_context->latest_session_id = session_id; + spdm_context->last_spdm_request_session_id_valid = true; + spdm_context->last_spdm_request_session_id = session_id; + session_info = &spdm_context->session_info[0]; + libspdm_session_info_init(spdm_context, session_info, session_id, true); + libspdm_secured_message_set_session_state( + session_info->secured_message_context, + LIBSPDM_SESSION_STATE_ESTABLISHED); +} + +/** + * Test 1: Successful response to subscribe event types that clears all events. + * Expected Behavior: Returns LIBSPDM_STATUS_SUCCESS with the expected values. + **/ +static void libspdm_test_responder_subscribe_event_types_ack_case1(void **state) +{ + libspdm_return_t status; + libspdm_test_context_t *spdm_test_context; + libspdm_context_t *spdm_context; + spdm_subscribe_event_types_request_t spdm_request; + size_t spdm_request_size; + uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE]; + size_t response_size = sizeof(response); + spdm_subscribe_event_types_ack_response_t *spdm_response; + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 1; + + set_standard_state(spdm_context); + + spdm_request.header.spdm_version = SPDM_MESSAGE_VERSION_13; + spdm_request.header.request_response_code = SPDM_SUBSCRIBE_EVENT_TYPES; + spdm_request.header.param1 = 0; + spdm_request.header.param2 = 0; + + spdm_request_size = sizeof(spdm_message_header_t); + + status = libspdm_get_response_subscribe_event_types_ack(spdm_context, + spdm_request_size, &spdm_request, + &response_size, response); + spdm_response = (spdm_subscribe_event_types_ack_response_t *)response; + + assert_int_equal(response_size, sizeof(spdm_subscribe_event_types_ack_response_t)); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + assert_int_equal(spdm_response->header.spdm_version, SPDM_MESSAGE_VERSION_13); + assert_int_equal(spdm_response->header.request_response_code, SPDM_SUBSCRIBE_EVENT_TYPES_ACK); + assert_int_equal(spdm_response->header.param1, 0); + assert_int_equal(spdm_response->header.param2, 0); +} + +/** + * Test 2: Successful response to subscribe event types that subscribes to two events. + * Expected Behavior: Returns LIBSPDM_STATUS_SUCCESS with the expected values. + **/ +static void libspdm_test_responder_subscribe_event_types_ack_case2(void **state) +{ + libspdm_return_t status; + libspdm_test_context_t *spdm_test_context; + libspdm_context_t *spdm_context; + spdm_subscribe_event_types_request_t *spdm_request; + uint8_t request[LIBSPDM_MAX_SPDM_MSG_SIZE]; + size_t spdm_request_size; + uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE]; + size_t response_size = sizeof(response); + spdm_subscribe_event_types_ack_response_t *spdm_response; + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 2; + + set_standard_state(spdm_context); + + spdm_request = (spdm_subscribe_event_types_request_t *)request; + + spdm_request->header.spdm_version = SPDM_MESSAGE_VERSION_13; + spdm_request->header.request_response_code = SPDM_SUBSCRIBE_EVENT_TYPES; + spdm_request->header.param1 = 1; + spdm_request->header.param2 = 0; + spdm_request->subscribe_list_len = 0; + + generate_dmtf_event_group(spdm_request + 1, (uint8_t *)&spdm_request->subscribe_list_len, + 0, true, true, false, false); + + spdm_request_size = sizeof(spdm_subscribe_event_types_request_t) + + spdm_request->subscribe_list_len; + + status = libspdm_get_response_subscribe_event_types_ack(spdm_context, + spdm_request_size, spdm_request, + &response_size, response); + spdm_response = (spdm_subscribe_event_types_ack_response_t *)response; + + assert_int_equal(response_size, sizeof(spdm_subscribe_event_types_ack_response_t)); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + assert_int_equal(spdm_response->header.spdm_version, SPDM_MESSAGE_VERSION_13); + assert_int_equal(spdm_response->header.request_response_code, SPDM_SUBSCRIBE_EVENT_TYPES_ACK); + assert_int_equal(spdm_response->header.param1, 0); + assert_int_equal(spdm_response->header.param2, 0); +} + +int libspdm_responder_subscribe_event_types_ack_test_main(void) +{ + libspdm_test_context_t test_context = { + LIBSPDM_TEST_CONTEXT_VERSION, + false, + }; + + const struct CMUnitTest spdm_responder_subscribe_event_types_ack_tests[] = { + cmocka_unit_test(libspdm_test_responder_subscribe_event_types_ack_case1), + cmocka_unit_test(libspdm_test_responder_subscribe_event_types_ack_case2) + }; + + libspdm_setup_test_context(&test_context); + + return cmocka_run_group_tests(spdm_responder_subscribe_event_types_ack_tests, + libspdm_unit_test_group_setup, + libspdm_unit_test_group_teardown); +} + +#endif /* LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP */ diff --git a/unit_test/test_spdm_responder/test_spdm_responder.c b/unit_test/test_spdm_responder/test_spdm_responder.c index 40643f0112f..3538bf74786 100644 --- a/unit_test/test_spdm_responder/test_spdm_responder.c +++ b/unit_test/test_spdm_responder/test_spdm_responder.c @@ -79,6 +79,8 @@ int libspdm_responder_chunk_send_ack_test_main(void); #if LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP int libspdm_responder_supported_event_types_test_main(void); int libspdm_responder_supported_event_types_error_test_main(void); +int libspdm_responder_subscribe_event_types_ack_test_main(void); +int libspdm_responder_subscribe_event_types_ack_error_test_main(void); #endif /* LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP */ #if LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES @@ -232,6 +234,12 @@ int main(void) if (libspdm_responder_supported_event_types_error_test_main() != 0) { return_value = 1; } + if (libspdm_responder_subscribe_event_types_ack_test_main() != 0) { + return_value = 1; + } + if (libspdm_responder_subscribe_event_types_ack_error_test_main() != 0) { + return_value = 1; + } #endif /* LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP */ #if LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES