Skip to content

TLS 1.3: reassemble fragmented post-handshake messages after FreeArrays#10691

Draft
julek-wolfssl wants to merge 1 commit into
wolfSSL:masterfrom
julek-wolfssl:tls13-fragmented-sessionticket-defrag
Draft

TLS 1.3: reassemble fragmented post-handshake messages after FreeArrays#10691
julek-wolfssl wants to merge 1 commit into
wolfSSL:masterfrom
julek-wolfssl:tls13-fragmented-sessionticket-defrag

Conversation

@julek-wolfssl

Copy link
Copy Markdown
Member

Description

The handshake-message defragmentation buffer (pendingMsg/pendingMsgSz/
pendingMsgOffset/pendingMsgType) lived inside ssl->arrays, which
FreeHandshakeResources() releases once the handshake completes. For a TLS 1.3
client the arrays are released whenever they are not being retained for later
use, e.g. when the library is built without HAVE_SESSION_TICKET.

DoTls13HandShakeMsg() then took an arrays == NULL early path that handed the
record straight to DoTls13HandShakeMsgType() without any reassembly. A
post-handshake handshake message split across several records — such as a
NewSessionTicket once a small max_fragment_length has been negotiated — was
therefore rejected with INCOMPLETE_DATA (-310) and the peer was reset.
Fragmentation during the handshake was unaffected because the arrays still
existed at that point.

Fix

Move the defragmentation buffer fields out of Arrays and into the WOLFSSL
object so they survive FreeArrays(), and drop the now-unnecessary
arrays == NULL special case in DoTls13HandShakeMsg() so that post-handshake
messages are reassembled exactly like handshake messages. The buffer is freed in
wolfSSL_ResourceFree(). DoHandShakeMsg() (TLS 1.2) is updated to use the
relocated fields as well.

Testing

Adds a regression test, test_tls13_fragmented_session_ticket, that releases
the client's handshake arrays after the handshake and injects a
NewSessionTicket fragmented across two records, confirming it is reassembled
and consumed instead of failing with INCOMPLETE_DATA.

The handshake-message defragmentation buffer (pendingMsg/pendingMsgSz/
pendingMsgOffset/pendingMsgType) lived inside ssl->arrays, which
FreeHandshakeResources() releases once the handshake completes. For a
TLS 1.3 client the arrays are released whenever they are not being
retained for later use, e.g. when the library is built without
HAVE_SESSION_TICKET.

DoTls13HandShakeMsg() then took an "arrays == NULL" early path that
handed the record straight to DoTls13HandShakeMsgType() without any
reassembly. A post-handshake handshake message split across several
records -- such as a NewSessionTicket once a small max_fragment_length
has been negotiated -- was therefore rejected with INCOMPLETE_DATA (-310)
and the peer was reset. Fragmentation during the handshake was
unaffected because the arrays still existed at that point.

Move the defragmentation buffer fields out of Arrays and into the WOLFSSL
object so they survive FreeArrays(), and drop the now-unnecessary
arrays == NULL special case in DoTls13HandShakeMsg() so that
post-handshake messages are reassembled exactly like handshake messages.
The buffer is freed in wolfSSL_ResourceFree(). DoHandShakeMsg() (TLS 1.2)
is updated to use the relocated fields as well.

Add a regression test, test_tls13_fragmented_session_ticket, that
releases the client's handshake arrays after the handshake and injects a
NewSessionTicket fragmented across two records, confirming it is
reassembled and consumed instead of failing with INCOMPLETE_DATA.
Copilot AI review requested due to automatic review settings June 15, 2026 22:20
@julek-wolfssl julek-wolfssl self-assigned this Jun 15, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes TLS 1.3 post-handshake handshake-message reassembly when ssl->arrays has been released (e.g., client builds without HAVE_SESSION_TICKET). It moves the handshake defragmentation buffer from Arrays into the WOLFSSL object so fragmented post-handshake messages (notably NewSessionTicket) can still be reassembled after FreeArrays().

Changes:

  • Move pendingMsg defragmentation state from Arrays into WOLFSSL so it survives FreeArrays().
  • Update TLS 1.3 (DoTls13HandShakeMsg) and TLS 1.2 (DoHandShakeMsg) handshake parsing to use ssl->pendingMsg*.
  • Add a regression test that injects a fragmented NewSessionTicket after simulating released handshake arrays.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
wolfssl/internal.h Relocates defrag buffer fields from Arrays into WOLFSSL.
src/tls13.c Removes arrays == NULL fast-path so TLS 1.3 post-handshake messages go through normal reassembly using ssl->pendingMsg*.
src/internal.c Stops freeing pendingMsg in FreeArrays() and frees it in wolfSSL_ResourceFree(); updates TLS 1.2 defrag to use ssl->pendingMsg*.
tests/api/test_tls13.h Registers new regression test in the TLS 1.3 API test list.
tests/api/test_tls13.c Adds regression test for fragmented post-handshake NewSessionTicket when arrays are released.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/internal.c
Comment on lines +8865 to +8866
XFREE(ssl->pendingMsg, ssl->heap, DYNAMIC_TYPE_ARRAYS);
ssl->pendingMsg = NULL;
Comment thread tests/api/test_tls13.c
Comment on lines +5691 to +5695
if (EXPECT_SUCCESS() && ssl_c->arrays != NULL) {
XFREE(ssl_c->arrays->preMasterSecret, ssl_c->heap, DYNAMIC_TYPE_SECRET);
XFREE(ssl_c->arrays, ssl_c->heap, DYNAMIC_TYPE_ARRAYS);
ssl_c->arrays = NULL;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants