Skip to content

Prevent TLS1.2 handshake fragments from entering TLS1.3 post-handshak… - #6039

Open
FreezB11 wants to merge 2 commits into
aws:mainfrom
FreezB11:fix/5624-post-handshake-tls12-routing
Open

Prevent TLS1.2 handshake fragments from entering TLS1.3 post-handshak…#6039
FreezB11 wants to merge 2 commits into
aws:mainfrom
FreezB11:fix/5624-post-handshake-tls12-routing

Conversation

@FreezB11

Copy link
Copy Markdown
Contributor

Description

Fixes #5624.

s2n_post_handshake_recv() treated any TLS_HANDSHAKE-typed record as a post-handshake message, even if the handshake hadn't actually finished. If a caller's completion tracking diverges from s2n-tls's internal state (e.g. the peer's final Finished message wasn't fully consumed yet), leftover handshake bytes get misread as a post-handshake message header — resulting in either S2N_ERR_BAD_MESSAGE, or worse, silent success if the misread bytes happened to look like a TLS_HELLO_REQUEST (which is silently ignored by default).

Fix

s2n_post_handshake_recv() now requires s2n_handshake_is_complete(conn) before processing anything, returning the existing S2N_ERR_HANDSHAKE_NOT_COMPLETE otherwise.

I deliberately checked handshake completeness rather than gating on actual_protocol_version < S2N_TLS13 (as suggested in the issue). TLS1.2 HelloRequest is a legitimate message this same function handles, so a blanket version check would make that unreachable. s2n_handshake_is_complete() correctly distinguishes leftover/unconsumed bytes (the bug) from a genuinely-finished TLS1.2 connection receiving HelloRequest or a finished TLS1.3 connection receiving KeyUpdate/NewSessionTicket (which already have their own version checks).

Testing

  • New regression test (s2n_post_handshake_test.c) reproducing the exact scenario: negotiates a real TLS1.2 handshake, stalls the client right before it reads the server's Finished, then asserts the leftover bytes are rejected with S2N_ERR_HANDSHAKE_NOT_COMPLETE.
  • Updated existing tests that built bare connections without a real handshake to use the existing s2n_skip_handshake() helper, matching real-world state.
  • s2n_early_data_io_test.c already covered a variant of this bug class; it now correctly gets S2N_ERR_HANDSHAKE_NOT_COMPLETE instead of S2N_ERR_BAD_MESSAGE.
  • One test asserted HelloRequest was accepted on a TLS1.3 connection — only passing because the handshake was never marked NEGOTIATED, bypassing a pre-existing version check. Updated to assert the correct rejection.
  • 283/283 unit test binaries pass locally (ctest -j$(nproc)).

@FreezB11

FreezB11 commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

@kaukabrizvi @jmayclin, please do review when free thanks

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.

Prevent TLS 1.2 Handshake Messages from Entering TLS 1.3 Post-Handshake Path

1 participant