diff --git a/include/hal/library/responder/keyexlib.h b/include/hal/library/responder/keyexlib.h index 90294719704..dae74b51630 100644 --- a/include/hal/library/responder/keyexlib.h +++ b/include/hal/library/responder/keyexlib.h @@ -11,7 +11,68 @@ #include "internal/libspdm_lib_config.h" #include "industry_standard/spdm.h" -#if (LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP) && (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) +#if LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP + +/** + * Generates the OpaqueData field of the KEY_EXCHANGE_RSP message. + * + * @param spdm_context A pointer to the SPDM context. + * @param spdm_version Indicates the negotiated version. + * @param measurement_hash_type The measurement hash type in the KEY_EXCHANGE request. + * @param slot_id The certificate slot within the KEY_EXCHANGE request. + * @param session_policy Policy for the session. A bitmask whose values are + * SPDM_KEY_EXCHANGE_REQUEST_SESSION_POLICY_*. + * @param req_opaque_data The OpaqueData field in the KEY_EXCHANGE request. + * @param req_opaque_data_size Size, in bytes, of req_opaque_data. + * @param opaque_data The buffer to store the OpaqueData field in the + * KEY_EXCHANGE_RSP response. + * @param opaque_data_size On input, size, in bytes, of the opaque_data buffer. + * On output, size, in bytes, of copied data in the + * opaque_data buffer. + * + * @retval true OpaqueData field is generated successfully. + * If return true, responder will not generate any opaque data, + * including secured message version. + * @retval false OpaqueData field generation failed. + */ +extern bool libspdm_key_exchange_rsp_opaque_data( + void *spdm_context, + spdm_version_number_t spdm_version, + uint8_t measurement_hash_type, + uint8_t slot_id, + uint8_t session_policy, + const void *req_opaque_data, + size_t req_opaque_data_size, + void *opaque_data, + size_t *opaque_data_size); + +/** + * Processes the OpaqueData field of the FINISH_RSP message. + * + * @param spdm_context A pointer to the SPDM context. + * @param session_id Secure session identifier. + * @param spdm_version Indicates the negotiated version. + * @param req_slot_id The certificate slot within the FINISH reuest. + * @param req_opaque_data The OpaqueData field in the FINISH request. + * @param req_opaque_data_size Size, in bytes, of req_opaque_data. + * @param opaque_data The buffer to store the OpaqueData field in the FINISH_RSP response. + * @param opaque_data_size On input, size, in bytes, of the opaque_data buffer. + * On output, size, in bytes, of copied data in the opaque_data buffer. + * + * @retval true OpaqueData field is processed successfully. + * @retval false OpaqueData field processing failed. + */ +extern bool libspdm_finish_rsp_opaque_data( + void *spdm_context, + uint32_t session_id, + spdm_version_number_t spdm_version, + uint8_t req_slot_id, + const void *req_opaque_data, + size_t req_opaque_data_size, + void *opaque_data, + size_t *opaque_data_size); + +#if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP /** * Queries whether session-based mutual authentication should be initiated or not. * @@ -50,6 +111,7 @@ extern uint8_t libspdm_key_exchange_start_mut_auth( size_t opaque_data_length, const void *opaque_data, bool *mandatory_mut_auth); -#endif /* (LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP) && (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) */ +#endif /* LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP */ +#endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP */ #endif /* RESPONDER_KEYEXLIB_H */ diff --git a/include/hal/library/responder/psklib.h b/include/hal/library/responder/psklib.h index c2e997b1113..593fcee9bff 100644 --- a/include/hal/library/responder/psklib.h +++ b/include/hal/library/responder/psklib.h @@ -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 **/ @@ -54,6 +54,63 @@ extern bool libspdm_psk_master_secret_hkdf_expand( const uint8_t *psk_hint, size_t psk_hint_size, const uint8_t *info, size_t info_size, uint8_t *out, size_t out_size); + +/** + * Generates the OpaqueData field of the PSK_EXCHANGE_RSP message. + * + * @param spdm_context A pointer to the SPDM context. + * @param psk_hint Pointer to the peer-provided PSK Hint. + * @param psk_hint_size PSK Hint size in bytes. + * @param spdm_version Indicates the negotiated version. + * @param measurement_hash_type The measurement hash type in the PSK_EXCHANGE request. + * @param req_opaque_data The OpaqueData field in the PSK_EXCHANGE request. + * @param req_opaque_data_size Size, in bytes, of req_opaque_data. + * @param opaque_data The buffer to store the OpaqueData field in the + * PSK_EXCHANGE_RSP response. + * @param opaque_data_size On input, size, in bytes, of the opaque_data buffer. + * On output, size, in bytes, of copied data in the + * opaque_data buffer. + * + * @retval true OpaqueData field is generated successfully. + * If return true, responder will not generate any opaque data, + * including secured message version. + * @retval false OpaqueData field generation failed. + */ +extern bool libspdm_psk_exchange_rsp_opaque_data( + void *spdm_context, + const void *psk_hint, + uint16_t psk_hint_size, + spdm_version_number_t spdm_version, + uint8_t measurement_hash_type, + const void *req_opaque_data, + size_t req_opaque_data_size, + void *opaque_data, + size_t *opaque_data_size); + +/** + * Processes the OpaqueData field of the PSK_FINISH_RSP message. + * + * @param spdm_context A pointer to the SPDM context. + * @param session_id Secure session identifier. + * @param spdm_version Indicates the negotiated version. + * @param req_opaque_data The OpaqueData field in the PSK_FINISH request. + * @param req_opaque_data_size Size, in bytes, of req_opaque_data. + * @param opaque_data The buffer to store the OpaqueData field in the PSK_FINISH_RSP response. + * @param opaque_data_size On input, size, in bytes, of the opaque_data buffer. + * On output, size, in bytes, of copied data in the opaque_data buffer. + * + * @retval true OpaqueData field is processed successfully. + * @retval false OpaqueData field processing failed. + */ +extern bool libspdm_psk_finish_rsp_opaque_data( + void *spdm_context, + uint32_t session_id, + spdm_version_number_t spdm_version, + const void *req_opaque_data, + size_t req_opaque_data_size, + void *opaque_data, + size_t *opaque_data_size); + #endif /* LIBSPDM_ENABLE_CAPABILITY_PSK_CAP */ #endif /* RESPONDER_PSKLIB_H */ diff --git a/library/spdm_responder_lib/libspdm_rsp_finish.c b/library/spdm_responder_lib/libspdm_rsp_finish.c index ce55de4fd7a..767f86cb185 100644 --- a/library/spdm_responder_lib/libspdm_rsp_finish.c +++ b/library/spdm_responder_lib/libspdm_rsp_finish.c @@ -410,6 +410,9 @@ libspdm_return_t libspdm_get_response_finish(libspdm_context_t *spdm_context, si libspdm_session_state_t session_state; uint8_t *ptr; size_t opaque_data_entry_size; + const uint8_t *req_opaque_data; + size_t req_opaque_data_size; + uint8_t *opaque_data; size_t opaque_data_size; spdm_request = request; @@ -531,17 +534,18 @@ libspdm_return_t libspdm_get_response_finish(libspdm_context_t *spdm_context, si ptr = (uint8_t *)(size_t)spdm_request + sizeof(spdm_finish_request_t); if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) { - opaque_data_size = libspdm_read_uint16((const uint8_t *)request + - sizeof(spdm_finish_request_t)); + req_opaque_data_size = libspdm_read_uint16((const uint8_t *)request + + sizeof(spdm_finish_request_t)); ptr += sizeof(uint16_t); if (request_size < sizeof(spdm_finish_request_t) + - sizeof(uint16_t) + opaque_data_size) { + sizeof(uint16_t) + req_opaque_data_size) { return libspdm_generate_error_response(spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response); } - ptr += opaque_data_size; - opaque_data_entry_size = sizeof(uint16_t) + opaque_data_size; + req_opaque_data = ptr; + ptr += req_opaque_data_size; + opaque_data_entry_size = sizeof(uint16_t) + req_opaque_data_size; } else { opaque_data_entry_size = 0; } @@ -660,9 +664,9 @@ libspdm_return_t libspdm_get_response_finish(libspdm_context_t *spdm_context, si opaque_data_entry_size = 0; } + /* response_size should be large enough to hold a finish response without opaque data. */ LIBSPDM_ASSERT(*response_size >= sizeof(spdm_finish_response_t) + opaque_data_entry_size + hmac_size); - *response_size = sizeof(spdm_finish_response_t) + opaque_data_entry_size + hmac_size; libspdm_zero_mem(response, *response_size); spdm_response = response; @@ -673,11 +677,32 @@ libspdm_return_t libspdm_get_response_finish(libspdm_context_t *spdm_context, si ptr = (uint8_t *)spdm_response + sizeof(spdm_finish_response_t); if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) { - opaque_data_size = 0; + opaque_data_size = *response_size - sizeof(spdm_finish_response_t) - + hmac_size - opaque_data_entry_size; + opaque_data = ptr + opaque_data_entry_size; + + if ((spdm_context->connection_info.algorithm.other_params_support & + SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) == SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_NONE) { + opaque_data_size = 0; + } else { + result = libspdm_finish_rsp_opaque_data( + spdm_context, session_id, spdm_request->header.spdm_version, + req_slot_id, req_opaque_data, req_opaque_data_size, + opaque_data, &opaque_data_size); + if (!result){ + return libspdm_generate_error_response(spdm_context, + SPDM_ERROR_CODE_UNSPECIFIED, 0, + response_size, response); + } + } + libspdm_write_uint16(ptr, (uint16_t)opaque_data_size); - ptr += sizeof(uint16_t); + opaque_data_entry_size = sizeof(uint16_t) + opaque_data_size; + ptr += opaque_data_entry_size; } + *response_size = sizeof(spdm_finish_response_t) + opaque_data_entry_size + hmac_size; + status = libspdm_append_message_f(spdm_context, session_info, false, spdm_response, (size_t)ptr - (size_t)spdm_response); if (LIBSPDM_STATUS_IS_ERROR(status)) { diff --git a/library/spdm_responder_lib/libspdm_rsp_key_exchange.c b/library/spdm_responder_lib/libspdm_rsp_key_exchange.c index 28a5336e734..d55095d395a 100644 --- a/library/spdm_responder_lib/libspdm_rsp_key_exchange.c +++ b/library/spdm_responder_lib/libspdm_rsp_key_exchange.c @@ -207,6 +207,7 @@ libspdm_return_t libspdm_get_response_key_exchange(libspdm_context_t *spdm_conte uint16_t rsp_session_id; libspdm_return_t status; size_t opaque_key_exchange_rsp_size; + bool use_default_opaque_data; uint8_t th1_hash_data[LIBSPDM_MAX_HASH_SIZE]; spdm_version_number_t secured_message_version; #if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP @@ -405,12 +406,10 @@ libspdm_return_t libspdm_get_response_key_exchange(libspdm_context_t *spdm_conte response_size, response); } } else { + secured_message_version = 0; req_opaque_data = NULL; } - opaque_key_exchange_rsp_size = - libspdm_get_opaque_data_version_selection_data_size(spdm_context); - libspdm_reset_message_buffer_via_request_code(spdm_context, NULL, spdm_request->header.request_response_code); @@ -421,6 +420,27 @@ libspdm_return_t libspdm_get_response_key_exchange(libspdm_context_t *spdm_conte hmac_size = 0; } + /* + * Here allows integrator generate own opaque data for Key Exchange Response. + * If libspdm_key_exchange_rsp_opaque_data() returns false, + * libspdm will generate version selection opaque data. + */ + opaque_key_exchange_rsp_size = *response_size - sizeof(spdm_key_exchange_response_t) - + rsp_key_exchange_size - measurement_summary_hash_size - + sizeof(uint16_t) - signature_size - hmac_size; + + use_default_opaque_data = false; + result = libspdm_key_exchange_rsp_opaque_data( + spdm_context, spdm_request->header.spdm_version, + spdm_request->header.param1, slot_id, spdm_request->session_policy, + req_opaque_data, opaque_data_length, NULL, + &opaque_key_exchange_rsp_size); + if (!result) { + use_default_opaque_data = true; + opaque_key_exchange_rsp_size = + libspdm_get_opaque_data_version_selection_data_size(spdm_context); + } + total_size = sizeof(spdm_key_exchange_response_t) + rsp_key_exchange_size + measurement_summary_hash_size + sizeof(uint16_t) + opaque_key_exchange_rsp_size + signature_size + hmac_size; @@ -649,8 +669,24 @@ libspdm_return_t libspdm_get_response_key_exchange(libspdm_context_t *spdm_conte libspdm_write_uint16(ptr, (uint16_t)opaque_key_exchange_rsp_size); ptr += sizeof(uint16_t); - libspdm_build_opaque_data_version_selection_data( - spdm_context, secured_message_version, &opaque_key_exchange_rsp_size, ptr); + + if (use_default_opaque_data) { + libspdm_build_opaque_data_version_selection_data( + spdm_context, secured_message_version, &opaque_key_exchange_rsp_size, ptr); + } else { + result = libspdm_key_exchange_rsp_opaque_data( + spdm_context, spdm_request->header.spdm_version, + spdm_request->header.param1, slot_id, spdm_request->session_policy, + req_opaque_data, opaque_data_length, ptr, + &opaque_key_exchange_rsp_size); + if (!result) { + libspdm_free_session_id(spdm_context, session_id); + return libspdm_generate_error_response(spdm_context, + SPDM_ERROR_CODE_UNSPECIFIED, 0, + response_size, response); + } + } + ptr += opaque_key_exchange_rsp_size; status = libspdm_append_message_k(spdm_context, session_info, false, request, request_size); diff --git a/library/spdm_responder_lib/libspdm_rsp_psk_exchange.c b/library/spdm_responder_lib/libspdm_rsp_psk_exchange.c index e9d27f8d8ce..d2c3947d1e7 100644 --- a/library/spdm_responder_lib/libspdm_rsp_psk_exchange.c +++ b/library/spdm_responder_lib/libspdm_rsp_psk_exchange.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 **/ @@ -84,7 +84,7 @@ libspdm_return_t libspdm_get_response_psk_exchange(libspdm_context_t *spdm_conte uint32_t session_id; uint32_t measurement_summary_hash_size; uint32_t hmac_size; - const uint8_t *cptr; + const uint8_t *req_opaque_data; uint8_t *ptr; libspdm_session_info_t *session_info; size_t total_size; @@ -92,6 +92,7 @@ libspdm_return_t libspdm_get_response_psk_exchange(libspdm_context_t *spdm_conte uint16_t rsp_session_id; libspdm_return_t status; size_t opaque_psk_exchange_rsp_size; + bool use_default_opaque_data; uint8_t th1_hash_data[LIBSPDM_MAX_HASH_SIZE]; uint8_t th2_hash_data[LIBSPDM_MAX_HASH_SIZE]; uint32_t algo_size; @@ -246,18 +247,19 @@ libspdm_return_t libspdm_get_response_psk_exchange(libspdm_context_t *spdm_conte spdm_request->context_length + spdm_request->opaque_length; + secured_message_version = 0; if (spdm_request->opaque_length != 0) { - cptr = (const uint8_t *)request + sizeof(spdm_psk_exchange_request_t) + - spdm_request->psk_hint_length + spdm_request->context_length; + req_opaque_data = (const uint8_t *)request + sizeof(spdm_psk_exchange_request_t) + + spdm_request->psk_hint_length + spdm_request->context_length; result = libspdm_process_general_opaque_data_check(spdm_context, - spdm_request->opaque_length, cptr); + spdm_request->opaque_length, req_opaque_data); if (!result) { return libspdm_generate_error_response(spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response); } status = libspdm_process_opaque_data_supported_version_data( - spdm_context, spdm_request->opaque_length, cptr, &secured_message_version); + spdm_context, spdm_request->opaque_length, req_opaque_data, &secured_message_version); if (LIBSPDM_STATUS_IS_ERROR(status)) { return libspdm_generate_error_response(spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, @@ -265,8 +267,6 @@ libspdm_return_t libspdm_get_response_psk_exchange(libspdm_context_t *spdm_conte } } - opaque_psk_exchange_rsp_size = - libspdm_get_opaque_data_version_selection_data_size(spdm_context); if (libspdm_is_capabilities_flag_supported( spdm_context, false, 0, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP_RESPONDER_WITH_CONTEXT)) { @@ -274,6 +274,41 @@ libspdm_return_t libspdm_get_response_psk_exchange(libspdm_context_t *spdm_conte } else { context_length = 0; } + + if (spdm_request->psk_hint_length == 0) { + psk_hint_size = 0; + psk_hint = NULL; + } else if (spdm_request->psk_hint_length <= LIBSPDM_PSK_MAX_HINT_LENGTH ) { + psk_hint_size = spdm_request->psk_hint_length; + psk_hint = (const uint8_t *)request + + sizeof(spdm_psk_exchange_request_t); + } else { + return libspdm_generate_error_response( + spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, + response_size, response); + } + + /* + * Here allows integrator generate own opaque data for Key Exchange Response. + * If libspdm_psk_exchange_rsp_opaque_data() returns false, + * libspdm will generate version selection opaque data. + */ + opaque_psk_exchange_rsp_size = *response_size - sizeof(spdm_psk_exchange_response_t) - + measurement_summary_hash_size - context_length - + hmac_size; + use_default_opaque_data = false; + result = libspdm_psk_exchange_rsp_opaque_data( + spdm_context, psk_hint, spdm_request->psk_hint_length, + spdm_request->header.spdm_version, + spdm_request->header.param1, + req_opaque_data, spdm_request->opaque_length, NULL, + &opaque_psk_exchange_rsp_size); + if (!result) { + use_default_opaque_data = true; + opaque_psk_exchange_rsp_size = + libspdm_get_opaque_data_version_selection_data_size(spdm_context); + } + total_size = sizeof(spdm_psk_exchange_response_t) + measurement_summary_hash_size + context_length + opaque_psk_exchange_rsp_size + hmac_size; @@ -301,18 +336,6 @@ libspdm_return_t libspdm_get_response_psk_exchange(libspdm_context_t *spdm_conte spdm_context, SPDM_ERROR_CODE_SESSION_LIMIT_EXCEEDED, 0, response_size, response); } - if (spdm_request->psk_hint_length == 0) { - psk_hint_size = 0; - psk_hint = NULL; - } else if (spdm_request->psk_hint_length <= LIBSPDM_PSK_MAX_HINT_LENGTH ) { - psk_hint_size = spdm_request->psk_hint_length; - psk_hint = (const uint8_t *)request + - sizeof(spdm_psk_exchange_request_t); - } else { - return libspdm_generate_error_response( - spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, - response_size, response); - } session_id = libspdm_generate_session_id(req_session_id, rsp_session_id); session_info = libspdm_assign_session_id(spdm_context, session_id, secured_message_version, true); @@ -370,8 +393,23 @@ libspdm_return_t libspdm_get_response_psk_exchange(libspdm_context_t *spdm_conte ptr += context_length; } - libspdm_build_opaque_data_version_selection_data( - spdm_context, secured_message_version, &opaque_psk_exchange_rsp_size, ptr); + if (use_default_opaque_data) { + libspdm_build_opaque_data_version_selection_data( + spdm_context, secured_message_version, &opaque_psk_exchange_rsp_size, ptr); + } else { + result = libspdm_psk_exchange_rsp_opaque_data( + spdm_context, psk_hint, spdm_request->psk_hint_length, + spdm_request->header.spdm_version, + spdm_request->header.param1, + req_opaque_data, spdm_request->opaque_length, ptr, + &opaque_psk_exchange_rsp_size); + if (!result) { + libspdm_free_session_id(spdm_context, session_id); + return libspdm_generate_error_response(spdm_context, + SPDM_ERROR_CODE_UNSPECIFIED, 0, + response_size, response); + } + } ptr += opaque_psk_exchange_rsp_size; diff --git a/library/spdm_responder_lib/libspdm_rsp_psk_finish.c b/library/spdm_responder_lib/libspdm_rsp_psk_finish.c index 84b63ebce92..e390c61082b 100644 --- a/library/spdm_responder_lib/libspdm_rsp_psk_finish.c +++ b/library/spdm_responder_lib/libspdm_rsp_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 **/ @@ -83,6 +83,9 @@ libspdm_return_t libspdm_get_response_psk_finish(libspdm_context_t *spdm_context libspdm_session_state_t session_state; uint8_t *ptr; size_t opaque_data_entry_size; + const uint8_t *req_opaque_data; + size_t req_opaque_data_size; + uint8_t *opaque_data; size_t opaque_data_size; spdm_request = request; @@ -166,17 +169,18 @@ libspdm_return_t libspdm_get_response_psk_finish(libspdm_context_t *spdm_context ptr = (uint8_t *)(size_t)spdm_request + sizeof(spdm_psk_finish_request_t); if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) { - opaque_data_size = libspdm_read_uint16((const uint8_t *)request + - sizeof(spdm_psk_finish_request_t)); + req_opaque_data_size = libspdm_read_uint16((const uint8_t *)request + + sizeof(spdm_psk_finish_request_t)); ptr += sizeof(uint16_t); if (request_size < sizeof(spdm_psk_finish_request_t) + - sizeof(uint16_t) + opaque_data_size) { + sizeof(uint16_t) + req_opaque_data_size) { return libspdm_generate_error_response(spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response); } - ptr += opaque_data_size; - opaque_data_entry_size = sizeof(uint16_t) + opaque_data_size; + req_opaque_data = ptr; + ptr += req_opaque_data_size; + opaque_data_entry_size = sizeof(uint16_t) + req_opaque_data_size; } else { opaque_data_entry_size = 0; } @@ -233,8 +237,8 @@ libspdm_return_t libspdm_get_response_psk_finish(libspdm_context_t *spdm_context opaque_data_entry_size = 0; } + /* response_size should be large enough to hold a psk finish response without opaque data. */ LIBSPDM_ASSERT(*response_size >= sizeof(spdm_psk_finish_response_t) + opaque_data_entry_size); - *response_size = sizeof(spdm_psk_finish_response_t) + opaque_data_entry_size; libspdm_zero_mem(response, *response_size); spdm_response = response; @@ -243,13 +247,33 @@ libspdm_return_t libspdm_get_response_psk_finish(libspdm_context_t *spdm_context spdm_response->header.param1 = 0; spdm_response->header.param2 = 0; - ptr = (uint8_t *)spdm_response + sizeof(spdm_finish_response_t); + ptr = (uint8_t *)spdm_response + sizeof(spdm_psk_finish_response_t); if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) { - opaque_data_size = 0; + opaque_data_size = *response_size - sizeof(spdm_psk_finish_response_t) - + opaque_data_entry_size; + opaque_data = ptr + opaque_data_entry_size; + + if ((spdm_context->connection_info.algorithm.other_params_support & + SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) == SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_NONE) { + opaque_data_size = 0; + } else { + status = libspdm_psk_finish_rsp_opaque_data( + spdm_context, session_id, spdm_request->header.spdm_version, + req_opaque_data, req_opaque_data_size, + opaque_data, &opaque_data_size); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + return libspdm_generate_error_response(spdm_context, + SPDM_ERROR_CODE_UNSPECIFIED, 0, + response_size, response); + } + } libspdm_write_uint16(ptr, (uint16_t)opaque_data_size); - ptr += sizeof(uint16_t); + opaque_data_entry_size = sizeof(uint16_t) + opaque_data_size; + ptr += opaque_data_entry_size; } + *response_size = sizeof(spdm_psk_finish_response_t) + opaque_data_entry_size; + status = libspdm_append_message_f(spdm_context, session_info, false, spdm_response, *response_size); if (LIBSPDM_STATUS_IS_ERROR(status)) { diff --git a/os_stub/spdm_device_secret_lib_null/lib.c b/os_stub/spdm_device_secret_lib_null/lib.c index 09e437f1c89..b3b1fc215d6 100644 --- a/os_stub/spdm_device_secret_lib_null/lib.c +++ b/os_stub/spdm_device_secret_lib_null/lib.c @@ -117,7 +117,35 @@ bool libspdm_measurement_extension_log_collection( } #endif /* LIBSPDM_ENABLE_CAPABILITY_MEL_CAP */ -#if (LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP) && (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) +#if LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP +bool libspdm_key_exchange_rsp_opaque_data( + void *spdm_context, + spdm_version_number_t spdm_version, + uint8_t measurement_hash_type, + uint8_t slot_id, + uint8_t session_policy, + const void *req_opaque_data, + size_t req_opaque_data_size, + void *opaque_data, + size_t *opaque_data_size) +{ + return false; +} + +bool libspdm_finish_rsp_opaque_data( + void *spdm_context, + uint32_t session_id, + spdm_version_number_t spdm_version, + uint8_t req_slot_id, + const void *req_opaque_data, + size_t req_opaque_data_size, + void *opaque_data, + size_t *opaque_data_size) +{ + return false; +} + +#if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP extern uint8_t libspdm_key_exchange_start_mut_auth( void *spdm_context, uint32_t session_id, @@ -131,7 +159,8 @@ extern uint8_t libspdm_key_exchange_start_mut_auth( { return false; } -#endif /* (LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP) && (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) */ +#endif /* LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP */ +#endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP */ #if (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) || (LIBSPDM_ENABLE_CAPABILITY_ENDPOINT_INFO_CAP) bool libspdm_requester_data_sign( @@ -183,6 +212,32 @@ bool libspdm_psk_master_secret_hkdf_expand( { return false; } + +bool libspdm_psk_exchange_rsp_opaque_data( + void *spdm_context, + const void *psk_hint, + uint16_t psk_hint_size, + spdm_version_number_t spdm_version, + uint8_t measurement_hash_type, + const void *req_opaque_data, + size_t req_opaque_data_size, + void *opaque_data, + size_t *opaque_data_size) +{ + return false; +} + +bool libspdm_psk_finish_rsp_opaque_data( + void *spdm_context, + uint32_t session_id, + spdm_version_number_t spdm_version, + const void *req_opaque_data, + size_t req_opaque_data_size, + void *opaque_data, + size_t *opaque_data_size) +{ + return false; +} #endif /* LIBSPDM_ENABLE_CAPABILITY_PSK_CAP */ #if LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP diff --git a/os_stub/spdm_device_secret_lib_sample/key_ex.c b/os_stub/spdm_device_secret_lib_sample/key_ex.c index 1f8fa14ae81..5c7958af569 100644 --- a/os_stub/spdm_device_secret_lib_sample/key_ex.c +++ b/os_stub/spdm_device_secret_lib_sample/key_ex.c @@ -10,7 +10,69 @@ uint8_t g_key_exchange_start_mut_auth = 0; bool g_mandatory_mut_auth = false; -#if (LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP) && (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) +#if LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP +size_t libspdm_secret_lib_key_exchange_opaque_data_size; +bool g_generate_key_exchange_opaque_data = false; +size_t libspdm_secret_lib_finish_opaque_data_size; +bool g_generate_finish_opaque_data = false; + +bool libspdm_key_exchange_rsp_opaque_data( + void *spdm_context, + spdm_version_number_t spdm_version, + uint8_t measurement_hash_type, + uint8_t slot_id, + uint8_t session_policy, + const void *req_opaque_data, + size_t req_opaque_data_size, + void *opaque_data, + size_t *opaque_data_size) +{ + if (g_generate_key_exchange_opaque_data) { + LIBSPDM_ASSERT(libspdm_secret_lib_key_exchange_opaque_data_size <= *opaque_data_size); + + *opaque_data_size = libspdm_secret_lib_key_exchange_opaque_data_size; + + if (opaque_data != NULL) { + for (size_t index = 0; index < *opaque_data_size; index++) + { + ((uint8_t *)opaque_data)[index] = (uint8_t)(index + 1); + } + } + + return true; + } + return false; +} + +bool libspdm_finish_rsp_opaque_data( + void *spdm_context, + uint32_t session_id, + spdm_version_number_t spdm_version, + uint8_t req_slot_id, + const void *req_opaque_data, + size_t req_opaque_data_size, + void *opaque_data, + size_t *opaque_data_size) +{ + if (g_generate_finish_opaque_data) { + LIBSPDM_ASSERT(libspdm_secret_lib_finish_opaque_data_size <= *opaque_data_size); + + *opaque_data_size = libspdm_secret_lib_finish_opaque_data_size; + + if (opaque_data != NULL) { + for (size_t index = 0; index < *opaque_data_size; index++) + { + ((uint8_t *)opaque_data)[index] = (uint8_t)(index + 1); + } + } + } else { + *opaque_data_size = 0; + } + + return true; +} + +#if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP extern uint8_t libspdm_key_exchange_start_mut_auth( void *spdm_context, uint32_t session_id, @@ -27,4 +89,5 @@ extern uint8_t libspdm_key_exchange_start_mut_auth( return g_key_exchange_start_mut_auth; } -#endif /* (LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP) && (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) */ +#endif /* LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP */ +#endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP */ diff --git a/os_stub/spdm_device_secret_lib_sample/psk.c b/os_stub/spdm_device_secret_lib_sample/psk.c index 87766444b5b..44f8d206d1b 100644 --- a/os_stub/spdm_device_secret_lib_sample/psk.c +++ b/os_stub/spdm_device_secret_lib_sample/psk.c @@ -44,6 +44,11 @@ uint8_t m_cxl_tsp_2nd_session_psk[CXL_TSP_2ND_SESSION_COUNT][CXL_TSP_2ND_SESSION uint8_t m_cxl_tsp_current_psk_session_index = 0xFF; +size_t libspdm_secret_lib_psk_exchange_opaque_data_size; +bool g_generate_psk_exchange_opaque_data = false; +size_t libspdm_secret_lib_psk_finish_opaque_data_size; +bool g_generate_psk_finish_opaque_data = false; + bool libspdm_psk_handshake_secret_hkdf_expand( spdm_version_number_t spdm_version, uint32_t base_hash_algo, @@ -197,4 +202,61 @@ bool libspdm_psk_master_secret_hkdf_expand( return result; } + +bool libspdm_psk_exchange_rsp_opaque_data( + void *spdm_context, + const void *psk_hint, + uint16_t psk_hint_size, + spdm_version_number_t spdm_version, + uint8_t measurement_hash_type, + const void *req_opaque_data, + size_t req_opaque_data_size, + void *opaque_data, + size_t *opaque_data_size) +{ + if (g_generate_psk_exchange_opaque_data) { + LIBSPDM_ASSERT(libspdm_secret_lib_psk_exchange_opaque_data_size <= *opaque_data_size); + + *opaque_data_size = libspdm_secret_lib_psk_exchange_opaque_data_size; + + if (opaque_data != NULL) { + for (size_t index = 0; index < *opaque_data_size; index++) + { + ((uint8_t *)opaque_data)[index] = (uint8_t)(index + 1); + } + } + + + return true; + } + return false; +} + +bool libspdm_psk_finish_rsp_opaque_data( + void *spdm_context, + uint32_t session_id, + spdm_version_number_t spdm_version, + const void *req_opaque_data, + size_t req_opaque_data_size, + void *opaque_data, + size_t *opaque_data_size) +{ + if (g_generate_psk_finish_opaque_data) { + LIBSPDM_ASSERT(libspdm_secret_lib_psk_finish_opaque_data_size <= *opaque_data_size); + + *opaque_data_size = libspdm_secret_lib_psk_finish_opaque_data_size; + + if (opaque_data != NULL) { + for (size_t index = 0; index < *opaque_data_size; index++) + { + ((uint8_t *)opaque_data)[index] = (uint8_t)(index + 1); + } + } + } else { + *opaque_data_size = 0; + } + + return true; +} + #endif /* LIBSPDM_ENABLE_CAPABILITY_PSK_CAP */ diff --git a/unit_test/test_spdm_responder/finish_rsp.c b/unit_test/test_spdm_responder/finish_rsp.c index 8eb944bbda0..c2eec968045 100644 --- a/unit_test/test_spdm_responder/finish_rsp.c +++ b/unit_test/test_spdm_responder/finish_rsp.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 **/ @@ -69,6 +69,9 @@ uint8_t m_dummy_buffer[LIBSPDM_MAX_HASH_SIZE]; static libspdm_th_managed_buffer_t th_curr; +extern size_t libspdm_secret_lib_finish_opaque_data_size; +extern bool g_generate_finish_opaque_data; + void libspdm_secured_message_set_request_finished_key( void *spdm_secured_message_context, const void *key, size_t key_size) { @@ -3963,6 +3966,138 @@ void rsp_finish_rsp_case30(void **state) free(data1); } +/** + * Test 31: SPDM version 1.4, with OpaqueData. + * Expected behavior: the responder accepts the request and produces a valid + * FINISH_RSP response message with integrator defined opaque data in the response. + **/ +void rsp_finish_rsp_case31(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_finish_response_t *spdm_response; + void *data1; + size_t data_size1; + uint8_t *ptr; + uint8_t *cert_buffer; + size_t cert_buffer_size; + uint8_t cert_buffer_hash[LIBSPDM_MAX_HASH_SIZE]; + 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 = 31; + 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_KEY_EX_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.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_finish_opaque_data = true; + libspdm_secret_lib_finish_opaque_data_size = 8; + + 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); + + /* The requester and responder have not set HANDSHAKE_IN_THE_CLEAR*/ + spdm_context->connection_info.capability.flags &= + ~SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP; + spdm_context->local_context.capability.flags &= + ~SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP; + + 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, false); + + session_info->local_used_cert_chain_slot_id = 0; + hash_size = libspdm_get_hash_size(m_libspdm_use_hash_algo); + hmac_size = libspdm_get_hash_size(m_libspdm_use_hash_algo); + + libspdm_set_mem(m_dummy_buffer, hash_size, (uint8_t)(0xFF)); + libspdm_secured_message_set_request_finished_key( + session_info->secured_message_context, m_dummy_buffer, + hash_size); + libspdm_secured_message_set_session_state( + session_info->secured_message_context, + LIBSPDM_SESSION_STATE_HANDSHAKING); + + m_libspdm_finish_request8.opaque_data_size = sizeof(m_libspdm_finish_request8.opaque_data); + + hash_size = libspdm_get_hash_size(m_libspdm_use_hash_algo); + ptr = m_libspdm_finish_request8.signature; + libspdm_init_managed_buffer(&th_curr, sizeof(th_curr.buffer)); + cert_buffer = (uint8_t *)data1; + cert_buffer_size = data_size1; + libspdm_hash_all(m_libspdm_use_hash_algo, cert_buffer, cert_buffer_size, + cert_buffer_hash); + /* transcript.message_a size is 0*/ + libspdm_append_managed_buffer(&th_curr, cert_buffer_hash, hash_size); + /* session_transcript.message_k is 0*/ + libspdm_append_managed_buffer(&th_curr, (uint8_t *)&m_libspdm_finish_request8, + sizeof(spdm_finish_request_t) + sizeof(uint16_t) + + m_libspdm_finish_request8.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_finish_request8_size = sizeof(spdm_finish_request_t) + hmac_size + + sizeof(uint16_t) + m_libspdm_finish_request8.opaque_data_size; + response_size = sizeof(response); + status = libspdm_get_response_finish(spdm_context, + m_libspdm_finish_request8_size, + &m_libspdm_finish_request8, + &response_size, response); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + /* The ResponderVerifyData field shall be absent.*/ + ptr = (uint8_t *)response + sizeof(spdm_finish_response_t); + assert_int_equal(libspdm_read_uint16(ptr), + libspdm_secret_lib_finish_opaque_data_size); + assert_int_equal(response_size, + sizeof(spdm_finish_response_t) + sizeof(uint16_t) + + libspdm_read_uint16(ptr)); + spdm_response = (void *)response; + assert_int_equal(spdm_response->header.request_response_code, + SPDM_FINISH_RSP); + g_generate_finish_opaque_data = false; + free(data1); +} + int libspdm_rsp_finish_test(void) { const struct CMUnitTest test_cases[] = { @@ -4024,6 +4159,8 @@ int libspdm_rsp_finish_test(void) cmocka_unit_test(rsp_finish_rsp_case29), /* SPDM 1.4 with OpaqueData */ cmocka_unit_test(rsp_finish_rsp_case30), + /* SPDM 1.4, the Responder using integrator defined opaque data */ + cmocka_unit_test(rsp_finish_rsp_case31), }; libspdm_test_context_t test_context = { diff --git a/unit_test/test_spdm_responder/key_exchange_rsp.c b/unit_test/test_spdm_responder/key_exchange_rsp.c index 000ff7f0ac2..31483ece673 100644 --- a/unit_test/test_spdm_responder/key_exchange_rsp.c +++ b/unit_test/test_spdm_responder/key_exchange_rsp.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 **/ @@ -90,6 +90,8 @@ size_t m_libspdm_key_exchange_request10_size = sizeof(m_libspdm_key_exchange_req extern uint8_t g_key_exchange_start_mut_auth; extern bool g_mandatory_mut_auth; +extern size_t libspdm_secret_lib_key_exchange_opaque_data_size; +extern bool g_generate_key_exchange_opaque_data; extern bool g_event_all_subscribe; extern bool g_event_all_unsubscribe; @@ -2186,6 +2188,108 @@ static void rsp_key_exchange_rsp_case24(void **state) free(data1); } +/** + * Test 25: Successful response to a valid KEY_EXCHANGE request. + * Expected Behavior: get a valid KEY_EXCHANGE_RSP message + * with integrator defined opaque data in the response + **/ +static void rsp_key_exchange_rsp_case25(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_key_exchange_response_t *spdm_response; + void *data1; + size_t data_size1; + uint8_t *ptr; + size_t dhe_key_size; + void *dhe_context; + size_t opaque_key_exchange_req_size; + uint16_t opaque_length; + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 0x19; + spdm_context->connection_info.connection_state = + LIBSPDM_CONNECTION_STATE_NEGOTIATED; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_EX_CAP | + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MAC_CAP; + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP | + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MAC_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.version = SPDM_MESSAGE_VERSION_12 << + SPDM_VERSION_NUMBER_SHIFT_BIT; + spdm_context->connection_info.algorithm.other_params_support = + SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1; + spdm_context->local_context.secured_message_version.secured_message_version_count = 1; + g_generate_key_exchange_opaque_data = true; + libspdm_secret_lib_key_exchange_opaque_data_size = 8; + + libspdm_session_info_init(spdm_context, + spdm_context->session_info, + 0, + INVALID_SESSION_ID, false); + 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); + + libspdm_get_random_number(SPDM_RANDOM_DATA_SIZE, m_libspdm_key_exchange_request8.random_data); + m_libspdm_key_exchange_request8.req_session_id = 0xFFFF; + m_libspdm_key_exchange_request8.reserved = 0; + m_libspdm_key_exchange_request8.session_policy = 0xFF; + ptr = m_libspdm_key_exchange_request8.exchange_data; + dhe_key_size = libspdm_get_dhe_pub_key_size(m_libspdm_use_dhe_algo); + dhe_context = libspdm_dhe_new(spdm_context->connection_info.version, m_libspdm_use_dhe_algo, + false); + libspdm_dhe_generate_key(m_libspdm_use_dhe_algo, dhe_context, ptr, &dhe_key_size); + ptr += dhe_key_size; + libspdm_dhe_free(m_libspdm_use_dhe_algo, dhe_context); + opaque_key_exchange_req_size = + libspdm_get_opaque_data_supported_version_data_size(spdm_context); + *(uint16_t *)ptr = (uint16_t)opaque_key_exchange_req_size; + ptr += sizeof(uint16_t); + libspdm_build_opaque_data_supported_version_data( + spdm_context, &opaque_key_exchange_req_size, ptr); + ptr += opaque_key_exchange_req_size; + response_size = sizeof(response); + status = libspdm_get_response_key_exchange( + spdm_context, m_libspdm_key_exchange_request8_size, + &m_libspdm_key_exchange_request8, &response_size, response); + assert_int_equal(spdm_context->session_info[0].session_policy, + m_libspdm_key_exchange_request8.session_policy); + spdm_response = (void *)response; + assert_int_equal(spdm_response->header.spdm_version, SPDM_MESSAGE_VERSION_12); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + assert_int_equal( + libspdm_secured_message_get_session_state( + spdm_context->session_info[0].secured_message_context), + LIBSPDM_SESSION_STATE_HANDSHAKING); + spdm_response = (void *)response; + assert_int_equal(spdm_response->header.request_response_code, SPDM_KEY_EXCHANGE_RSP); + assert_int_equal(spdm_response->rsp_session_id, 0xFFFF); + ptr = (uint8_t *)(spdm_response + 1); + ptr += dhe_key_size; + opaque_length = *(uint16_t *)ptr; + assert_int_equal(opaque_length, libspdm_secret_lib_key_exchange_opaque_data_size); + + g_generate_key_exchange_opaque_data = false; + free(data1); +} + int libspdm_rsp_key_exchange_rsp_test(void) { const struct CMUnitTest test_cases[] = { @@ -2233,6 +2337,8 @@ int libspdm_rsp_key_exchange_rsp_test(void) /* The Responder requires mutual authentication, but the Requester does not support it */ cmocka_unit_test(rsp_key_exchange_rsp_case23), cmocka_unit_test(rsp_key_exchange_rsp_case24), + /* The Responder using integrator defined opaque data */ + cmocka_unit_test(rsp_key_exchange_rsp_case25), }; libspdm_test_context_t test_context = { diff --git a/unit_test/test_spdm_responder/psk_exchange_rsp.c b/unit_test/test_spdm_responder/psk_exchange_rsp.c index 2ebc3ddbf28..c5a8b363a91 100644 --- a/unit_test/test_spdm_responder/psk_exchange_rsp.c +++ b/unit_test/test_spdm_responder/psk_exchange_rsp.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 **/ @@ -112,6 +112,9 @@ libspdm_psk_exchange_request_mine_t_noPSKHINT_noOPAQUE m_libspdm_psk_exchange_re }; size_t m_libspdm_psk_exchange_request9_size = sizeof(m_libspdm_psk_exchange_request9); +extern size_t libspdm_secret_lib_psk_exchange_opaque_data_size; +extern bool g_generate_psk_exchange_opaque_data; + static void rsp_psk_exchange_rsp_case1(void **state) { libspdm_return_t status; @@ -1673,6 +1676,115 @@ static void rsp_psk_exchange_rsp_case17(void **state) free(data1); } + +/** + * Test 18: Successful response to a valid PSK_EXCHANGE request. + * Expected Behavior: get a valid PSK_EXCHANGE_RSP message + * with integrator defined opaque data in the response + **/ +static void rsp_psk_exchange_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_psk_exchange_response_t *spdm_response; + void *data1; + size_t data_size1; + uint8_t *ptr; + size_t opaque_psk_exchange_req_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_12 << + 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.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.key_schedule = + m_libspdm_use_key_schedule_algo; + spdm_context->connection_info.algorithm.other_params_support = + SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1; + g_generate_psk_exchange_opaque_data = true; + libspdm_secret_lib_psk_exchange_opaque_data_size = 8; + + libspdm_session_info_init(spdm_context, + spdm_context->session_info, + 0, + INVALID_SESSION_ID, true); + 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); + + m_libspdm_psk_exchange_request3.psk_hint_length = + (uint16_t)sizeof(LIBSPDM_TEST_PSK_HINT_STRING); + m_libspdm_psk_exchange_request3.context_length = LIBSPDM_PSK_CONTEXT_LENGTH; + opaque_psk_exchange_req_size = + libspdm_get_opaque_data_supported_version_data_size(spdm_context); + m_libspdm_psk_exchange_request3.opaque_length = + (uint16_t)opaque_psk_exchange_req_size; + m_libspdm_psk_exchange_request3.req_session_id = 0xFFFF; + ptr = m_libspdm_psk_exchange_request3.psk_hint; + libspdm_copy_mem(ptr, sizeof(m_libspdm_psk_exchange_request3.psk_hint), + LIBSPDM_TEST_PSK_HINT_STRING, + sizeof(LIBSPDM_TEST_PSK_HINT_STRING)); + ptr += m_libspdm_psk_exchange_request3.psk_hint_length; + libspdm_get_random_number(LIBSPDM_PSK_CONTEXT_LENGTH, ptr); + ptr += m_libspdm_psk_exchange_request3.context_length; + libspdm_build_opaque_data_supported_version_data( + spdm_context, &opaque_psk_exchange_req_size, ptr); +#if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT + spdm_context->transcript.message_m.buffer_size = + spdm_context->transcript.message_m.max_buffer_size; +#endif + ptr += opaque_psk_exchange_req_size; + response_size = sizeof(response); + status = libspdm_get_response_psk_exchange( + spdm_context, m_libspdm_psk_exchange_request3_size, + &m_libspdm_psk_exchange_request3, &response_size, response); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + assert_int_equal( + libspdm_secured_message_get_session_state( + spdm_context->session_info[0].secured_message_context), + LIBSPDM_SESSION_STATE_HANDSHAKING); + assert_int_equal(spdm_context->session_info[0].session_policy, 0); + spdm_response = (void *)response; + assert_int_equal(spdm_response->header.spdm_version, + SPDM_MESSAGE_VERSION_12); + assert_int_equal(spdm_response->header.request_response_code, + SPDM_PSK_EXCHANGE_RSP); + assert_int_equal(spdm_response->rsp_session_id, 0xFFFF); + assert_int_equal(spdm_response->opaque_length, + libspdm_secret_lib_psk_exchange_opaque_data_size); + +#if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT + assert_int_equal(spdm_context->transcript.message_m.buffer_size, + 0); +#endif + g_generate_psk_exchange_opaque_data = false; + free(data1); +} + int libspdm_rsp_psk_exchange_rsp_test(void) { const struct CMUnitTest test_cases[] = { @@ -1712,6 +1824,8 @@ int libspdm_rsp_psk_exchange_rsp_test(void) cmocka_unit_test(rsp_psk_exchange_rsp_case16), /* OpaqueData only supports OpaqueDataFmt1, Success Case */ cmocka_unit_test(rsp_psk_exchange_rsp_case17), + /* The Responder using integrator defined opaque data */ + cmocka_unit_test(rsp_psk_exchange_rsp_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 19577a13bb5..3f792f9d371 100644 --- a/unit_test/test_spdm_responder/psk_finish_rsp.c +++ b/unit_test/test_spdm_responder/psk_finish_rsp.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 **/ @@ -42,6 +42,9 @@ size_t m_libspdm_psk_finish_request3_size = sizeof(m_libspdm_psk_finish_request3 static uint8_t m_libspdm_dummy_buffer[LIBSPDM_MAX_HASH_SIZE]; +extern size_t libspdm_secret_lib_psk_finish_opaque_data_size; +extern bool g_generate_psk_finish_opaque_data; + static void libspdm_secured_message_set_request_finished_key( void *spdm_secured_message_context, const void *key, size_t key_size) { @@ -1644,6 +1647,113 @@ static void rsp_psk_finish_rsp_case15(void **state) free(data1); } +/** + * Test 16: SPDM version 1.4, with OpaqueData. + * Expected behavior: the responder accepts the request and produces a valid + * PSK_FINISH_RSP response message with integrator defined opaque data in the response. + **/ +static void rsp_psk_finish_rsp_case16(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_psk_finish_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 = 0x10; + 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 = 8; + + 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)); + /* transcript.message_a size is 0 + * session_transcript.message_k is 0*/ + 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); + ptr = (uint8_t *)response + sizeof(spdm_psk_finish_response_t); + assert_int_equal(libspdm_read_uint16(ptr), + libspdm_secret_lib_psk_finish_opaque_data_size); + assert_int_equal(response_size, sizeof(spdm_psk_finish_response_t) + + sizeof(uint16_t) + libspdm_read_uint16(ptr)); + spdm_response = (void *)response; + assert_int_equal(spdm_response->header.request_response_code, SPDM_PSK_FINISH_RSP); + + g_generate_psk_finish_opaque_data = false; + free(data1); +} + int libspdm_rsp_psk_finish_rsp_test(void) { const struct CMUnitTest test_cases[] = { @@ -1677,6 +1787,8 @@ int libspdm_rsp_psk_finish_rsp_test(void) cmocka_unit_test(rsp_psk_finish_rsp_case14), /* SPDM 1.4 with OpaqueData */ 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), }; libspdm_test_context_t test_context = {