From 0995be1d38ac6045cc93d31d08b74e557fd46df4 Mon Sep 17 00:00:00 2001
From: Aaron Li <aaron.li@intel.com>
Date: Tue, 7 Jan 2025 11:09:27 +0800
Subject: [PATCH 1/4] Fix chunk_seq_no wrap in chunk send.

Fix #2875

Signed-off-by: Aaron Li <aaron.li@intel.com>
---
 .../libspdm_req_send_receive.c                | 21 +++--
 unit_test/test_spdm_requester/chunk_send.c    | 78 ++++++++++++++++++-
 2 files changed, 93 insertions(+), 6 deletions(-)

diff --git a/library/spdm_requester_lib/libspdm_req_send_receive.c b/library/spdm_requester_lib/libspdm_req_send_receive.c
index 8639de04129..7db85c129f4 100644
--- a/library/spdm_requester_lib/libspdm_req_send_receive.c
+++ b/library/spdm_requester_lib/libspdm_req_send_receive.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
  **/
 
@@ -316,6 +316,7 @@ libspdm_return_t libspdm_handle_large_request(
     size_t copy_size;
     libspdm_chunk_info_t *send_info;
     uint32_t min_data_transfer_size;
+    uint64_t max_chunk_data_transfer_size;
     spdm_error_response_t *spdm_error;
 
     if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_12) {
@@ -330,6 +331,20 @@ libspdm_return_t libspdm_handle_large_request(
         return LIBSPDM_STATUS_ERROR_PEER;
     }
 
+    /* Fail if exceed max chunks */
+    min_data_transfer_size = LIBSPDM_MIN(
+        spdm_context->connection_info.capability.data_transfer_size,
+        spdm_context->local_context.capability.sender_data_transfer_size);
+
+    max_chunk_data_transfer_size =
+        ((size_t) min_data_transfer_size - sizeof(spdm_chunk_send_request_t)) * 65536 -
+        sizeof(uint32_t);
+    /* max_spdm_msg_size is already checked in caller */
+
+    if (request_size > max_chunk_data_transfer_size) {
+        return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
+    }
+
     /* now we can get sender buffer */
     transport_header_size = spdm_context->local_context.capability.transport_header_size;
 
@@ -359,10 +374,6 @@ libspdm_return_t libspdm_handle_large_request(
     request = NULL; /* Invalidate to prevent accidental use. */
     request_size = 0;
 
-    min_data_transfer_size = LIBSPDM_MIN(
-        spdm_context->connection_info.capability.data_transfer_size,
-        spdm_context->local_context.capability.sender_data_transfer_size);
-
     do {
         LIBSPDM_ASSERT(send_info->large_message_capacity >= transport_header_size);
         spdm_request = (spdm_chunk_send_request_t *)((uint8_t *)message + transport_header_size);
diff --git a/unit_test/test_spdm_requester/chunk_send.c b/unit_test/test_spdm_requester/chunk_send.c
index b66e411754f..9aa312fdfb2 100644
--- a/unit_test/test_spdm_requester/chunk_send.c
+++ b/unit_test/test_spdm_requester/chunk_send.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
  **/
 
@@ -105,6 +105,10 @@ libspdm_return_t libspdm_requester_chunk_send_test_send_message(
         LIBSPDM_ASSERT(chunk_send->header.request_response_code == SPDM_CHUNK_SEND);
         return LIBSPDM_STATUS_SUCCESS;
     }
+    if (spdm_test_context->case_id == 13) {
+        /* Should never reach here since the test case is meant to fail before send */
+        LIBSPDM_ASSERT(0);
+    }
     return LIBSPDM_STATUS_SEND_FAIL;
 }
 
@@ -323,6 +327,10 @@ libspdm_return_t libspdm_requester_chunk_send_test_receive_message(
 
         return LIBSPDM_STATUS_SUCCESS;
     }
+    if (spdm_test_context->case_id == 13) {
+        /* Should never reach here since the test case is meant to fail before send */
+        LIBSPDM_ASSERT(0);
+    }
     return LIBSPDM_STATUS_RECEIVE_FAIL;
 }
 
@@ -380,6 +388,56 @@ libspdm_return_t libspdm_test_requester_chunk_send_generic_test_case(
     return status;
 }
 
+libspdm_return_t libspdm_test_requester_chunk_send_vendor_specific_test_case(
+    void** state, uint32_t case_id)
+{
+    /* Use vendor specific request to generate a large request. */
+    libspdm_return_t status;
+    libspdm_test_context_t* spdm_test_context;
+    libspdm_context_t* spdm_context;
+
+    uint16_t standard_id = 6;
+    uint8_t vendor_id_len = 2;
+    uint8_t vendor_id[SPDM_MAX_VENDOR_ID_LENGTH] = {0xAA, 0xAA};
+    uint16_t data_len = 65535;
+    uint8_t data[65535] = {0};
+
+    spdm_test_context = *state;
+    spdm_context = spdm_test_context->spdm_context;
+    spdm_test_context->case_id = case_id;
+    spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
+                                            SPDM_VERSION_NUMBER_SHIFT_BIT;
+    /* Large request need a large scratch buffer. */
+    spdm_context->connection_info.capability.max_spdm_msg_size = 0x12000;
+    spdm_context->local_context.capability.max_spdm_msg_size = 0x12000;
+    spdm_context->connection_info.connection_state =
+        LIBSPDM_CONNECTION_STATE_NEGOTIATED;
+    spdm_context->connection_info.capability.flags |=
+        (SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP
+         | SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP);
+    spdm_context->connection_info.capability.data_transfer_size
+        = sizeof(spdm_chunk_send_request_t) + 1;
+    spdm_context->local_context.capability.sender_data_transfer_size
+        = CHUNK_SEND_REQUESTER_UNIT_TEST_DATA_TRANSFER_SIZE;
+    spdm_context->local_context.is_requester = true;
+
+    spdm_test_context->scratch_buffer_size =
+        libspdm_get_sizeof_required_scratch_buffer(spdm_context);
+    spdm_test_context->scratch_buffer = (void *)malloc(spdm_test_context->scratch_buffer_size);
+    libspdm_set_scratch_buffer (spdm_context,
+                                spdm_test_context->scratch_buffer,
+                                spdm_test_context->scratch_buffer_size);
+
+    libspdm_reset_message_a(spdm_context);
+
+    status = libspdm_vendor_send_request_receive_response(spdm_context, NULL,
+                                                          standard_id, vendor_id_len, vendor_id,
+                                                          data_len, data,
+                                                          &standard_id, &vendor_id_len, vendor_id,
+                                                          &data_len, data);
+    return status;
+}
+
 void libspdm_test_requester_chunk_send_case1(void** state)
 {
     libspdm_return_t status;
@@ -472,6 +530,20 @@ void libspdm_test_requester_chunk_send_case12(void** state)
     assert_int_equal(status, LIBSPDM_STATUS_ERROR_PEER);
 }
 
+#if LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES
+/**
+ * Test 13: Request size shall not exceed max supported transfer size.
+ * Expected behavior: returns a status of LIBSPDM_STATUS_SEND_FAIL,
+ **/
+void libspdm_test_requester_chunk_send_case13(void** state)
+{
+    libspdm_return_t status;
+
+    status = libspdm_test_requester_chunk_send_vendor_specific_test_case(state, 13);
+    assert_int_equal(status, LIBSPDM_STATUS_SEND_FAIL);
+}
+#endif
+
 int libspdm_requester_chunk_send_test_main(void)
 {
     /* Test the CHUNK_SEND handlers in various requester handlers */
@@ -500,6 +572,10 @@ int libspdm_requester_chunk_send_test_main(void)
         cmocka_unit_test(libspdm_test_requester_chunk_send_case11),
         /* ErrorCode == LargeResponse shall not be allowed in ResponseToLargeRequest */
         cmocka_unit_test(libspdm_test_requester_chunk_send_case12),
+#if LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES
+        /* Request size exceed max chunks */
+        cmocka_unit_test(libspdm_test_requester_chunk_send_case13),
+#endif
     };
 
     libspdm_test_context_t test_context = {

From 63642f1cfdaaa975cd36a77d17c65932be0a033e Mon Sep 17 00:00:00 2001
From: Aaron Li <aaron.li@intel.com>
Date: Tue, 7 Jan 2025 14:24:07 +0800
Subject: [PATCH 2/4] Fix chunk_seq_no wrap in chunk send ack.

Fix #2875

Signed-off-by: Aaron Li <aaron.li@intel.com>
---
 .../libspdm_rsp_chunk_send_ack.c              |  10 +-
 .../test_spdm_responder/chunk_send_ack.c      | 165 +++++++++++++++++-
 2 files changed, 173 insertions(+), 2 deletions(-)

diff --git a/library/spdm_responder_lib/libspdm_rsp_chunk_send_ack.c b/library/spdm_responder_lib/libspdm_rsp_chunk_send_ack.c
index 94aa6b02415..941dba1148e 100644
--- a/library/spdm_responder_lib/libspdm_rsp_chunk_send_ack.c
+++ b/library/spdm_responder_lib/libspdm_rsp_chunk_send_ack.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
  **/
 
@@ -25,6 +25,7 @@ libspdm_return_t libspdm_get_response_chunk_send(libspdm_context_t *spdm_context
     size_t scratch_buffer_size;
     uint8_t* chunk_response;
     size_t chunk_response_size;
+    uint64_t max_chunk_data_transfer_size;
 
     spdm_request = (const spdm_chunk_send_request_t*) request;
 
@@ -103,6 +104,9 @@ libspdm_return_t libspdm_get_response_chunk_send(libspdm_context_t *spdm_context
         chunk = (((const uint8_t*) (spdm_request + 1)) + sizeof(uint32_t));
         calc_max_chunk_size =
             (uint32_t)request_size - (sizeof(spdm_chunk_send_request_t) + sizeof(uint32_t));
+        max_chunk_data_transfer_size =
+            ((size_t) spdm_context->local_context.capability.data_transfer_size
+             - sizeof(spdm_chunk_send_request_t)) * 65536 - sizeof(uint32_t);
 
         if (spdm_request->chunk_seq_no != 0
             || (spdm_request->chunk_size
@@ -112,6 +116,7 @@ libspdm_return_t libspdm_get_response_chunk_send(libspdm_context_t *spdm_context
             || spdm_request->chunk_size > calc_max_chunk_size
             || (uint32_t)request_size > spdm_context->local_context.capability.data_transfer_size
             || large_message_size > spdm_context->local_context.capability.max_spdm_msg_size
+            || large_message_size > max_chunk_data_transfer_size
             || large_message_size <= SPDM_MIN_DATA_TRANSFER_SIZE_VERSION_12
             || (spdm_request->header.param1 & SPDM_CHUNK_SEND_REQUEST_ATTRIBUTE_LAST_CHUNK)
             ) {
@@ -160,6 +165,9 @@ libspdm_return_t libspdm_get_response_chunk_send(libspdm_context_t *spdm_context
                        || ((uint32_t) request_size
                            > spdm_context->local_context.capability.data_transfer_size))) {
             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
+        } else if (spdm_request->chunk_seq_no == 0) {
+            /* Chunk seq no wrapped */
+            status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
         } else {
 
             libspdm_copy_mem(
diff --git a/unit_test/test_spdm_responder/chunk_send_ack.c b/unit_test/test_spdm_responder/chunk_send_ack.c
index f392daa61fb..c5628acbc3a 100644
--- a/unit_test/test_spdm_responder/chunk_send_ack.c
+++ b/unit_test/test_spdm_responder/chunk_send_ack.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
  **/
 
@@ -1705,6 +1705,165 @@ void libspdm_test_responder_chunk_send_ack_rsp_case19(void** state)
     libspdm_test_responder_chunk_send_ack_reset_send_state(spdm_context);
 }
 
+/**
+ *  Test 20: Request chunk seq wrapped.
+ **/
+void libspdm_test_responder_chunk_send_ack_rsp_case20(void** state)
+{
+    libspdm_return_t status;
+
+    libspdm_test_context_t* spdm_test_context;
+    libspdm_context_t* spdm_context;
+
+    size_t request_size;
+    size_t response_size;
+
+    uint8_t request[LIBSPDM_MAX_SPDM_MSG_SIZE];
+    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
+
+    spdm_chunk_send_request_t* chunk_send_request;
+    spdm_chunk_send_ack_response_t* chunk_send_ack_response;
+    spdm_error_response_t* error_response;
+
+    const uint8_t* chunk_src;
+    uint8_t* chunk_dst;
+
+    /* Format the last chunk. */
+    spdm_test_context = *state;
+    spdm_context = spdm_test_context->spdm_context;
+    spdm_test_context->case_id = 20;
+
+    libspdm_test_responder_chunk_send_ack_setup_algo_state(spdm_context);
+    spdm_context->chunk_context.send.chunk_in_use = true;
+    spdm_context->chunk_context.send.chunk_handle = (uint8_t) spdm_test_context->case_id;
+    spdm_context->chunk_context.send.chunk_seq_no = 65535; /* maximum chunk seq received */
+    spdm_context->chunk_context.send.large_message_size = 0x10000;
+    spdm_context->chunk_context.send.chunk_bytes_transferred = 0x8000;
+
+    chunk_src = (const uint8_t*) &m_libspdm_chunk_send_negotiate_algorithm_request1;
+
+    libspdm_zero_mem(request, sizeof(request));
+    chunk_send_request = (spdm_chunk_send_request_t*) request;
+
+    chunk_send_request->header.spdm_version = SPDM_MESSAGE_VERSION_12;
+    chunk_send_request->header.request_response_code = SPDM_CHUNK_SEND;
+    chunk_send_request->header.param1 = 0;
+    chunk_send_request->header.param2 = (uint8_t) spdm_test_context->case_id; /* chunk_handle */
+    chunk_send_request->chunk_seq_no = 0; /* chunk seq wrapped */
+
+    chunk_send_request->chunk_size =
+        spdm_context->local_context.capability.data_transfer_size
+        - sizeof(spdm_chunk_send_request_t);
+
+    chunk_dst = ((uint8_t*) (chunk_send_request + 1));
+
+    request_size = sizeof(spdm_chunk_send_request_t)
+                   + chunk_send_request->chunk_size;
+
+    libspdm_copy_mem(chunk_dst, chunk_send_request->chunk_size,
+                     chunk_src, chunk_send_request->chunk_size);
+
+    response_size = sizeof(response);
+    status = libspdm_get_response_chunk_send(
+        spdm_context,
+        request_size, request,
+        &response_size, response);
+
+    assert_int_equal(status, LIBSPDM_STATUS_INVALID_MSG_FIELD);
+    assert_true(response_size == sizeof(spdm_chunk_send_ack_response_t)
+                + sizeof(spdm_error_response_t));
+
+    chunk_send_ack_response = (spdm_chunk_send_ack_response_t*) response;
+    assert_int_equal(chunk_send_ack_response->header.param1,
+                     SPDM_CHUNK_SEND_ACK_RESPONSE_ATTRIBUTE_EARLY_ERROR_DETECTED);
+
+    error_response = (spdm_error_response_t*) (chunk_send_ack_response + 1);
+    assert_int_equal(error_response->header.spdm_version, SPDM_MESSAGE_VERSION_12);
+    assert_int_equal(error_response->header.request_response_code, SPDM_ERROR);
+    assert_int_equal(error_response->header.param1, SPDM_ERROR_CODE_INVALID_REQUEST);
+    assert_int_equal(error_response->header.param2, 0);
+
+    libspdm_test_responder_chunk_send_ack_reset_send_state(spdm_context);
+}
+
+/**
+ *  Test 21: Request size exceed max chunk seq no.
+ **/
+void libspdm_test_responder_chunk_send_ack_rsp_case21(void** state)
+{
+    libspdm_return_t status;
+
+    libspdm_test_context_t* spdm_test_context;
+    libspdm_context_t* spdm_context;
+
+    size_t request_size;
+    size_t response_size;
+
+    uint8_t request[LIBSPDM_MAX_SPDM_MSG_SIZE];
+    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
+
+    spdm_chunk_send_request_t* chunk_send_request;
+    spdm_chunk_send_ack_response_t* chunk_send_ack_response;
+    spdm_error_response_t* error_response;
+
+    const uint8_t* chunk_src;
+    uint8_t* chunk_dst;
+
+    /* Format the last chunk. */
+    spdm_test_context = *state;
+    spdm_context = spdm_test_context->spdm_context;
+    spdm_test_context->case_id = 21;
+
+    libspdm_test_responder_chunk_send_ack_setup_algo_state(spdm_context);
+    chunk_src = (const uint8_t*) &m_libspdm_chunk_send_negotiate_algorithm_request1;
+
+    libspdm_zero_mem(request, sizeof(request));
+    chunk_send_request = (spdm_chunk_send_request_t*) request;
+
+    chunk_send_request->header.spdm_version = SPDM_MESSAGE_VERSION_12;
+    chunk_send_request->header.request_response_code = SPDM_CHUNK_SEND;
+    chunk_send_request->header.param1 = 0;
+    chunk_send_request->header.param2 = (uint8_t) spdm_test_context->case_id; /* chunk_handle */
+    chunk_send_request->chunk_seq_no = 0;
+
+
+    *((uint32_t*) (chunk_send_request + 1)) = 0x1000000; /* a size exceed max chunk seq */
+    chunk_send_request->chunk_size =
+        spdm_context->local_context.capability.data_transfer_size
+        - sizeof(spdm_chunk_send_request_t) - sizeof(uint32_t);
+
+    chunk_dst = ((uint8_t*) (chunk_send_request + 1)) + sizeof(uint32_t);
+
+    request_size = sizeof(spdm_chunk_send_request_t)
+                   + sizeof(uint32_t)
+                   + chunk_send_request->chunk_size;
+
+    libspdm_copy_mem(chunk_dst, chunk_send_request->chunk_size,
+                     chunk_src, chunk_send_request->chunk_size);
+
+    response_size = sizeof(response);
+    status = libspdm_get_response_chunk_send(
+        spdm_context,
+        request_size, request,
+        &response_size, response);
+
+    assert_int_equal(status, LIBSPDM_STATUS_INVALID_MSG_FIELD);
+    assert_true(response_size == sizeof(spdm_chunk_send_ack_response_t)
+                + sizeof(spdm_error_response_t));
+
+    chunk_send_ack_response = (spdm_chunk_send_ack_response_t*) response;
+    assert_int_equal(chunk_send_ack_response->header.param1,
+                     SPDM_CHUNK_SEND_ACK_RESPONSE_ATTRIBUTE_EARLY_ERROR_DETECTED);
+
+    error_response = (spdm_error_response_t*) (chunk_send_ack_response + 1);
+    assert_int_equal(error_response->header.spdm_version, SPDM_MESSAGE_VERSION_12);
+    assert_int_equal(error_response->header.request_response_code, SPDM_ERROR);
+    assert_int_equal(error_response->header.param1, SPDM_ERROR_CODE_INVALID_REQUEST);
+    assert_int_equal(error_response->header.param2, 0);
+
+    libspdm_test_responder_chunk_send_ack_reset_send_state(spdm_context);
+}
+
 int libspdm_responder_chunk_send_ack_test_main(void)
 {
     const struct CMUnitTest spdm_responder_chunk_send_ack_tests[] = {
@@ -1750,6 +1909,10 @@ int libspdm_responder_chunk_send_ack_test_main(void)
         cmocka_unit_test(libspdm_test_responder_chunk_send_ack_rsp_case18),
         /* Request missing LAST_CHUNK when request size != data transfer size. */
         cmocka_unit_test(libspdm_test_responder_chunk_send_ack_rsp_case19),
+        /* Request chunk seq warpped. */
+        cmocka_unit_test(libspdm_test_responder_chunk_send_ack_rsp_case20),
+        /* Request size exceed max chunk seq no. */
+        cmocka_unit_test(libspdm_test_responder_chunk_send_ack_rsp_case21),
     };
 
     libspdm_test_context_t test_context = {

From 8d1e90048a7b2f290e9f2a7362cb6e0fc2261b15 Mon Sep 17 00:00:00 2001
From: Aaron Li <aaron.li@intel.com>
Date: Wed, 8 Jan 2025 14:19:20 +0800
Subject: [PATCH 3/4] Fix chunk_seq_no wrap in chunk get.

Fix #2875

Signed-off-by: Aaron Li <aaron.li@intel.com>
---
 .../libspdm_req_handle_error_response.c       | 17 +++-
 unit_test/test_spdm_requester/chunk_get.c     | 93 ++++++++++++++++++-
 2 files changed, 108 insertions(+), 2 deletions(-)

diff --git a/library/spdm_requester_lib/libspdm_req_handle_error_response.c b/library/spdm_requester_lib/libspdm_req_handle_error_response.c
index 262b844a079..8a135d4a7f0 100644
--- a/library/spdm_requester_lib/libspdm_req_handle_error_response.c
+++ b/library/spdm_requester_lib/libspdm_req_handle_error_response.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
  **/
 
@@ -225,6 +225,7 @@ libspdm_return_t libspdm_handle_error_large_response(
     size_t large_response_capacity;
     size_t large_response_size;
     size_t large_response_size_so_far;
+    uint64_t max_chunk_data_transfer_size;
 
     if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_12) {
         return LIBSPDM_STATUS_UNSUPPORTED_CAP;
@@ -262,6 +263,10 @@ libspdm_return_t libspdm_handle_error_large_response(
     message = scratch_buffer + libspdm_get_scratch_buffer_sender_receiver_offset(spdm_context);
     message_size = libspdm_get_scratch_buffer_sender_receiver_capacity(spdm_context);
 
+    max_chunk_data_transfer_size =
+        ((size_t) spdm_context->local_context.capability.data_transfer_size
+         - sizeof(spdm_chunk_response_response_t)) * 65536 - sizeof(uint32_t);
+
     libspdm_zero_mem(large_response, large_response_capacity);
     large_response_size = 0;
     large_response_size_so_far = 0;
@@ -280,6 +285,12 @@ libspdm_return_t libspdm_handle_error_large_response(
         spdm_request->chunk_seq_no = chunk_seq_no;
         spdm_request_size = sizeof(spdm_chunk_get_request_t);
 
+        if (chunk_seq_no == 0 && large_response_size_so_far != 0) {
+            /* chunk_seq_no wrapped */
+            status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
+            break;
+        }
+
         LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
                        "CHUNK_GET Handle %d SeqNo %d\n", chunk_handle, chunk_seq_no));
 
@@ -346,6 +357,10 @@ libspdm_return_t libspdm_handle_error_large_response(
                 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
                 break;
             }
+            if (large_response_size > max_chunk_data_transfer_size) {
+                status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
+                break;
+            }
             if (large_response_size <= SPDM_MIN_DATA_TRANSFER_SIZE_VERSION_12) {
                 status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
                 break;
diff --git a/unit_test/test_spdm_requester/chunk_get.c b/unit_test/test_spdm_requester/chunk_get.c
index 90827206948..68873710b43 100644
--- a/unit_test/test_spdm_requester/chunk_get.c
+++ b/unit_test/test_spdm_requester/chunk_get.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
  **/
 
@@ -15,6 +15,10 @@ static size_t m_libspdm_local_certificate_chain_size_test_case_1;
 
 static uint8_t m_libspdm_local_large_response_buffer[LIBSPDM_MAX_SPDM_MSG_SIZE];
 
+#define BUFFER_SIZE_FOR_CHUNK_SEQ_NO_WRAP_TEST 0x200000
+static uint8_t m_libspdm_local_response_buffer_for_chunk_seq_no_wrap_test[
+    BUFFER_SIZE_FOR_CHUNK_SEQ_NO_WRAP_TEST];
+
 static size_t m_libspdm_local_buffer_size;
 static uint8_t m_libspdm_local_buffer[LIBSPDM_MAX_MESSAGE_M1M2_BUFFER_SIZE];
 
@@ -259,6 +263,29 @@ void libspdm_requester_chunk_get_test_case4_build_digest_response(
     spdm_response->header.param2 |= (0xFF << 0);
 }
 
+void libspdm_requester_chunk_get_test_case5_build_vendor_response(
+    void* context, void* response, size_t* response_size)
+{
+    spdm_vendor_defined_response_msg_t *spdm_response;
+
+    /* For exceed max chunk seq no */
+    *response_size =
+        (CHUNK_GET_REQUESTER_UNIT_TEST_DATA_TRANSFER_SIZE -
+         sizeof(spdm_chunk_response_response_t)) * 65536 - sizeof(uint32_t) + 0x10;
+
+    libspdm_set_mem(response, *response_size, 0xff);
+
+    spdm_response = response;
+
+    spdm_response->header.spdm_version = SPDM_MESSAGE_VERSION_12;
+    spdm_response->header.request_response_code = SPDM_VENDOR_DEFINED_RESPONSE;
+    spdm_response->header.param1 = 0;
+    spdm_response->header.param2 = 0;
+
+    spdm_response->standard_id = 6;
+    spdm_response->len = 2;
+}
+
 libspdm_return_t libspdm_requester_chunk_get_test_send_message(
     void* spdm_context, size_t request_size, const void* request,
     uint64_t timeout)
@@ -431,6 +458,9 @@ libspdm_return_t libspdm_requester_chunk_get_test_receive_message(
     } else if (spdm_test_context->case_id == 0x4) {
         build_response_func =
             libspdm_requester_chunk_get_test_case4_build_digest_response;
+    } else if (spdm_test_context->case_id == 0x5) {
+        build_response_func =
+            libspdm_requester_chunk_get_test_case5_build_vendor_response;
     } else {
         LIBSPDM_ASSERT(0);
         return LIBSPDM_STATUS_RECEIVE_FAIL;
@@ -453,6 +483,12 @@ libspdm_return_t libspdm_requester_chunk_get_test_receive_message(
 
             sub_rsp = (spdm_message_header_t*) m_libspdm_local_large_response_buffer;
             sub_rsp_size = sizeof(m_libspdm_local_large_response_buffer);
+            if (spdm_test_context->case_id == 0x5) {
+                sub_rsp =
+                    (spdm_message_header_t*)
+                    m_libspdm_local_response_buffer_for_chunk_seq_no_wrap_test;
+                sub_rsp_size = sizeof(m_libspdm_local_response_buffer_for_chunk_seq_no_wrap_test);
+            }
             libspdm_zero_mem(sub_rsp, sub_rsp_size);
 
             build_response_func(spdm_context, sub_rsp, &sub_rsp_size);
@@ -832,6 +868,57 @@ void libspdm_test_requester_chunk_get_case4(void** state)
 }
 #endif
 
+#if LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES
+static void libspdm_test_requester_chunk_get_case5(void **state)
+{
+    /* Copied from Vendor Request case 1*/
+    libspdm_return_t status;
+    libspdm_test_context_t *spdm_test_context;
+    libspdm_context_t *spdm_context;
+
+    uint16_t standard_id = 6;
+    uint8_t vendor_id_len = 2;
+    uint8_t vendor_id[SPDM_MAX_VENDOR_ID_LENGTH] = {0xAA, 0xAA};
+    uint16_t data_len = 16;
+    uint8_t data[16];
+
+    spdm_test_context = *state;
+    spdm_context = spdm_test_context->spdm_context;
+    spdm_test_context->case_id = 0x5;
+    spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
+                                            SPDM_VERSION_NUMBER_SHIFT_BIT;
+    /* Large response need a large scratch buffer. */
+    spdm_context->connection_info.capability.max_spdm_msg_size =
+        BUFFER_SIZE_FOR_CHUNK_SEQ_NO_WRAP_TEST;
+    spdm_context->local_context.capability.max_spdm_msg_size =
+        BUFFER_SIZE_FOR_CHUNK_SEQ_NO_WRAP_TEST;
+    spdm_context->connection_info.connection_state =
+        LIBSPDM_CONNECTION_STATE_NEGOTIATED;
+    spdm_context->connection_info.capability.data_transfer_size =
+        CHUNK_GET_REQUESTER_UNIT_TEST_DATA_TRANSFER_SIZE;
+    spdm_context->local_context.capability.sender_data_transfer_size =
+        CHUNK_GET_REQUESTER_UNIT_TEST_DATA_TRANSFER_SIZE;
+    spdm_context->local_context.is_requester = true;
+
+    spdm_test_context->scratch_buffer_size =
+        libspdm_get_sizeof_required_scratch_buffer(spdm_context);
+    spdm_test_context->scratch_buffer = (void *)malloc(spdm_test_context->scratch_buffer_size);
+    libspdm_set_scratch_buffer (spdm_context,
+                                spdm_test_context->scratch_buffer,
+                                spdm_test_context->scratch_buffer_size);
+
+    libspdm_set_mem(data, sizeof(data), 0xAA);
+
+    status = libspdm_vendor_send_request_receive_response(spdm_context, NULL,
+                                                          standard_id, vendor_id_len, vendor_id,
+                                                          data_len, data,
+                                                          &standard_id, &vendor_id_len, vendor_id,
+                                                          &data_len, data);
+
+    assert_int_equal(status, LIBSPDM_STATUS_RECEIVE_FAIL);
+}
+#endif /* LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES */
+
 int libspdm_requester_chunk_get_test_main(void)
 {
     /* Test the CHUNK_GET handlers in various requester handlers */
@@ -851,6 +938,10 @@ int libspdm_requester_chunk_get_test_main(void)
 #if LIBSPDM_SEND_GET_CERTIFICATE_SUPPORT
         /* Request Digests */
         cmocka_unit_test(libspdm_test_requester_chunk_get_case4),
+#endif
+#if LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES
+        /* Request Vendor Specific Response and chunk seq no wrapped */
+        cmocka_unit_test(libspdm_test_requester_chunk_get_case5),
 #endif
     };
 

From 4c2e63df57839edb26f8032687b742e5100cc729 Mon Sep 17 00:00:00 2001
From: Aaron Li <aaron.li@intel.com>
Date: Mon, 13 Jan 2025 09:54:38 +0800
Subject: [PATCH 4/4] Fix chunk_seq_no wrap in chunk get response.

Fix #2875

Signed-off-by: Aaron Li <aaron.li@intel.com>
---
 .../libspdm_rsp_chunk_get.c                   | 20 +++-
 unit_test/test_spdm_responder/chunk_get.c     | 99 ++++++++++++++++++-
 2 files changed, 115 insertions(+), 4 deletions(-)

diff --git a/library/spdm_responder_lib/libspdm_rsp_chunk_get.c b/library/spdm_responder_lib/libspdm_rsp_chunk_get.c
index 0fb140ee0b6..04f957501e3 100644
--- a/library/spdm_responder_lib/libspdm_rsp_chunk_get.c
+++ b/library/spdm_responder_lib/libspdm_rsp_chunk_get.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
  **/
 
@@ -17,6 +17,7 @@ libspdm_return_t libspdm_get_response_chunk_get(
 {
     libspdm_chunk_info_t* get_info;
     uint32_t min_data_transfer_size;
+    uint64_t max_chunk_data_transfer_size;
 
     const spdm_chunk_get_request_t* spdm_request;
     spdm_chunk_response_response_t* spdm_response;
@@ -103,12 +104,25 @@ libspdm_return_t libspdm_get_response_chunk_get(
             response_size, response);
     }
 
-    libspdm_zero_mem(response, *response_size);
-
     min_data_transfer_size = LIBSPDM_MIN(
         spdm_context->connection_info.capability.data_transfer_size,
         spdm_context->local_context.capability.sender_data_transfer_size);
 
+    /* Fail if exceed max chunks */
+    max_chunk_data_transfer_size =
+        ((size_t) min_data_transfer_size - sizeof(spdm_chunk_response_response_t)) * 65536 -
+        sizeof(uint32_t);
+    /* max_spdm_msg_size already checked in caller */
+
+    if (get_info->large_message_size > max_chunk_data_transfer_size) {
+        return libspdm_generate_error_response(
+            spdm_context,
+            SPDM_ERROR_CODE_RESPONSE_TOO_LARGE, 0,
+            response_size, response);
+    }
+
+    libspdm_zero_mem(response, *response_size);
+
     /* Assert the data transfer size is smaller than the response size.
      * Otherwise there is no reason to chunk this response. */
     LIBSPDM_ASSERT(min_data_transfer_size < *response_size);
diff --git a/unit_test/test_spdm_responder/chunk_get.c b/unit_test/test_spdm_responder/chunk_get.c
index cfc04574195..26017c0b3a4 100644
--- a/unit_test/test_spdm_responder/chunk_get.c
+++ b/unit_test/test_spdm_responder/chunk_get.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
  **/
 
@@ -996,6 +996,101 @@ void libspdm_test_responder_chunk_get_rsp_case13(void** state)
     }
 }
 
+
+/**
+ * Test 14: Responder has reponse exceed chunk seq no
+ **/
+void libspdm_test_responder_chunk_get_rsp_case14(void** state)
+{
+    libspdm_return_t status;
+    libspdm_test_context_t* spdm_test_context;
+    libspdm_context_t* spdm_context;
+    size_t response_size;
+    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
+    spdm_error_response_t* spdm_response;
+    spdm_chunk_get_request_t spdm_request;
+    void* scratch_buffer;
+    size_t scratch_buffer_size;
+
+    uint8_t chunk_handle;
+    uint32_t data_transfer_size;
+    uint32_t total_chunk_size;
+
+    spdm_test_context = *state;
+    spdm_context = spdm_test_context->spdm_context;
+    spdm_test_context->case_id = 10;
+    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.algorithm.base_hash_algo =
+        m_libspdm_use_hash_algo;
+
+    data_transfer_size = CHUNK_GET_RESPONDER_UNIT_TEST_DATA_TRANSFER_SIZE;
+    spdm_context->local_context.capability.data_transfer_size = data_transfer_size;
+    spdm_context->local_context.capability.flags |=
+        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP;
+    spdm_context->connection_info.capability.flags |=
+        SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP;
+
+    /* large response need a large scratch buffer */
+    spdm_context->connection_info.capability.max_spdm_msg_size = data_transfer_size * 65536;
+    spdm_context->local_context.capability.max_spdm_msg_size = data_transfer_size * 65536;
+    spdm_test_context->scratch_buffer_size =
+        libspdm_get_sizeof_required_scratch_buffer(spdm_context);
+    spdm_test_context->scratch_buffer = (void *)malloc(spdm_test_context->scratch_buffer_size);
+    libspdm_set_scratch_buffer (spdm_context,
+                                spdm_test_context->scratch_buffer,
+                                spdm_test_context->scratch_buffer_size);
+
+
+    libspdm_get_scratch_buffer(spdm_context, &scratch_buffer, &scratch_buffer_size);
+
+    scratch_buffer = (uint8_t*)scratch_buffer +
+                     libspdm_get_scratch_buffer_large_message_offset(spdm_context);
+    scratch_buffer_size = scratch_buffer_size -
+                          libspdm_get_scratch_buffer_large_message_offset(spdm_context);
+    libspdm_zero_mem(scratch_buffer, scratch_buffer_size);
+
+    /* a huge chunk size to cause the chunk seq no wrap */
+    total_chunk_size = data_transfer_size * 65536;
+
+    LIBSPDM_ASSERT(total_chunk_size <= scratch_buffer_size);
+
+    chunk_handle = (uint8_t) spdm_test_context->case_id; /* Any number is fine */
+    spdm_context->chunk_context.get.chunk_in_use = true;
+    spdm_context->chunk_context.get.chunk_handle = chunk_handle;
+    spdm_context->chunk_context.get.chunk_seq_no = 0;
+    spdm_context->chunk_context.get.large_message = scratch_buffer;
+    spdm_context->chunk_context.get.large_message_size = total_chunk_size;
+    spdm_context->chunk_context.get.chunk_bytes_transferred = 0;
+
+    libspdm_zero_mem(&spdm_request, sizeof(spdm_request));
+    spdm_request.header.spdm_version = SPDM_MESSAGE_VERSION_12;
+    spdm_request.header.request_response_code = SPDM_CHUNK_GET;
+    spdm_request.header.param1 = 0;
+    spdm_request.header.param2 = chunk_handle;
+    spdm_request.chunk_seq_no = 0;
+
+    response_size = sizeof(response);
+    status = libspdm_get_response_chunk_get(
+        spdm_context,
+        sizeof(spdm_request), &spdm_request,
+        &response_size, response);
+
+    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
+    assert_int_equal(response_size, sizeof(spdm_error_response_t));
+
+    spdm_response = (spdm_error_response_t*) response;
+
+    assert_int_equal(spdm_response->header.spdm_version, SPDM_MESSAGE_VERSION_12);
+    assert_int_equal(spdm_response->header.request_response_code, SPDM_ERROR);
+    assert_int_equal(spdm_response->header.param1, SPDM_ERROR_CODE_RESPONSE_TOO_LARGE);
+    assert_int_equal(spdm_response->header.param2, 0);
+}
+
+
 int libspdm_responder_chunk_get_rsp_test_main(void)
 {
     const struct CMUnitTest spdm_responder_chunk_get_tests[] = {
@@ -1025,6 +1120,8 @@ int libspdm_responder_chunk_get_rsp_test_main(void)
         cmocka_unit_test(libspdm_test_responder_chunk_get_rsp_case12),
         /* Successful request of last chunk where chunk size is exactly 1 byte */
         cmocka_unit_test(libspdm_test_responder_chunk_get_rsp_case13),
+        /* Responder has reponse exceed chunk seq no */
+        cmocka_unit_test(libspdm_test_responder_chunk_get_rsp_case14),
     };
 
     libspdm_test_context_t test_context = {