diff --git a/library/spdm_requester_lib/libspdm_req_psk_finish.c b/library/spdm_requester_lib/libspdm_req_psk_finish.c index 84521916e2e..27aa4b247ed 100644 --- a/library/spdm_requester_lib/libspdm_req_psk_finish.c +++ b/library/spdm_requester_lib/libspdm_req_psk_finish.c @@ -1,6 +1,6 @@ /** * Copyright Notice: - * Copyright 2021-2025 DMTF. All rights reserved. + * Copyright 2021-2026 DMTF. All rights reserved. * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md **/ @@ -293,6 +293,7 @@ static libspdm_return_t libspdm_try_send_receive_psk_finish( status = LIBSPDM_STATUS_INVALID_MSG_FIELD; goto receive_done; } + /* this message can only be in secured session * thus don't need to consider transport layer padding, just check its exact size */ if (spdm_response_size != sizeof(spdm_psk_finish_response_t) + sizeof(uint16_t) + @@ -302,7 +303,7 @@ static libspdm_return_t libspdm_try_send_receive_psk_finish( } if ((responder_opaque_data != NULL) && (responder_opaque_data_size != NULL)) { - if (opaque_data_size >= *responder_opaque_data_size) { + if (opaque_data_size > *responder_opaque_data_size) { status = LIBSPDM_STATUS_BUFFER_TOO_SMALL; goto receive_done; } @@ -325,7 +326,7 @@ static libspdm_return_t libspdm_try_send_receive_psk_finish( } opaque_data_entry_size = 0; } - spdm_response_size = sizeof(spdm_finish_response_t) + opaque_data_entry_size; + spdm_response_size = sizeof(spdm_psk_finish_response_t) + opaque_data_entry_size; status = libspdm_append_message_f(spdm_context, session_info, true, spdm_response, spdm_response_size); diff --git a/library/spdm_responder_lib/libspdm_rsp_psk_finish_rsp.c b/library/spdm_responder_lib/libspdm_rsp_psk_finish_rsp.c index e390c61082b..ae56c673d15 100644 --- a/library/spdm_responder_lib/libspdm_rsp_psk_finish_rsp.c +++ b/library/spdm_responder_lib/libspdm_rsp_psk_finish_rsp.c @@ -266,6 +266,12 @@ libspdm_return_t libspdm_get_response_psk_finish(libspdm_context_t *spdm_context SPDM_ERROR_CODE_UNSPECIFIED, 0, response_size, response); } + + if (opaque_data_size > SPDM_MAX_OPAQUE_DATA_SIZE) { + return libspdm_generate_error_response(spdm_context, + SPDM_ERROR_CODE_UNSPECIFIED, 0, + response_size, response); + } } libspdm_write_uint16(ptr, (uint16_t)opaque_data_size); opaque_data_entry_size = sizeof(uint16_t) + opaque_data_size; diff --git a/unit_test/test_spdm_requester/psk_finish.c b/unit_test/test_spdm_requester/psk_finish.c index 5432adec9df..cceca981eab 100644 --- a/unit_test/test_spdm_requester/psk_finish.c +++ b/unit_test/test_spdm_requester/psk_finish.c @@ -123,6 +123,8 @@ static libspdm_return_t send_message( m_libspdm_local_buffer_size += decoded_message_size; } return LIBSPDM_STATUS_SUCCESS; + case 0x12: + return LIBSPDM_STATUS_SUCCESS; default: return LIBSPDM_STATUS_SEND_FAIL; } @@ -921,6 +923,49 @@ static libspdm_return_t receive_message( } return LIBSPDM_STATUS_SUCCESS; + case 0x12: { + spdm_psk_finish_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; + uint16_t opaque_data_size; + uint8_t *ptr; + + session_id = 0xFFFFFFFF; + opaque_data_size = SPDM_MAX_OPAQUE_DATA_SIZE + 1; + spdm_response_size = sizeof(spdm_psk_finish_response_t) + sizeof(uint16_t); + transport_header_size = LIBSPDM_TEST_TRANSPORT_HEADER_SIZE; + spdm_response = (void *)((uint8_t *)*response + transport_header_size); + + spdm_response->header.spdm_version = SPDM_MESSAGE_VERSION_14; + spdm_response->header.request_response_code = SPDM_PSK_FINISH_RSP; + spdm_response->header.param1 = 0; + spdm_response->header.param2 = 0; + ptr = (uint8_t *)spdm_response + sizeof(spdm_psk_finish_response_t); + libspdm_write_uint16(ptr, opaque_data_size); + + 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); + session_info = libspdm_get_session_info_via_session_id(spdm_context, session_id); + if (session_info == NULL) { + return LIBSPDM_STATUS_RECEIVE_FAIL; + } + ((libspdm_secured_message_context_t*)(session_info->secured_message_context)) + ->handshake_secret.response_handshake_sequence_number--; + } + return LIBSPDM_STATUS_SUCCESS; + default: return LIBSPDM_STATUS_RECEIVE_FAIL; } @@ -2414,6 +2459,8 @@ static void req_psk_finish_case17(void **state) 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; + spdm_context->connection_info.algorithm.other_params_support = + SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1; session_id = 0xFFFFFFFF; session_info = &spdm_context->session_info[0]; @@ -2455,6 +2502,84 @@ static void req_psk_finish_case17(void **state) free(data); } +/** + * Test 18: SPDM version 1.4, response opaque length exceeds protocol max. + * Expected behavior: requester returns LIBSPDM_STATUS_INVALID_MSG_FIELD. + **/ +static void req_psk_finish_case18(void **state) +{ + libspdm_return_t status; + libspdm_test_context_t *spdm_test_context; + libspdm_context_t *spdm_context; + uint32_t session_id; + void *data; + size_t data_size; + void *hash; + size_t hash_size; + libspdm_session_info_t *session_info; + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 0x12; + spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_14 << + 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_PSK_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->local_context.capability.flags |= SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PSK_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; + if (!libspdm_read_responder_public_certificate_chain(m_libspdm_use_hash_algo, + m_libspdm_use_asym_algo, &data, + &data_size, &hash, &hash_size)) { + assert(false); + } + libspdm_reset_message_a(spdm_context); + 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; + spdm_context->connection_info.algorithm.other_params_support = + SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1; + + session_id = 0xFFFFFFFF; + session_info = &spdm_context->session_info[0]; + libspdm_session_info_init(spdm_context, session_info, session_id, + SECURED_SPDM_VERSION_11 << SPDM_VERSION_NUMBER_SHIFT_BIT, true); + libspdm_session_info_set_psk_hint(session_info, + LIBSPDM_TEST_PSK_HINT_STRING, + sizeof(LIBSPDM_TEST_PSK_HINT_STRING)); + libspdm_secured_message_set_session_state( + session_info->secured_message_context, + LIBSPDM_SESSION_STATE_HANDSHAKING); + libspdm_set_mem(m_libspdm_dummy_key_buffer, + ((libspdm_secured_message_context_t*)(session_info->secured_message_context)) + ->aead_key_size, (uint8_t)(0xFF)); + libspdm_secured_message_set_response_handshake_encryption_key( + session_info->secured_message_context, m_libspdm_dummy_key_buffer, + ((libspdm_secured_message_context_t*)(session_info->secured_message_context)) + ->aead_key_size); + libspdm_set_mem(m_libspdm_dummy_salt_buffer, + ((libspdm_secured_message_context_t*)(session_info->secured_message_context)) + ->aead_iv_size, (uint8_t)(0xFF)); + libspdm_secured_message_set_response_handshake_salt( + session_info->secured_message_context, m_libspdm_dummy_salt_buffer, + ((libspdm_secured_message_context_t*)(session_info->secured_message_context)) + ->aead_iv_size); + ((libspdm_secured_message_context_t *)(session_info->secured_message_context)) + ->handshake_secret.response_handshake_sequence_number = 0; + ((libspdm_secured_message_context_t *)(session_info->secured_message_context)) + ->handshake_secret.request_handshake_sequence_number = 0; + libspdm_secured_message_set_dummy_finished_key (session_info->secured_message_context); + + status = libspdm_send_receive_psk_finish(spdm_context, session_id); + assert_int_equal(status, LIBSPDM_STATUS_INVALID_MSG_FIELD); + + free(data); +} + int libspdm_req_psk_finish_test(void) { const struct CMUnitTest test_cases[] = { @@ -2492,6 +2617,8 @@ int libspdm_req_psk_finish_test(void) cmocka_unit_test(req_psk_finish_case16), /* SPDM 1.4 with OpaqueData */ cmocka_unit_test(req_psk_finish_case17), + /* SPDM 1.4 response opaque length over protocol max */ + cmocka_unit_test(req_psk_finish_case18), }; libspdm_test_context_t test_context = { diff --git a/unit_test/test_spdm_responder/psk_finish_rsp.c b/unit_test/test_spdm_responder/psk_finish_rsp.c index e8b6a91425a..b5478edde2a 100644 --- a/unit_test/test_spdm_responder/psk_finish_rsp.c +++ b/unit_test/test_spdm_responder/psk_finish_rsp.c @@ -1593,6 +1593,185 @@ static void rsp_psk_finish_rsp_case16(void **state) free(data1); } +/** + * Test 17: SPDM version 1.4 request declares opaque data larger than payload. + * Expected behavior: the responder rejects with INVALID_REQUEST. + **/ +static void rsp_psk_finish_rsp_case17(void **state) +{ + libspdm_return_t status; + libspdm_test_context_t *spdm_test_context; + libspdm_context_t *spdm_context; + size_t response_size; + uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE]; + spdm_error_response_t *spdm_response; + void *data1; + size_t data_size1; + libspdm_session_info_t *session_info; + uint32_t session_id; + uint32_t hash_size; + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 0x11; + spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_14 << + SPDM_VERSION_NUMBER_SHIFT_BIT; + spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_NEGOTIATED; + spdm_context->connection_info.capability.flags |= SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PSK_CAP; + spdm_context->local_context.capability.flags |= SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_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.measurement_spec = m_libspdm_use_measurement_spec; + spdm_context->connection_info.algorithm.measurement_hash_algo = + m_libspdm_use_measurement_hash_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; + spdm_context->connection_info.algorithm.other_params_support = + SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1; + libspdm_read_responder_public_certificate_chain(m_libspdm_use_hash_algo, + m_libspdm_use_asym_algo, &data1, + &data_size1, NULL, NULL); + spdm_context->local_context.local_cert_chain_provision[0] = data1; + spdm_context->local_context.local_cert_chain_provision_size[0] = data_size1; + + libspdm_reset_message_a(spdm_context); + + 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, + SECURED_SPDM_VERSION_11 << SPDM_VERSION_NUMBER_SHIFT_BIT, true); + libspdm_session_info_set_psk_hint(session_info, + LIBSPDM_TEST_PSK_HINT_STRING, + sizeof(LIBSPDM_TEST_PSK_HINT_STRING)); + hash_size = libspdm_get_hash_size(m_libspdm_use_hash_algo); + libspdm_set_mem(m_libspdm_dummy_buffer, hash_size, (uint8_t)(0xFF)); + libspdm_secured_message_set_request_finished_key( + session_info->secured_message_context, m_libspdm_dummy_buffer, hash_size); + libspdm_secured_message_set_session_state( + session_info->secured_message_context, LIBSPDM_SESSION_STATE_HANDSHAKING); + + m_libspdm_psk_finish_request3.opaque_data_size = + sizeof(m_libspdm_psk_finish_request3.opaque_data); + + response_size = sizeof(response); + status = libspdm_get_response_psk_finish( + spdm_context, sizeof(spdm_psk_finish_request_t) + sizeof(uint16_t) + 4, + &m_libspdm_psk_finish_request3, &response_size, response); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + assert_int_equal(response_size, sizeof(spdm_error_response_t)); + spdm_response = (void *)response; + assert_int_equal(spdm_response->header.request_response_code, SPDM_ERROR); + assert_int_equal(spdm_response->header.param1, SPDM_ERROR_CODE_INVALID_REQUEST); + assert_int_equal(spdm_response->header.param2, 0); + + free(data1); +} + +/** + * Test 18: SPDM version 1.4 responder generates opaque response larger than protocol max. + * Expected behavior: the responder returns UNSPECIFIED error. + **/ +static void rsp_psk_finish_rsp_case18(void **state) +{ + libspdm_return_t status; + libspdm_test_context_t *spdm_test_context; + libspdm_context_t *spdm_context; + size_t response_size; + uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE]; + spdm_error_response_t *spdm_response; + void *data1; + size_t data_size1; + uint8_t *ptr; + uint8_t hash_data[LIBSPDM_MAX_HASH_SIZE]; + uint8_t request_finished_key[LIBSPDM_MAX_HASH_SIZE]; + libspdm_session_info_t *session_info; + uint32_t session_id; + uint32_t hash_size; + uint32_t hmac_size; + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 0x12; + spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_14 << + SPDM_VERSION_NUMBER_SHIFT_BIT; + spdm_context->connection_info.connection_state = + LIBSPDM_CONNECTION_STATE_NEGOTIATED; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PSK_CAP; + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_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.measurement_spec = m_libspdm_use_measurement_spec; + spdm_context->connection_info.algorithm.measurement_hash_algo = + m_libspdm_use_measurement_hash_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; + spdm_context->connection_info.algorithm.other_params_support = + SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1; + g_generate_psk_finish_opaque_data = true; + libspdm_secret_lib_psk_finish_opaque_data_size = SPDM_MAX_OPAQUE_DATA_SIZE + 1; + + libspdm_read_responder_public_certificate_chain(m_libspdm_use_hash_algo, + m_libspdm_use_asym_algo, &data1, + &data_size1, NULL, NULL); + spdm_context->local_context.local_cert_chain_provision[0] = data1; + spdm_context->local_context.local_cert_chain_provision_size[0] = data_size1; + + libspdm_reset_message_a(spdm_context); + + 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, + SECURED_SPDM_VERSION_11 << SPDM_VERSION_NUMBER_SHIFT_BIT, true); + libspdm_session_info_set_psk_hint(session_info, + LIBSPDM_TEST_PSK_HINT_STRING, + sizeof(LIBSPDM_TEST_PSK_HINT_STRING)); + hash_size = libspdm_get_hash_size(m_libspdm_use_hash_algo); + libspdm_set_mem(m_libspdm_dummy_buffer, hash_size, (uint8_t)(0xFF)); + libspdm_secured_message_set_request_finished_key( + session_info->secured_message_context, m_libspdm_dummy_buffer, hash_size); + libspdm_secured_message_set_session_state( + session_info->secured_message_context, LIBSPDM_SESSION_STATE_HANDSHAKING); + + m_libspdm_psk_finish_request3.opaque_data_size = + sizeof(m_libspdm_psk_finish_request3.opaque_data); + hash_size = libspdm_get_hash_size(m_libspdm_use_hash_algo); + hmac_size = libspdm_get_hash_size(m_libspdm_use_hash_algo); + ptr = m_libspdm_psk_finish_request3.verify_data; + libspdm_init_managed_buffer(&th_curr, sizeof(th_curr.buffer)); + libspdm_append_managed_buffer(&th_curr, (uint8_t *)&m_libspdm_psk_finish_request3, + sizeof(spdm_psk_finish_request_t) + sizeof(uint16_t) + + m_libspdm_psk_finish_request3.opaque_data_size); + libspdm_set_mem(request_finished_key, LIBSPDM_MAX_HASH_SIZE, (uint8_t)(0xFF)); + libspdm_hash_all(m_libspdm_use_hash_algo, libspdm_get_managed_buffer(&th_curr), + libspdm_get_managed_buffer_size(&th_curr), hash_data); + libspdm_hmac_all(m_libspdm_use_hash_algo, hash_data, hash_size, + request_finished_key, hash_size, ptr); + m_libspdm_psk_finish_request3_size = sizeof(spdm_psk_finish_request_t) + hmac_size + + sizeof(uint16_t) + + m_libspdm_psk_finish_request3.opaque_data_size; + response_size = sizeof(response); + status = libspdm_get_response_psk_finish( + spdm_context, m_libspdm_psk_finish_request3_size, &m_libspdm_psk_finish_request3, + &response_size, response); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + assert_int_equal(response_size, sizeof(spdm_error_response_t)); + spdm_response = (void *)response; + assert_int_equal(spdm_response->header.request_response_code, SPDM_ERROR); + assert_int_equal(spdm_response->header.param1, SPDM_ERROR_CODE_UNSPECIFIED); + assert_int_equal(spdm_response->header.param2, 0); + + g_generate_psk_finish_opaque_data = false; + free(data1); +} + int libspdm_rsp_psk_finish_rsp_test(void) { const struct CMUnitTest test_cases[] = { @@ -1628,6 +1807,10 @@ int libspdm_rsp_psk_finish_rsp_test(void) cmocka_unit_test(rsp_psk_finish_rsp_case15), /* SPDM 1.4, the Responder using integrator defined opaque data */ cmocka_unit_test(rsp_psk_finish_rsp_case16), + /* SPDM 1.4 request opaque size mismatch */ + cmocka_unit_test(rsp_psk_finish_rsp_case17), + /* SPDM 1.4 responder opaque exceeds protocol max */ + cmocka_unit_test(rsp_psk_finish_rsp_case18), }; libspdm_test_context_t test_context = {