From b8307f6d2783c075d9796e6f35a4d8734e557479 Mon Sep 17 00:00:00 2001 From: Jiewen Yao Date: Tue, 15 Jul 2025 13:13:05 +0800 Subject: [PATCH 1/5] 1.4 Add OpaqueData for FINISH/PSK_FINISH in spdm.h Signed-off-by: Jiewen Yao --- include/industry_standard/spdm.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/industry_standard/spdm.h b/include/industry_standard/spdm.h index 5ada747a7b7..1e57a6687aa 100644 --- a/include/industry_standard/spdm.h +++ b/include/industry_standard/spdm.h @@ -1112,6 +1112,8 @@ typedef struct { spdm_message_header_t header; /* param1 == signature_included * param2 == req_slot_id + * uint16_t opaque_length; // 1.4+ + * uint8_t opaque_data[opaque_length]; // 1.4+ * uint8_t signature[S]; * uint8_t verify_data[H];*/ } spdm_finish_request_t; @@ -1124,6 +1126,8 @@ typedef struct { spdm_message_header_t header; /* param1 == RSVD * param2 == RSVD + * uint16_t opaque_length; // 1.4+ + * uint8_t opaque_data[opaque_length]; // 1.4+ * uint8_t verify_data[H];*/ } spdm_finish_response_t; @@ -1171,6 +1175,8 @@ typedef struct { spdm_message_header_t header; /* param1 == RSVD * param2 == RSVD + * uint16_t opaque_length; // 1.4+ + * uint8_t opaque_data[opaque_length]; // 1.4+ * uint8_t verify_data[H];*/ } spdm_psk_finish_request_t; @@ -1178,7 +1184,9 @@ typedef struct { typedef struct { spdm_message_header_t header; /* param1 == RSVD - * param2 == RSVD*/ + * param2 == RSVD + * uint16_t opaque_length; // 1.4+ + * uint8_t opaque_data[opaque_length]; // 1.4+ */ } spdm_psk_finish_response_t; From f170318492c7c2b60b55140c36221ac9c9806961 Mon Sep 17 00:00:00 2001 From: Jiewen Yao Date: Tue, 15 Jul 2025 23:12:54 +0800 Subject: [PATCH 2/5] 1.4 Add OpaqueData to FINISH/PSK_FINISH requester Signed-off-by: Jiewen Yao --- include/internal/libspdm_requester_lib.h | 17 ++ .../spdm_requester_lib/libspdm_req_finish.c | 148 +++++++++++++++--- .../libspdm_req_psk_finish.c | 141 +++++++++++++++-- 3 files changed, 274 insertions(+), 32 deletions(-) diff --git a/include/internal/libspdm_requester_lib.h b/include/internal/libspdm_requester_lib.h index 65e29a3fd07..c1e9b21054e 100644 --- a/include/internal/libspdm_requester_lib.h +++ b/include/internal/libspdm_requester_lib.h @@ -262,6 +262,15 @@ libspdm_return_t libspdm_send_receive_key_exchange_ex( libspdm_return_t libspdm_send_receive_finish(libspdm_context_t *spdm_context, uint32_t session_id, uint8_t req_slot_id_param); + +libspdm_return_t libspdm_send_receive_finish_ex( + libspdm_context_t *spdm_context, + uint32_t session_id, + uint8_t req_slot_id_param, + const void *requester_opaque_data, + size_t requester_opaque_data_size, + void *responder_opaque_data, + size_t *responder_opaque_data_size); #endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP */ #if LIBSPDM_ENABLE_CAPABILITY_PSK_CAP @@ -338,6 +347,14 @@ libspdm_return_t libspdm_send_receive_psk_exchange_ex(libspdm_context_t *spdm_co **/ libspdm_return_t libspdm_send_receive_psk_finish(libspdm_context_t *spdm_context, uint32_t session_id); + +libspdm_return_t libspdm_send_receive_psk_finish_ex( + libspdm_context_t *spdm_context, + uint32_t session_id, + const void *requester_opaque_data, + size_t requester_opaque_data_size, + void *responder_opaque_data, + size_t *responder_opaque_data_size); #endif /* LIBSPDM_ENABLE_CAPABILITY_PSK_CAP */ #if (LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP) || (LIBSPDM_ENABLE_CAPABILITY_PSK_CAP) diff --git a/library/spdm_requester_lib/libspdm_req_finish.c b/library/spdm_requester_lib/libspdm_req_finish.c index 4a83e155e9a..dd23e1f47e6 100644 --- a/library/spdm_requester_lib/libspdm_req_finish.c +++ b/library/spdm_requester_lib/libspdm_req_finish.c @@ -12,12 +12,16 @@ #pragma pack(1) typedef struct { spdm_message_header_t header; + uint16_t opaque_length; + uint8_t opaque_data[SPDM_MAX_OPAQUE_DATA_SIZE]; uint8_t signature[LIBSPDM_REQ_SIGNATURE_DATA_MAX_SIZE]; uint8_t verify_data[LIBSPDM_MAX_HASH_SIZE]; } libspdm_finish_request_mine_t; typedef struct { spdm_message_header_t header; + uint16_t opaque_length; + uint8_t opaque_data[SPDM_MAX_OPAQUE_DATA_SIZE]; uint8_t verify_data[LIBSPDM_MAX_HASH_SIZE]; } libspdm_finish_response_mine_t; #pragma pack() @@ -344,9 +348,14 @@ bool libspdm_generate_finish_req_signature(libspdm_context_t *spdm_context, * @retval RETURN_SUCCESS The FINISH is sent and the FINISH_RSP is received. * @retval RETURN_DEVICE_ERROR A device error occurs when communicates with the device. **/ -static libspdm_return_t libspdm_try_send_receive_finish(libspdm_context_t *spdm_context, - uint32_t session_id, - uint8_t req_slot_id_param) +static libspdm_return_t libspdm_try_send_receive_finish( + libspdm_context_t *spdm_context, + uint32_t session_id, + uint8_t req_slot_id_param, + const void *requester_opaque_data, + size_t requester_opaque_data_size, + void *responder_opaque_data, + size_t *responder_opaque_data_size) { libspdm_return_t status; libspdm_finish_request_mine_t *spdm_request; @@ -363,6 +372,8 @@ static libspdm_return_t libspdm_try_send_receive_finish(libspdm_context_t *spdm_ uint8_t *message; size_t message_size; size_t transport_header_size; + size_t opaque_data_entry_size; + size_t opaque_data_size; /* -=[Check Parameters Phase]=- */ if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) { @@ -424,6 +435,36 @@ static libspdm_return_t libspdm_try_send_receive_finish(libspdm_context_t *spdm_ spdm_request->header.request_response_code = SPDM_FINISH; spdm_request->header.param1 = 0; spdm_request->header.param2 = 0; + + ptr = (uint8_t *)spdm_request + sizeof(spdm_finish_request_t); + if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) { + if (requester_opaque_data != NULL) { + LIBSPDM_ASSERT(requester_opaque_data_size <= SPDM_MAX_OPAQUE_DATA_SIZE); + LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_finish_request_t) + + sizeof(uint16_t) + requester_opaque_data_size); + + libspdm_write_uint16(ptr, (uint16_t)requester_opaque_data_size); + ptr += sizeof(uint16_t); + + libspdm_copy_mem(ptr, + (spdm_request_size - (sizeof(spdm_finish_request_t) + + sizeof(uint16_t))), + requester_opaque_data, requester_opaque_data_size); + opaque_data_size = requester_opaque_data_size; + } else { + opaque_data_size = 0; + LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_finish_request_t) + + sizeof(uint16_t) + opaque_data_size); + + libspdm_write_uint16(ptr, (uint16_t)opaque_data_size); + ptr += sizeof(uint16_t); + } + ptr += opaque_data_size; + opaque_data_entry_size = sizeof(uint16_t) + opaque_data_size; + } else { + opaque_data_entry_size = 0; + } + signature_size = 0; #if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP if (session_info->mut_auth_requested != 0) { @@ -449,13 +490,13 @@ static libspdm_return_t libspdm_try_send_receive_finish(libspdm_context_t *spdm_ } hmac_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo); - LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_finish_request_t) + signature_size + - hmac_size); - spdm_request_size = sizeof(spdm_finish_request_t) + signature_size + hmac_size; - ptr = spdm_request->signature; + LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_finish_request_t) + opaque_data_entry_size + + signature_size + hmac_size); + spdm_request_size = sizeof(spdm_finish_request_t) + opaque_data_entry_size + + signature_size + hmac_size; status = libspdm_append_message_f(spdm_context, session_info, true, (uint8_t *)spdm_request, - sizeof(spdm_finish_request_t)); + spdm_request_size - signature_size - hmac_size); if (LIBSPDM_STATUS_IS_ERROR(status)) { libspdm_release_sender_buffer (spdm_context); goto error; @@ -553,13 +594,51 @@ static libspdm_return_t libspdm_try_send_receive_finish(libspdm_context_t *spdm_ hmac_size = 0; } - if (spdm_response_size < sizeof(spdm_finish_response_t) + hmac_size) { - status = LIBSPDM_STATUS_INVALID_MSG_SIZE; - goto receive_done; + ptr = (uint8_t *)spdm_response + sizeof(spdm_finish_response_t); + + if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) { + if (spdm_response_size < sizeof(spdm_finish_response_t) + sizeof(uint16_t) + hmac_size) { + status = LIBSPDM_STATUS_INVALID_MSG_SIZE; + goto receive_done; + } + opaque_data_size = libspdm_read_uint16((const uint8_t *)ptr); + ptr += sizeof(uint16_t); + if (opaque_data_size > SPDM_MAX_OPAQUE_DATA_SIZE) { + status = LIBSPDM_STATUS_INVALID_MSG_FIELD; + goto receive_done; + } + if (spdm_response_size < sizeof(spdm_finish_response_t) + sizeof(uint16_t) + + opaque_data_size + hmac_size) { + status = LIBSPDM_STATUS_INVALID_MSG_SIZE; + goto receive_done; + } + + if ((responder_opaque_data != NULL) && (responder_opaque_data_size != NULL)) { + if (opaque_data_size >= *responder_opaque_data_size) { + status = LIBSPDM_STATUS_BUFFER_TOO_SMALL; + goto receive_done; + } + libspdm_copy_mem(responder_opaque_data, *responder_opaque_data_size, + ptr, opaque_data_size); + *responder_opaque_data_size = opaque_data_size; + } + + ptr += opaque_data_size; + opaque_data_entry_size = sizeof(uint16_t) + opaque_data_size; + } else { + if (spdm_response_size < sizeof(spdm_finish_response_t) + hmac_size) { + status = LIBSPDM_STATUS_INVALID_MSG_SIZE; + goto receive_done; + } + if ((responder_opaque_data != NULL) && (responder_opaque_data_size != NULL)) { + *responder_opaque_data_size = 0; + } + opaque_data_entry_size = 0; } + spdm_response_size = sizeof(spdm_finish_response_t) + opaque_data_entry_size + hmac_size; status = libspdm_append_message_f(spdm_context, session_info, true, spdm_response, - sizeof(spdm_finish_response_t)); + spdm_response_size - hmac_size); if (LIBSPDM_STATUS_IS_ERROR(status)) { goto receive_done; } @@ -569,10 +648,9 @@ static libspdm_return_t libspdm_try_send_receive_finish(libspdm_context_t *spdm_ SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) { LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "verify_data (0x%zx):\n", hmac_size)); - LIBSPDM_INTERNAL_DUMP_HEX(spdm_response->verify_data, hmac_size); + LIBSPDM_INTERNAL_DUMP_HEX(ptr, hmac_size); result = libspdm_verify_finish_rsp_hmac(spdm_context, session_info, - spdm_response->verify_data, - hmac_size); + ptr, hmac_size); if (!result) { status = LIBSPDM_STATUS_VERIF_FAIL; goto receive_done; @@ -580,9 +658,7 @@ static libspdm_return_t libspdm_try_send_receive_finish(libspdm_context_t *spdm_ status = libspdm_append_message_f( spdm_context, session_info, true, - (uint8_t *)spdm_response + - sizeof(spdm_finish_response_t), - hmac_size); + ptr, hmac_size); if (LIBSPDM_STATUS_IS_ERROR(status)) { goto receive_done; } @@ -638,7 +714,41 @@ libspdm_return_t libspdm_send_receive_finish(libspdm_context_t *spdm_context, retry_delay_time = spdm_context->retry_delay_time; do { status = libspdm_try_send_receive_finish(spdm_context, session_id, - req_slot_id_param); + req_slot_id_param, + NULL, 0, NULL, NULL); + if (status != LIBSPDM_STATUS_BUSY_PEER) { + return status; + } + + libspdm_sleep(retry_delay_time); + } while (retry-- != 0); + + return status; +} + +libspdm_return_t libspdm_send_receive_finish_ex( + libspdm_context_t *spdm_context, + uint32_t session_id, + uint8_t req_slot_id_param, + const void *requester_opaque_data, + size_t requester_opaque_data_size, + void *responder_opaque_data, + size_t *responder_opaque_data_size) +{ + size_t retry; + uint64_t retry_delay_time; + libspdm_return_t status; + + spdm_context->crypto_request = true; + retry = spdm_context->retry_times; + retry_delay_time = spdm_context->retry_delay_time; + do { + status = libspdm_try_send_receive_finish(spdm_context, session_id, + req_slot_id_param, + requester_opaque_data, + requester_opaque_data_size, + responder_opaque_data, + responder_opaque_data_size); if (status != LIBSPDM_STATUS_BUSY_PEER) { return status; } diff --git a/library/spdm_requester_lib/libspdm_req_psk_finish.c b/library/spdm_requester_lib/libspdm_req_psk_finish.c index f22f9d8873a..9ac730a0541 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-2024 DMTF. All rights reserved. + * Copyright 2021-2025 DMTF. All rights reserved. * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md **/ @@ -12,12 +12,15 @@ #pragma pack(1) typedef struct { spdm_message_header_t header; + uint16_t opaque_length; + uint8_t opaque_data[SPDM_MAX_OPAQUE_DATA_SIZE]; uint8_t verify_data[LIBSPDM_MAX_HASH_SIZE]; } libspdm_psk_finish_request_mine_t; typedef struct { spdm_message_header_t header; - uint8_t dummy_data[sizeof(spdm_error_data_response_not_ready_t)]; + uint16_t opaque_length; + uint8_t opaque_data[SPDM_MAX_OPAQUE_DATA_SIZE]; } libspdm_psk_finish_response_max_t; #pragma pack() @@ -93,8 +96,13 @@ bool libspdm_generate_psk_exchange_req_hmac(libspdm_context_t *spdm_context, * @retval RETURN_SUCCESS The PSK_FINISH is sent and the PSK_FINISH_RSP is received. * @retval RETURN_DEVICE_ERROR A device error occurs when communicates with the device. **/ -static libspdm_return_t libspdm_try_send_receive_psk_finish(libspdm_context_t *spdm_context, - uint32_t session_id) +static libspdm_return_t libspdm_try_send_receive_psk_finish( + libspdm_context_t *spdm_context, + uint32_t session_id, + const void *requester_opaque_data, + size_t requester_opaque_data_size, + void *responder_opaque_data, + size_t *responder_opaque_data_size) { libspdm_return_t status; libspdm_psk_finish_request_mine_t *spdm_request; @@ -109,6 +117,9 @@ static libspdm_return_t libspdm_try_send_receive_psk_finish(libspdm_context_t *s uint8_t *message; size_t message_size; size_t transport_header_size; + uint8_t *ptr; + size_t opaque_data_entry_size; + size_t opaque_data_size; if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) { return LIBSPDM_STATUS_UNSUPPORTED_CAP; @@ -159,10 +170,40 @@ static libspdm_return_t libspdm_try_send_receive_psk_finish(libspdm_context_t *s spdm_request->header.param1 = 0; spdm_request->header.param2 = 0; + ptr = (uint8_t *)spdm_request + sizeof(spdm_psk_finish_request_t); + if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) { + if (requester_opaque_data != NULL) { + LIBSPDM_ASSERT(requester_opaque_data_size <= SPDM_MAX_OPAQUE_DATA_SIZE); + LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_psk_finish_request_t) + + sizeof(uint16_t) + requester_opaque_data_size); + + libspdm_write_uint16(ptr, (uint16_t)requester_opaque_data_size); + ptr += sizeof(uint16_t); + + libspdm_copy_mem(ptr, + (spdm_request_size - (sizeof(spdm_psk_finish_request_t) + + sizeof(uint16_t))), + requester_opaque_data, requester_opaque_data_size); + opaque_data_size = requester_opaque_data_size; + } else { + opaque_data_size = 0; + LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_psk_finish_request_t) + + sizeof(uint16_t) + opaque_data_size); + + libspdm_write_uint16(ptr, (uint16_t)opaque_data_size); + ptr += sizeof(uint16_t); + } + ptr += opaque_data_size; + opaque_data_entry_size = sizeof(uint16_t) + opaque_data_size; + } else { + opaque_data_entry_size = 0; + } + hmac_size = libspdm_get_hash_size( spdm_context->connection_info.algorithm.base_hash_algo); - LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_request->header) + hmac_size); - spdm_request_size = sizeof(spdm_psk_finish_request_t) + hmac_size; + LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_request->header) + + opaque_data_entry_size + hmac_size); + spdm_request_size = sizeof(spdm_psk_finish_request_t) + opaque_data_entry_size + hmac_size; status = libspdm_append_message_f(spdm_context, session_info, true, (uint8_t *)spdm_request, spdm_request_size - hmac_size); @@ -172,7 +213,7 @@ static libspdm_return_t libspdm_try_send_receive_psk_finish(libspdm_context_t *s } result = libspdm_generate_psk_exchange_req_hmac(spdm_context, session_info, - spdm_request->verify_data); + ptr); if (!result) { libspdm_release_sender_buffer (spdm_context); status = LIBSPDM_STATUS_CRYPTO_ERROR; @@ -241,12 +282,53 @@ static libspdm_return_t libspdm_try_send_receive_psk_finish(libspdm_context_t *s 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)) { - status = LIBSPDM_STATUS_INVALID_MSG_SIZE; - goto receive_done; + + ptr = (uint8_t *)spdm_response + sizeof(spdm_psk_finish_response_t); + + if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) { + if (spdm_response_size < sizeof(spdm_psk_finish_response_t) + sizeof(uint16_t)) { + status = LIBSPDM_STATUS_INVALID_MSG_SIZE; + goto receive_done; + } + opaque_data_size = libspdm_read_uint16((const uint8_t *)ptr); + ptr += sizeof(uint16_t); + if (opaque_data_size > SPDM_MAX_OPAQUE_DATA_SIZE) { + 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) + + opaque_data_size) { + status = LIBSPDM_STATUS_INVALID_MSG_SIZE; + goto receive_done; + } + + if ((responder_opaque_data != NULL) && (responder_opaque_data_size != NULL)) { + if (opaque_data_size >= *responder_opaque_data_size) { + status = LIBSPDM_STATUS_BUFFER_TOO_SMALL; + goto receive_done; + } + libspdm_copy_mem(responder_opaque_data, *responder_opaque_data_size, + ptr, opaque_data_size); + *responder_opaque_data_size = opaque_data_size; + } + + ptr += opaque_data_size; + opaque_data_entry_size = sizeof(uint16_t) + opaque_data_size; + } else { + /* 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)) { + status = LIBSPDM_STATUS_INVALID_MSG_SIZE; + goto receive_done; + } + if ((responder_opaque_data != NULL) && (responder_opaque_data_size != NULL)) { + *responder_opaque_data_size = 0; + } + opaque_data_entry_size = 0; } + spdm_response_size = sizeof(spdm_finish_response_t) + opaque_data_entry_size; status = libspdm_append_message_f(spdm_context, session_info, true, spdm_response, spdm_response_size); @@ -301,7 +383,40 @@ libspdm_return_t libspdm_send_receive_psk_finish(libspdm_context_t *spdm_context retry_delay_time = spdm_context->retry_delay_time; do { status = libspdm_try_send_receive_psk_finish(spdm_context, - session_id); + session_id, + NULL, 0, NULL, NULL); + if (status != LIBSPDM_STATUS_BUSY_PEER) { + return status; + } + + libspdm_sleep(retry_delay_time); + } while (retry-- != 0); + + return status; +} + +libspdm_return_t libspdm_send_receive_psk_finish_ex( + libspdm_context_t *spdm_context, + uint32_t session_id, + const void *requester_opaque_data, + size_t requester_opaque_data_size, + void *responder_opaque_data, + size_t *responder_opaque_data_size) +{ + size_t retry; + uint64_t retry_delay_time; + libspdm_return_t status; + + spdm_context->crypto_request = true; + retry = spdm_context->retry_times; + retry_delay_time = spdm_context->retry_delay_time; + do { + status = libspdm_try_send_receive_psk_finish(spdm_context, + session_id, + requester_opaque_data, + requester_opaque_data_size, + responder_opaque_data, + responder_opaque_data_size); if (status != LIBSPDM_STATUS_BUSY_PEER) { return status; } From 6b07746a83629e284a1dcc6c9d64e4fae35799fe Mon Sep 17 00:00:00 2001 From: Jiewen Yao Date: Wed, 16 Jul 2025 13:30:06 +0800 Subject: [PATCH 3/5] 1.4 Add OpaqueData to FINISH/PSK_FINISH responder Signed-off-by: Jiewen Yao --- .../spdm_responder_lib/libspdm_rsp_finish.c | 63 ++++++++++++++----- .../libspdm_rsp_psk_finish.c | 63 ++++++++++++++----- 2 files changed, 96 insertions(+), 30 deletions(-) diff --git a/library/spdm_responder_lib/libspdm_rsp_finish.c b/library/spdm_responder_lib/libspdm_rsp_finish.c index ed0d1d31978..2a8a1732aa1 100644 --- a/library/spdm_responder_lib/libspdm_rsp_finish.c +++ b/library/spdm_responder_lib/libspdm_rsp_finish.c @@ -407,6 +407,9 @@ libspdm_return_t libspdm_get_response_finish(libspdm_context_t *spdm_context, si uint8_t th2_hash_data[LIBSPDM_MAX_HASH_SIZE]; libspdm_return_t status; libspdm_session_state_t session_state; + uint8_t *ptr; + size_t opaque_data_entry_size; + size_t opaque_data_size; spdm_request = request; @@ -525,11 +528,31 @@ libspdm_return_t libspdm_get_response_finish(libspdm_context_t *spdm_context, si } #endif /* LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP */ - if (request_size < sizeof(spdm_finish_request_t) + signature_size + hmac_size) { + 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)); + ptr += sizeof(uint16_t); + if (request_size < sizeof(spdm_finish_request_t) + + sizeof(uint16_t) + 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; + } else { + opaque_data_entry_size = 0; + } + + if (request_size < sizeof(spdm_finish_request_t) + opaque_data_entry_size + + signature_size + hmac_size) { return libspdm_generate_error_response(spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response); } + request_size = sizeof(spdm_finish_request_t) + opaque_data_entry_size + + signature_size + hmac_size; if ((spdm_request->header.param1 & SPDM_FINISH_REQUEST_ATTRIBUTES_SIGNATURE_INCLUDED) != 0) { req_slot_id = spdm_request->header.param2; @@ -559,7 +582,7 @@ libspdm_return_t libspdm_get_response_finish(libspdm_context_t *spdm_context, si spdm_request->header.request_response_code); status = libspdm_append_message_f(spdm_context, session_info, false, request, - sizeof(spdm_finish_request_t)); + request_size - (signature_size + hmac_size)); if (LIBSPDM_STATUS_IS_ERROR(status)) { return libspdm_generate_error_response(spdm_context, SPDM_ERROR_CODE_UNSPECIFIED, 0, @@ -569,7 +592,7 @@ libspdm_return_t libspdm_get_response_finish(libspdm_context_t *spdm_context, si if (session_info->mut_auth_requested != 0) { result = libspdm_verify_finish_req_signature( spdm_context, session_info, - (const uint8_t *)request + sizeof(spdm_finish_request_t), signature_size); + ptr, signature_size); if (!result) { if((spdm_context->handle_error_return_policy & LIBSPDM_DATA_HANDLE_ERROR_RETURN_POLICY_DROP_ON_DECRYPT_ERROR) == 0) { @@ -587,18 +610,18 @@ libspdm_return_t libspdm_get_response_finish(libspdm_context_t *spdm_context, si } status = libspdm_append_message_f( spdm_context, session_info, false, - (const uint8_t *)request + sizeof(spdm_finish_request_t), signature_size); + ptr, signature_size); if (LIBSPDM_STATUS_IS_ERROR(status)) { return libspdm_generate_error_response( spdm_context, SPDM_ERROR_CODE_UNSPECIFIED, 0, response_size, response); } } + ptr += signature_size; #endif /* LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP */ result = libspdm_verify_finish_req_hmac( - spdm_context, session_info, (const uint8_t *)request + signature_size + - sizeof(spdm_finish_request_t), hmac_size); + spdm_context, session_info, ptr, hmac_size); if (!result) { if((spdm_context->handle_error_return_policy & LIBSPDM_DATA_HANDLE_ERROR_RETURN_POLICY_DROP_ON_DECRYPT_ERROR) == 0) { @@ -616,9 +639,7 @@ libspdm_return_t libspdm_get_response_finish(libspdm_context_t *spdm_context, si } status = libspdm_append_message_f(spdm_context, session_info, false, - (const uint8_t *)request + signature_size + - sizeof(spdm_finish_request_t), - hmac_size); + ptr, hmac_size); if (LIBSPDM_STATUS_IS_ERROR(status)) { return libspdm_generate_error_response(spdm_context, SPDM_ERROR_CODE_UNSPECIFIED, 0, @@ -632,8 +653,15 @@ libspdm_return_t libspdm_get_response_finish(libspdm_context_t *spdm_context, si hmac_size = 0; } - LIBSPDM_ASSERT(*response_size >= sizeof(spdm_finish_response_t) + hmac_size); - *response_size = sizeof(spdm_finish_response_t) + hmac_size; + if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) { + opaque_data_entry_size = sizeof(uint16_t); + } else { + opaque_data_entry_size = 0; + } + + 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; @@ -642,8 +670,15 @@ libspdm_return_t libspdm_get_response_finish(libspdm_context_t *spdm_context, si spdm_response->header.param1 = 0; spdm_response->header.param2 = 0; + 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; + libspdm_write_uint16(ptr, (uint16_t)opaque_data_size); + ptr += sizeof(uint16_t); + } + status = libspdm_append_message_f(spdm_context, session_info, false, spdm_response, - sizeof(spdm_finish_response_t)); + (size_t)ptr - (size_t)spdm_response); if (LIBSPDM_STATUS_IS_ERROR(status)) { return libspdm_generate_error_response(spdm_context, SPDM_ERROR_CODE_UNSPECIFIED, 0, @@ -655,7 +690,7 @@ libspdm_return_t libspdm_get_response_finish(libspdm_context_t *spdm_context, si SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) { result = libspdm_generate_finish_rsp_hmac( - spdm_context, session_info, (uint8_t *)spdm_response + sizeof(spdm_finish_request_t)); + spdm_context, session_info, ptr); if (!result) { return libspdm_generate_error_response( spdm_context, @@ -665,7 +700,7 @@ libspdm_return_t libspdm_get_response_finish(libspdm_context_t *spdm_context, si status = libspdm_append_message_f( spdm_context, session_info, false, - (uint8_t *)spdm_response + sizeof(spdm_finish_request_t), hmac_size); + ptr, hmac_size); if (LIBSPDM_STATUS_IS_ERROR(status)) { return libspdm_generate_error_response( spdm_context, SPDM_ERROR_CODE_UNSPECIFIED, diff --git a/library/spdm_responder_lib/libspdm_rsp_psk_finish.c b/library/spdm_responder_lib/libspdm_rsp_psk_finish.c index 59f6ea62f3f..51ab98447f7 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-2024 DMTF. All rights reserved. + * Copyright 2021-2025 DMTF. All rights reserved. * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md **/ @@ -81,6 +81,9 @@ libspdm_return_t libspdm_get_response_psk_finish(libspdm_context_t *spdm_context const spdm_psk_finish_request_t *spdm_request; libspdm_return_t status; libspdm_session_state_t session_state; + uint8_t *ptr; + size_t opaque_data_entry_size; + size_t opaque_data_size; spdm_request = request; @@ -161,9 +164,26 @@ libspdm_return_t libspdm_get_response_psk_finish(libspdm_context_t *spdm_context hmac_size = libspdm_get_hash_size( spdm_context->connection_info.algorithm.base_hash_algo); + 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)); + ptr += sizeof(uint16_t); + if (request_size < sizeof(spdm_psk_finish_request_t) + + sizeof(uint16_t) + 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; + } else { + opaque_data_entry_size = 0; + } + /* this message can only be in secured session * thus don't need to consider transport layer padding, just check its exact size */ - if (request_size != sizeof(spdm_psk_finish_request_t) + hmac_size) { + if (request_size != sizeof(spdm_psk_finish_request_t) + opaque_data_entry_size + hmac_size) { return libspdm_generate_error_response(spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response); @@ -180,20 +200,9 @@ libspdm_return_t libspdm_get_response_psk_finish(libspdm_context_t *spdm_context response_size, response); } - LIBSPDM_ASSERT(*response_size >= sizeof(spdm_psk_finish_response_t)); - *response_size = sizeof(spdm_psk_finish_response_t); - libspdm_zero_mem(response, *response_size); - spdm_response = response; - - spdm_response->header.spdm_version = spdm_request->header.spdm_version; - spdm_response->header.request_response_code = SPDM_PSK_FINISH_RSP; - spdm_response->header.param1 = 0; - spdm_response->header.param2 = 0; - result = libspdm_verify_psk_finish_req_hmac( spdm_context, session_info, - (const uint8_t *)request + sizeof(spdm_psk_finish_request_t), - hmac_size); + ptr, hmac_size); if (!result) { if((spdm_context->handle_error_return_policy & LIBSPDM_DATA_HANDLE_ERROR_RETURN_POLICY_DROP_ON_DECRYPT_ERROR) == 0) { @@ -211,14 +220,36 @@ libspdm_return_t libspdm_get_response_psk_finish(libspdm_context_t *spdm_context } status = libspdm_append_message_f( spdm_context, session_info, false, - (const uint8_t *)request + request_size - hmac_size, - hmac_size); + ptr, hmac_size); if (LIBSPDM_STATUS_IS_ERROR(status)) { return libspdm_generate_error_response(spdm_context, SPDM_ERROR_CODE_UNSPECIFIED, 0, response_size, response); } + if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) { + opaque_data_entry_size = sizeof(uint16_t); + } else { + opaque_data_entry_size = 0; + } + + 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; + + spdm_response->header.spdm_version = spdm_request->header.spdm_version; + 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_finish_response_t); + if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) { + opaque_data_size = 0; + libspdm_write_uint16(ptr, (uint16_t)opaque_data_size); + ptr += sizeof(uint16_t); + } + status = libspdm_append_message_f(spdm_context, session_info, false, spdm_response, *response_size); if (LIBSPDM_STATUS_IS_ERROR(status)) { From c74c32e82429fd78b45764c38107d7b96d7b73e5 Mon Sep 17 00:00:00 2001 From: Jiewen Yao Date: Fri, 18 Jul 2025 11:50:53 +0800 Subject: [PATCH 4/5] 1.4 Add unit test for FINISH/PSK_FINISH requester Signed-off-by: Jiewen Yao --- unit_test/test_spdm_requester/finish.c | 154 ++++++++++++++++++++- unit_test/test_spdm_requester/psk_finish.c | 144 ++++++++++++++++++- 2 files changed, 295 insertions(+), 3 deletions(-) diff --git a/unit_test/test_spdm_requester/finish.c b/unit_test/test_spdm_requester/finish.c index b7faf59502a..71e15a015f5 100644 --- a/unit_test/test_spdm_requester/finish.c +++ b/unit_test/test_spdm_requester/finish.c @@ -1,6 +1,6 @@ /** * Copyright Notice: - * Copyright 2021-2022 DMTF. All rights reserved. + * Copyright 2021-2025 DMTF. All rights reserved. * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md **/ @@ -176,6 +176,7 @@ libspdm_return_t libspdm_requester_finish_test_send_message(void *spdm_context, return LIBSPDM_STATUS_SUCCESS; case 0x17: case 0x18: + case 0x19: m_libspdm_local_buffer_size = 0; libspdm_copy_mem(m_libspdm_local_buffer, sizeof(m_libspdm_local_buffer), &ptr[1], request_size - 1); @@ -1491,6 +1492,48 @@ libspdm_return_t libspdm_requester_finish_test_receive_message( spdm_response->header.param1 = 0; spdm_response->header.param2 = 0; + session_id = 0xFFFFFFFF; + /* 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); + + session_info = libspdm_get_session_info_via_session_id (spdm_context, session_id); + ((libspdm_secured_message_context_t*)(session_info->secured_message_context))-> + handshake_secret.response_handshake_sequence_number--; + } + return LIBSPDM_STATUS_SUCCESS; + case 0x19: { + spdm_finish_response_t *spdm_response; + libspdm_session_info_t *session_info; + size_t spdm_response_size; + size_t transport_header_size; + uint32_t session_id; + uint8_t *scratch_buffer; + size_t scratch_buffer_size; + uint16_t opaque_data_size; + uint8_t *ptr; + + transport_header_size = LIBSPDM_TEST_TRANSPORT_HEADER_SIZE; + + opaque_data_size = 8; + /* The ResponderVerifyData field does absent.*/ + spdm_response_size = sizeof(spdm_finish_response_t) + sizeof(uint16_t) + opaque_data_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_FINISH_RSP; + spdm_response->header.param1 = 0; + spdm_response->header.param2 = 0; + ptr = (uint8_t *)spdm_response + sizeof(spdm_finish_response_t); + libspdm_write_uint16(ptr, opaque_data_size); + session_id = 0xFFFFFFFF; /* For secure message, message is in sender buffer, we need copy it to scratch buffer. * transport_message is always in sender buffer. */ @@ -3827,6 +3870,113 @@ void libspdm_test_requester_finish_case24(void **state) free(data); } +/** + * Test 25: SPDM version 1.4, with OpaqueData + * Expected behavior: client returns a Status of RETURN_SUCCESS and + * session is established. + **/ +void libspdm_test_requester_finish_case25(void **state) +{ + libspdm_return_t status; + libspdm_test_context_t *spdm_test_context; + libspdm_context_t *spdm_context; + uint32_t session_id; + uint8_t req_slot_id_param; + void *data; + size_t data_size; + void *hash; + size_t hash_size; + libspdm_session_info_t *session_info; + libspdm_secured_message_context_t *secured_message_context; + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 0x19; + 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_KEY_EX_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_KEY_EX_CAP; + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_ENCRYPT_CAP; + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MAC_CAP; + libspdm_read_responder_public_certificate_chain(m_libspdm_use_hash_algo, + m_libspdm_use_asym_algo, &data, + &data_size, &hash, &hash_size); + 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; + +#if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT + spdm_context->connection_info.peer_used_cert_chain[0].buffer_size = + data_size; + libspdm_copy_mem(spdm_context->connection_info.peer_used_cert_chain[0].buffer, + sizeof(spdm_context->connection_info.peer_used_cert_chain[0].buffer), + data, data_size); +#else + libspdm_hash_all( + m_libspdm_use_hash_algo, + data, data_size, + spdm_context->connection_info.peer_used_cert_chain[0].buffer_hash); + spdm_context->connection_info.peer_used_cert_chain[0].buffer_hash_size = + libspdm_get_hash_size(m_libspdm_use_hash_algo); + libspdm_get_leaf_cert_public_key_from_cert_chain( + m_libspdm_use_hash_algo, + spdm_context->connection_info.algorithm.base_asym_algo, + data, data_size, + &spdm_context->connection_info.peer_used_cert_chain[0].leaf_cert_public_key); +#endif + spdm_context->connection_info.peer_used_cert_chain_slot_id = 0; + + /* Set HANDSHAKE_IN_THE_CLEAR_CAP to 0*/ + spdm_context->connection_info.capability.flags &= + ~SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP; + spdm_context->local_context.capability.flags &= + ~SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP; + + session_id = 0xFFFFFFFF; + session_info = &spdm_context->session_info[0]; + spdm_context->last_spdm_request_session_id_valid = true; + spdm_context->last_spdm_request_session_id = session_id; + libspdm_session_info_init(spdm_context, session_info, session_id, false); + 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_response_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); + + req_slot_id_param = 0; + status = libspdm_send_receive_finish(spdm_context, session_id, req_slot_id_param); + 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_ESTABLISHED); + + secured_message_context = session_info->secured_message_context; + + assert_memory_equal((const void *)secured_message_context->master_secret.master_secret, + (const void *)m_libspdm_zero_buffer, sizeof(m_libspdm_zero_buffer)); + free(data); +} + int libspdm_requester_finish_test_main(void) { const struct CMUnitTest spdm_requester_finish_tests[] = { @@ -3873,6 +4023,8 @@ int libspdm_requester_finish_test_main(void) cmocka_unit_test(libspdm_test_requester_finish_case23), /* Set HANDSHAKE_IN_THE_CLEAR_CAP to 0 , The ResponderVerifyData field is absent.*/ cmocka_unit_test(libspdm_test_requester_finish_case24), + /* SPDM 1.4 with OpaqueData */ + cmocka_unit_test(libspdm_test_requester_finish_case25), }; libspdm_test_context_t test_context = { diff --git a/unit_test/test_spdm_requester/psk_finish.c b/unit_test/test_spdm_requester/psk_finish.c index 58007d303c0..2ff62270a30 100644 --- a/unit_test/test_spdm_requester/psk_finish.c +++ b/unit_test/test_spdm_requester/psk_finish.c @@ -1,6 +1,6 @@ /** * Copyright Notice: - * Copyright 2021-2022 DMTF. All rights reserved. + * Copyright 2021-2025 DMTF. All rights reserved. * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md **/ @@ -86,7 +86,9 @@ libspdm_return_t libspdm_requester_psk_finish_test_send_message(void *spdm_conte return LIBSPDM_STATUS_SUCCESS; case 0xF: return LIBSPDM_STATUS_SUCCESS; - case 0x10: { + case 0x10: + case 0x11: + { libspdm_return_t status; uint8_t *decoded_message; size_t decoded_message_size; @@ -901,6 +903,58 @@ libspdm_return_t libspdm_requester_psk_finish_test_receive_message( } return LIBSPDM_STATUS_SUCCESS; + case 0x11: { + 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 = 8; + spdm_response_size = sizeof(spdm_psk_finish_response_t) + sizeof(uint16_t) + opaque_data_size; + 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); + + /* 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_copy_mem(&m_libspdm_local_buffer[m_libspdm_local_buffer_size], + sizeof(m_libspdm_local_buffer) - m_libspdm_local_buffer_size, + spdm_response, spdm_response_size); + m_libspdm_local_buffer_size += spdm_response_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; + } + /* WALKAROUND: If just use single context to encode message and then decode message */ + ((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; } @@ -2467,6 +2521,90 @@ void libspdm_test_requester_psk_finish_case16(void **state) free(data); } +/** + * Test 17: SPDM version 1.4, with OpaqueData + * Expected Behavior: requester returns the status RETURN_SUCCESS and a PSK_FINISH_RSP message is + * received. + **/ +void libspdm_test_requester_psk_finish_case17(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 = 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_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; + libspdm_read_responder_public_certificate_chain(m_libspdm_use_hash_algo, + m_libspdm_use_asym_algo, &data, + &data_size, &hash, &hash_size); + 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; + + session_id = 0xFFFFFFFF; + session_info = &spdm_context->session_info[0]; + libspdm_session_info_init(spdm_context, session_info, session_id, 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_SUCCESS); + assert_int_equal( + libspdm_secured_message_get_session_state( + spdm_context->session_info[0].secured_message_context), + LIBSPDM_SESSION_STATE_ESTABLISHED); + + free(data); +} + int libspdm_requester_psk_finish_test_main(void) { const struct CMUnitTest spdm_requester_psk_finish_tests[] = { @@ -2502,6 +2640,8 @@ int libspdm_requester_psk_finish_test_main(void) cmocka_unit_test(libspdm_test_requester_psk_finish_case15), /* Buffer verification*/ cmocka_unit_test(libspdm_test_requester_psk_finish_case16), + /* SPDM 1.4 with OpaqueData */ + cmocka_unit_test(libspdm_test_requester_psk_finish_case17), }; libspdm_test_context_t test_context = { From 9c90724a1224bab2f79a309802a5dfde5d43e565 Mon Sep 17 00:00:00 2001 From: Jiewen Yao Date: Fri, 18 Jul 2025 12:16:29 +0800 Subject: [PATCH 5/5] 1.4 Add unit test for FINISH/PSK_FINISH responder Signed-off-by: Jiewen Yao --- unit_test/test_spdm_responder/finish.c | 141 +++++++++++++++++++++ unit_test/test_spdm_responder/psk_finish.c | 119 ++++++++++++++++- 2 files changed, 259 insertions(+), 1 deletion(-) diff --git a/unit_test/test_spdm_responder/finish.c b/unit_test/test_spdm_responder/finish.c index 1595944e0a4..50bf47427c8 100644 --- a/unit_test/test_spdm_responder/finish.c +++ b/unit_test/test_spdm_responder/finish.c @@ -16,6 +16,14 @@ typedef struct { uint8_t verify_data[LIBSPDM_MAX_HASH_SIZE]; } libspdm_finish_request_mine_t; +typedef struct { + spdm_message_header_t header; + uint16_t opaque_data_size; + uint8_t opaque_data[8]; + uint8_t signature[LIBSPDM_MAX_ASYM_KEY_SIZE]; + uint8_t verify_data[LIBSPDM_MAX_HASH_SIZE]; +} libspdm_finish_request_mine_14_t; + #pragma pack() libspdm_finish_request_mine_t m_libspdm_finish_request1 = { @@ -48,6 +56,11 @@ libspdm_finish_request_mine_t m_libspdm_finish_request7 = { }; size_t m_libspdm_finish_request7_size = sizeof(m_libspdm_finish_request7); +libspdm_finish_request_mine_14_t m_libspdm_finish_request8 = { + { SPDM_MESSAGE_VERSION_14, SPDM_FINISH, 0, 0 }, +}; +size_t m_libspdm_finish_request8_size = sizeof(m_libspdm_finish_request8); + uint8_t m_dummy_buffer[LIBSPDM_MAX_HASH_SIZE]; #if LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP @@ -3834,6 +3847,132 @@ void libspdm_test_responder_finish_case29(void **state) free(data1); } +/** + * Test 30: SPDM version 1.4, with OpaqueData. + * Expected behavior: the responder accepts the request and produces a valid + * FINISH_RSP response message. + **/ +void libspdm_test_responder_finish_case30(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 = 30; + 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; + 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; + spdm_context->connection_info.local_used_cert_chain_buffer = data1; + spdm_context->connection_info.local_used_cert_chain_buffer_size = + data_size1; + + libspdm_reset_message_a(spdm_context); + spdm_context->local_context.mut_auth_requested = 0; + + /* 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, false); + + 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(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); + free(data1); +} + int libspdm_responder_finish_test_main(void) { const struct CMUnitTest spdm_responder_finish_tests[] = { @@ -3893,6 +4032,8 @@ int libspdm_responder_finish_test_main(void) cmocka_unit_test_setup(libspdm_test_responder_finish_case28, libspdm_unit_test_group_setup), /* The requester and responder have not set HANDSHAKE_IN_THE_CLEAR*/ cmocka_unit_test(libspdm_test_responder_finish_case29), + /* SPDM 1.4 with OpaqueData */ + cmocka_unit_test(libspdm_test_responder_finish_case30), }; libspdm_test_context_t test_context = { diff --git a/unit_test/test_spdm_responder/psk_finish.c b/unit_test/test_spdm_responder/psk_finish.c index bcdb434d88e..aee3e5ee0db 100644 --- a/unit_test/test_spdm_responder/psk_finish.c +++ b/unit_test/test_spdm_responder/psk_finish.c @@ -1,6 +1,6 @@ /** * Copyright Notice: - * Copyright 2021-2022 DMTF. All rights reserved. + * Copyright 2021-2025 DMTF. All rights reserved. * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md **/ @@ -14,6 +14,13 @@ typedef struct { spdm_message_header_t header; uint8_t verify_data[LIBSPDM_MAX_HASH_SIZE]; } libspdm_psk_finish_request_mine_t; + +typedef struct { + spdm_message_header_t header; + uint16_t opaque_data_size; + uint8_t opaque_data[8]; + uint8_t verify_data[LIBSPDM_MAX_HASH_SIZE]; +} libspdm_psk_finish_request_mine_14_t; #pragma pack() static libspdm_th_managed_buffer_t th_curr; @@ -28,6 +35,11 @@ libspdm_psk_finish_request_mine_t m_libspdm_psk_finish_request2 = { }; size_t m_libspdm_psk_finish_request2_size = LIBSPDM_MAX_SPDM_MSG_SIZE; +libspdm_psk_finish_request_mine_14_t m_libspdm_psk_finish_request3 = { + { SPDM_MESSAGE_VERSION_14, SPDM_PSK_FINISH, 0, 0 }, +}; +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]; static void libspdm_secured_message_set_request_finished_key( @@ -1497,6 +1509,8 @@ void libspdm_test_responder_psk_finish_case14(void **state) spdm_test_context = *state; spdm_context = spdm_test_context->spdm_context; spdm_test_context->case_id = 0xE; + spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_11 << + SPDM_VERSION_NUMBER_SHIFT_BIT; spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_NEGOTIATED; spdm_context->connection_info.capability.flags |= @@ -1572,6 +1586,107 @@ void libspdm_test_responder_psk_finish_case14(void **state) free(data1); } +/** + * Test 15: SPDM version 1.4, with OpaqueData. + * Expected behavior: the responder accepts the request and produces a valid PSK_FINISH + * response message. + **/ +void libspdm_test_responder_psk_finish_case15(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 = 0xF; + 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; + 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; + spdm_context->connection_info.local_used_cert_chain_buffer = data1; + spdm_context->connection_info.local_used_cert_chain_buffer_size = data_size1; + + libspdm_reset_message_a(spdm_context); + spdm_context->local_context.mut_auth_requested = 0; + + session_id = 0xFFFFFFFF; + spdm_context->latest_session_id = session_id; + spdm_context->last_spdm_request_session_id_valid = true; + spdm_context->last_spdm_request_session_id = session_id; + session_info = &spdm_context->session_info[0]; + libspdm_session_info_init(spdm_context, session_info, session_id, true); + libspdm_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(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); + + free(data1); +} + int libspdm_responder_psk_finish_test_main(void) { const struct CMUnitTest spdm_responder_psk_finish_tests[] = { @@ -1603,6 +1718,8 @@ int libspdm_responder_psk_finish_test_main(void) cmocka_unit_test(libspdm_test_responder_psk_finish_case13), /* Buffer verification*/ cmocka_unit_test(libspdm_test_responder_psk_finish_case14), + /* SPDM 1.4 with OpaqueData */ + cmocka_unit_test(libspdm_test_responder_psk_finish_case15), }; libspdm_test_context_t test_context = {