diff --git a/include/industry_standard/spdm.h b/include/industry_standard/spdm.h index 349143e5cc9..9e41c52f0d8 100644 --- a/include/industry_standard/spdm.h +++ b/include/industry_standard/spdm.h @@ -1,6 +1,6 @@ /** * Copyright Notice: - * Copyright 2021-2022 DMTF. All rights reserved. + * Copyright 2021-2024 DMTF. All rights reserved. * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md **/ @@ -54,6 +54,9 @@ #define SPDM_CHUNK_SEND_ACK 0x05 #define SPDM_CHUNK_RESPONSE 0x06 +/* SPDM response code (1.3) */ +#define SPDM_SUPPORTED_EVENT_TYPES 0x62 + /* SPDM request code (1.0) */ #define SPDM_GET_DIGESTS 0x81 #define SPDM_GET_CERTIFICATE 0x82 @@ -82,6 +85,9 @@ #define SPDM_CHUNK_SEND 0x85 #define SPDM_CHUNK_GET 0x86 +/* SPDM request code (1.3) */ +#define SPDM_GET_SUPPORTED_EVENT_TYPES 0xE2 + /* SPDM message header*/ typedef struct { uint8_t spdm_version; @@ -1151,6 +1157,20 @@ typedef struct { #define SPDM_CHUNK_GET_RESPONSE_ATTRIBUTE_LAST_CHUNK (1 << 0) +typedef struct { + spdm_message_header_t header; + /* param1 == RSVD + * param2 == RSVD */ +} spdm_get_supported_event_types_request_t; + +typedef struct { + spdm_message_header_t header; + /* param1 == EventGroupCount + * param2 == RSVD */ + uint32_t supported_event_groups_list_len; + /* uint8_t supported_event_groups_list[supported_event_groups_list_len] */ +} spdm_supported_event_types_response_t; + #pragma pack() #define SPDM_VERSION_1_1_BIN_CONCAT_LABEL "spdm1.1 " @@ -1197,4 +1217,10 @@ typedef struct { #define SPDM_OID_DMTF_SPDM_EXTENSION \ { /*0x06, 0x0A,*/ 0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1C, 0x82, 0x12, 0x06 } +/* DMTF Event Type IDs */ +#define SPDM_DMTF_EVENT_TYPE_EVENT_LOST 1 +#define SPDM_DMTF_EVENT_TYPE_MEASUREMENT_CHANGED 2 +#define SPDM_DMTF_EVENT_TYPE_MEASUREMENT_PRE_UPDATE 3 +#define SPDM_DMTF_EVENT_TYPE_CERTIFICATE_CHANGED 4 + #endif /* SPDM_H */ diff --git a/library/spdm_common_lib/libspdm_com_support.c b/library/spdm_common_lib/libspdm_com_support.c index 48abc3c32c3..049c0e612f5 100644 --- a/library/spdm_common_lib/libspdm_com_support.c +++ b/library/spdm_common_lib/libspdm_com_support.c @@ -42,6 +42,8 @@ const char *libspdm_get_code_str(uint8_t request_code) { SPDM_SET_CERTIFICATE_RSP, "SPDM_SET_CERTIFICATE_RSP" }, { SPDM_CHUNK_SEND_ACK, "SPDM_CHUNK_SEND_ACK" }, { SPDM_CHUNK_RESPONSE, "SPDM_CHUNK_RESPONSE" }, + /* SPDM response code (1.3 )*/ + { SPDM_SUPPORTED_EVENT_TYPES, "SPDM_SUPPORTED_EVENT_TYPES" }, /* SPDM request code (1.0) */ { SPDM_GET_DIGESTS, "SPDM_GET_DIGESTS" }, { SPDM_GET_CERTIFICATE, "SPDM_GET_CERTIFICATE" }, @@ -66,7 +68,8 @@ const char *libspdm_get_code_str(uint8_t request_code) { SPDM_GET_CSR, "SPDM_GET_CSR" }, { SPDM_SET_CERTIFICATE, "SPDM_SET_CERTIFICATE" }, { SPDM_CHUNK_SEND, "SPDM_CHUNK_SEND" }, - { SPDM_CHUNK_GET, "SPDM_CHUNK_GET" } + { SPDM_CHUNK_GET, "SPDM_CHUNK_GET" }, + { SPDM_GET_SUPPORTED_EVENT_TYPES, "SPDM_GET_SUPPORTED_EVENT_TYPES" } }; for (index = 0; index < LIBSPDM_ARRAY_SIZE(code_str_struct); index++) { diff --git a/library/spdm_requester_lib/CMakeLists.txt b/library/spdm_requester_lib/CMakeLists.txt index e055e74e52a..f25ef1ec886 100644 --- a/library/spdm_requester_lib/CMakeLists.txt +++ b/library/spdm_requester_lib/CMakeLists.txt @@ -17,6 +17,7 @@ SET(src_spdm_requester_lib libspdm_req_get_capabilities.c libspdm_req_get_certificate.c libspdm_req_get_digests.c + libspdm_req_get_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_get_event_types.c b/library/spdm_requester_lib/libspdm_req_get_event_types.c new file mode 100644 index 00000000000..bacaa0f81e0 --- /dev/null +++ b/library/spdm_requester_lib/libspdm_req_get_event_types.c @@ -0,0 +1,172 @@ +/** + * 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 libspdm_try_get_event_types(libspdm_context_t *spdm_context, + uint32_t session_id, + uint8_t *event_group_count, + uint32_t *supported_event_groups_list_len, + void *supported_event_groups_list) +{ + libspdm_return_t status; + libspdm_session_info_t *session_info; + spdm_get_supported_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]=- */ + LIBSPDM_ASSERT(event_group_count != NULL); + LIBSPDM_ASSERT(supported_event_groups_list_len != NULL); + LIBSPDM_ASSERT(supported_event_groups_list != NULL); + + 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; + + spdm_request->header.spdm_version = libspdm_get_connection_version(spdm_context); + spdm_request->header.request_response_code = SPDM_GET_SUPPORTED_EVENT_TYPES; + spdm_request->header.param1 = 0; + spdm_request->header.param2 = 0; + spdm_request_size = sizeof(spdm_heartbeat_request_t); + + /* -=[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; + + libspdm_zero_mem(spdm_response, spdm_response_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_message_header_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_GET_SUPPORTED_EVENT_TYPES, SPDM_SUPPORTED_EVENT_TYPES); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + goto receive_done; + } + } else if (spdm_response->header.request_response_code != SPDM_SUPPORTED_EVENT_TYPES) { + status = LIBSPDM_STATUS_INVALID_MSG_FIELD; + goto receive_done; + } + if (spdm_response->header.param1 == 0) { + status = LIBSPDM_STATUS_INVALID_MSG_FIELD; + goto receive_done; + } + if (spdm_response->supported_event_groups_list_len == 0) { + status = LIBSPDM_STATUS_INVALID_MSG_FIELD; + goto receive_done; + } else if (spdm_response->supported_event_groups_list_len > *supported_event_groups_list_len) { + status = LIBSPDM_STATUS_BUFFER_TOO_SMALL; + goto receive_done; + } + + /* -=[Process Response Phase]=- */ + *event_group_count = spdm_response->header.param1; + libspdm_copy_mem(supported_event_groups_list, *supported_event_groups_list_len, + spdm_response + 1, spdm_response->supported_event_groups_list_len); + *supported_event_groups_list_len = spdm_response->supported_event_groups_list_len; + +receive_done: + libspdm_release_receiver_buffer(spdm_context); + + return status; +} + +libspdm_return_t libspdm_get_event_types(void *spdm_context, + uint32_t session_id, + uint8_t *event_group_count, + uint32_t *supported_event_groups_list_len, + void *supported_event_groups_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 = libspdm_try_get_event_types(context, + session_id, + event_group_count, + supported_event_groups_list_len, + supported_event_groups_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/unit_test/test_spdm_requester/CMakeLists.txt b/unit_test/test_spdm_requester/CMakeLists.txt index fd3e92ae683..07653ef23b9 100644 --- a/unit_test/test_spdm_requester/CMakeLists.txt +++ b/unit_test/test_spdm_requester/CMakeLists.txt @@ -24,6 +24,7 @@ SET(src_test_spdm_requester get_digests.c get_certificate.c challenge.c + get_event_types.c get_measurements.c key_exchange.c finish.c @@ -47,6 +48,7 @@ SET(src_test_spdm_requester error_test/get_digests_err.c error_test/key_exchange_err.c error_test/get_measurements_err.c + error_test/get_event_types_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 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 new file mode 100644 index 00000000000..0ba35042060 --- /dev/null +++ b/unit_test/test_spdm_requester/error_test/get_event_types_err.c @@ -0,0 +1,292 @@ +/** + * 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 uint8_t m_supported_event_groups_list[0x1000]; +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; + + 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_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->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 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) +{ + libspdm_return_t status; + uint32_t session_id; + uint32_t *message_session_id; + spdm_get_supported_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_get_supported_event_types_request_t), 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_GET_SUPPORTED_EVENT_TYPES); + assert_int_equal(spdm_message->header.param1, 0); + assert_int_equal(spdm_message->header.param2, 0); + + return LIBSPDM_STATUS_SUCCESS; +} + +static libspdm_return_t receive_message( + void *spdm_context, size_t *response_size, void **response, uint64_t timeout) +{ + spdm_supported_event_types_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; + uint8_t event_group_total_bytes; + libspdm_test_context_t *spdm_test_context; + + spdm_test_context = libspdm_get_test_context(); + switch (spdm_test_context->case_id) { + case 1: { + 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)); + + spdm_response->header.spdm_version = SPDM_MESSAGE_VERSION_13; + spdm_response->header.request_response_code = SPDM_SUPPORTED_EVENT_TYPES; + /* Illegal EventGroupCount value. */ + spdm_response->header.param1 = 0; + spdm_response->header.param2 = 0; + + generate_dmtf_event_group(spdm_response + 1, &event_group_total_bytes, + true, true, true, true); + spdm_response->supported_event_groups_list_len = event_group_total_bytes; + + spdm_response_size = sizeof(spdm_supported_event_types_response_t) + + event_group_total_bytes; + + /* 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; + default: + return LIBSPDM_STATUS_RECEIVE_FAIL; + } +} + +/** + * Test 1: Responder returns a value of 0 for EventGroupCount (param1). + * Expected Behavior: Returns with status LIBSPDM_STATUS_INVALID_MSG_FIELD. + **/ +static void libspdm_test_requester_get_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; + uint8_t event_group_count; + uint32_t supported_event_groups_list_len = sizeof(m_supported_event_groups_list); + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 1; + + set_standard_state(spdm_context, &session_id); + + status = libspdm_get_event_types(spdm_context, session_id, &event_group_count, + &supported_event_groups_list_len, + (void *)&m_supported_event_groups_list); + + assert_int_equal(status, LIBSPDM_STATUS_INVALID_MSG_FIELD); +} + +static libspdm_test_context_t m_test_context = { + LIBSPDM_TEST_CONTEXT_VERSION, + true, + send_message, + receive_message, +}; + +int libspdm_requester_get_event_types_error_test_main(void) +{ + const struct CMUnitTest spdm_requester_get_event_types_tests[] = { + cmocka_unit_test(libspdm_test_requester_get_event_types_err_case1) + }; + + libspdm_setup_test_context(&m_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 new file mode 100644 index 00000000000..689d3af2638 --- /dev/null +++ b/unit_test/test_spdm_requester/get_event_types.c @@ -0,0 +1,292 @@ +/** + * 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 uint8_t m_supported_event_groups_list[0x1000]; +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; + + 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_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->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 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) +{ + libspdm_return_t status; + uint32_t session_id; + uint32_t *message_session_id; + spdm_get_supported_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_get_supported_event_types_request_t), 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_GET_SUPPORTED_EVENT_TYPES); + assert_int_equal(spdm_message->header.param1, 0); + assert_int_equal(spdm_message->header.param2, 0); + + return LIBSPDM_STATUS_SUCCESS; +} + +static libspdm_return_t receive_message( + void *spdm_context, size_t *response_size, void **response, uint64_t timeout) +{ + spdm_supported_event_types_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; + uint8_t event_group_total_bytes; + libspdm_test_context_t *spdm_test_context; + + spdm_test_context = libspdm_get_test_context(); + switch (spdm_test_context->case_id) { + case 1: { + 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)); + + spdm_response->header.spdm_version = SPDM_MESSAGE_VERSION_13; + spdm_response->header.request_response_code = SPDM_SUPPORTED_EVENT_TYPES; + spdm_response->header.param1 = 1; + spdm_response->header.param2 = 0; + + generate_dmtf_event_group(spdm_response + 1, &event_group_total_bytes, + true, true, true, true); + spdm_response->supported_event_groups_list_len = event_group_total_bytes; + + spdm_response_size = sizeof(spdm_supported_event_types_response_t) + + event_group_total_bytes; + + /* 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; + default: + return LIBSPDM_STATUS_RECEIVE_FAIL; + } +} + +/** + * Test 1: Successful response to get supported event types. + * Expected Behavior: Returns LIBSPDM_STATUS_SUCCESS with the expected values. + **/ +static void libspdm_test_requester_get_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; + uint8_t event_group_count; + uint32_t supported_event_groups_list_len = sizeof(m_supported_event_groups_list); + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 1; + + set_standard_state(spdm_context, &session_id); + + status = libspdm_get_event_types(spdm_context, session_id, &event_group_count, + &supported_event_groups_list_len, + (void *)&m_supported_event_groups_list); + + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + assert_int_equal(event_group_count, 1); +} + +static libspdm_test_context_t m_test_context = { + LIBSPDM_TEST_CONTEXT_VERSION, + true, + send_message, + receive_message, +}; + +int libspdm_requester_get_event_types_test_main(void) +{ + const struct CMUnitTest spdm_requester_get_event_types_tests[] = { + cmocka_unit_test(libspdm_test_requester_get_event_types_case1) + }; + + libspdm_setup_test_context(&m_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 1122481f38a..cf2b61f2fde 100644 --- a/unit_test/test_spdm_requester/test_spdm_requester.c +++ b/unit_test/test_spdm_requester/test_spdm_requester.c @@ -68,6 +68,11 @@ int libspdm_requester_chunk_get_test_main(void); int libspdm_requester_chunk_send_test_main(void); #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */ +#if LIBSPDM_EVENT_RECIPIENT_SUPPORT +int libspdm_requester_get_event_types_test_main(void); +int libspdm_requester_get_event_types_error_test_main(void); +#endif /* LIBSPDM_EVENT_RECIPIENT_SUPPORT */ + int main(void) { int return_value = 0; @@ -203,5 +208,14 @@ int main(void) } #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */ + #if LIBSPDM_EVENT_RECIPIENT_SUPPORT + if (libspdm_requester_get_event_types_test_main() != 0) { + return_value = 1; + } + if (libspdm_requester_get_event_types_error_test_main() != 0) { + return_value = 1; + } + #endif /* LIBSPDM_EVENT_RECIPIENT_SUPPORT */ + return return_value; }