Skip to content

Support CLIENT_HELLO split across multiple packets#12290

Merged
bneradt merged 2 commits intoapache:masterfrom
bneradt:fix_split_client_hello
Jun 26, 2025
Merged

Support CLIENT_HELLO split across multiple packets#12290
bneradt merged 2 commits intoapache:masterfrom
bneradt:fix_split_client_hello

Conversation

@bneradt
Copy link
Copy Markdown
Contributor

@bneradt bneradt commented Jun 13, 2025

Our TLS CLIENT_HELLO processing logic assumed all CLIENT_HELLO bytes came in a single TCP packet. However, with more recent cryptographic ciphers, the CLIENT_HELLO is often greater than the standard 1,500 byte MTU, so the CLIENT_HELLO is being delivered in multiple packets. This updates our logic to properly buffer and parse data across multiple socket reads.

Fixes: #11758

@bneradt bneradt added this to the 10.2.0 milestone Jun 13, 2025
@bneradt bneradt self-assigned this Jun 13, 2025
@bneradt bneradt requested a review from Copilot June 13, 2025 22:45
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 updates TLS handshake processing to support CLIENT_HELLO messages arriving in multiple packets. Key changes include new test cases to simulate split and large CLIENT_HELLO packets, adjustments to proxy protocol checking, and enhanced debug logging for handshake buffering.

Reviewed Changes

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

Show a summary per file
File Description
tests/gold_tests/tls/tls_tunnel.test.py Added tests for split and large CLIENT_HELLO along with TimeOut updates.
tests/gold_tests/tls/split_client_hello.py Introduced a script to send CLIENT_HELLO in multiple packets.
tests/gold_tests/tls/receive_split_client_hello.py Added a script to receive CLIENT_HELLO and validate its length.
tests/gold_tests/tls/gold/tls-tunnel-metrics.gold Updated expected metric numbers.
src/iocore/net/SSLNetVConnection.cc Updated proxy protocol logic and added detailed debug messaging.
src/iocore/net/P_SSLNetVConnection.h Added documentation and new members for handshake buffer management.
Comments suppressed due to low confidence (1)

src/iocore/net/SSLNetVConnection.cc:584

  • [nitpick] The conditional logic for updating the read BIO based on the CLIENT_HELLO state would benefit from an inline comment explaining why the buffers are retained while in the CLIENT_HELLO phase.
read.triggered = update_rbio(!in_client_hello);

@bneradt bneradt force-pushed the fix_split_client_hello branch from 51256ea to d41cbaa Compare June 13, 2025 22:47
@bneradt bneradt force-pushed the fix_split_client_hello branch 3 times, most recently from dbb78c8 to 2537ce6 Compare June 16, 2025 16:07
Our TLS CLIENT_HELLO processing logic assumed all CLIENT_HELLO bytes
came in a single TCP packet. However, with more recent cryptographic
ciphers, the CLIENT_HELLO is often greater than the standard 1,500 byte
MTU, so the CLIENT_HELLO is being delivered in multiple packets. This
updates our logic to properly buffer and parse data across multiple
socket reads.

Fixes: apache#11758
@bneradt bneradt force-pushed the fix_split_client_hello branch from 2537ce6 to cd9665c Compare June 16, 2025 18:16
@bryancall bryancall requested a review from moonchen June 16, 2025 22:33
// finished. We need to keep our buffers updated until then in case we
// enter tunnel mode.
Dbg(dbg_ctl_ssl, "Updating our buffers, in CLIENT_HELLO: %s", in_client_hello ? "true" : "false");
read.triggered = update_rbio(!in_client_hello);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Only transition to socket mode from our manually fed buffer if we're not still processing the CLIENT_HELLO. While we process the CLIENT_HELLO, we need to keep buffering it in case we want to replay it in the blind tunnel case.

Comment on lines +1230 to 1237
bool const in_client_hello =
this->get_handshake_hook_state() == TLSEventSupport::SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO;
// We only feed CLIENT_HELLO bytes into our temporary buffers. If we are past
// the CLIENT_HELLO, then no need to buffer.
if (in_client_hello && this->handShakeReader) {
if (BIO_eof(SSL_get_rbio(this->ssl))) { // No more data in the buffer
// Is this the first read?
if (!this->handShakeReader->is_read_avail_more_than(0) && !this->handShakeHolder->is_read_avail_more_than(0)) {
// Is this the first read?
#if TS_USE_TLS_ASYNC
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If the CLIENT_HELLO is split on multiple packets, then we need to call this->read_raw_data for each packet (see 1246). Before this change, we assumed we would only ever need to call it once, thus we only called it if handShakeReader/Holder was empty. This change makes us do the raw read for each packet that comes in, so we can populate our buffered CLIENT_HELLO and feed it to the SSL socket.

Comment on lines 1243 to 1245
}
} else {
update_rbio(false);
} else if (retval == 0) {
// EOF, go away, we stopped in the handshake
SSLVCDebug(this, "SSL handshake error: EOF");
return EVENT_ERROR;
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

the read_faw_data logic above does what update_rbio would have been doing (read from the socket and populate our buffers), so no need to call it here.

@tomuxi
Copy link
Copy Markdown

tomuxi commented Jun 18, 2025

I guess no hope in getting this fix backported to older major versions?

@bneradt
Copy link
Copy Markdown
Contributor Author

bneradt commented Jun 18, 2025

I guess no hope in getting this fix backported to older major versions?

The cherry-pick for 9.x is non-trivial, but I can look into it.

Support the situation in which handShakeReader is a chain of more than
one IOBufferBlock.
@bneradt
Copy link
Copy Markdown
Contributor Author

bneradt commented Jun 25, 2025

I guess no hope in getting this fix backported to older major versions?

The cherry-pick for 9.x is non-trivial, but I can look into it.

I guess no hope in getting this fix backported to older major versions?

The cherry-pick for 9.x is non-trivial, but I can look into it.

I made a 9.2.x backport:
#12319

@bneradt bneradt merged commit 572ec5d into apache:master Jun 26, 2025
15 checks passed
@github-project-automation github-project-automation bot moved this to For v10.1.0 in ATS v10.1.x Jun 26, 2025
@bneradt bneradt deleted the fix_split_client_hello branch June 26, 2025 16:43
@cmcfarlen cmcfarlen moved this from For v10.1.0 to picked v10.1.0 in ATS v10.1.x Jun 30, 2025
@cmcfarlen cmcfarlen modified the milestones: 10.2.0, 10.1.0 Jun 30, 2025
@cmcfarlen
Copy link
Copy Markdown
Contributor

Cherry-picked to 10.1.x branch

cmcfarlen pushed a commit that referenced this pull request Jun 30, 2025
Our TLS CLIENT_HELLO processing logic assumed all CLIENT_HELLO bytes
came in a single TCP packet. However, with more recent cryptographic
ciphers, the CLIENT_HELLO is often greater than the standard 1,500 byte
MTU, so the CLIENT_HELLO is being delivered in multiple packets. This
updates our logic to properly buffer and parse data across multiple
socket reads.

Fixes: #11758
(cherry picked from commit 572ec5d)
cap-jonesa added a commit to cap-jonesa/tldr.fail that referenced this pull request Aug 26, 2025
Updating chart: The issue with Apache Traffic Server has been fixed. apache/trafficserver#12290
dadrian pushed a commit to dadrian/tldr.fail that referenced this pull request Oct 5, 2025
Updating chart: The issue with Apache Traffic Server has been fixed. apache/trafficserver#12290
bneradt pushed a commit to bneradt/trafficserver that referenced this pull request Jan 23, 2026
This cherry picks a review comment update from:
apache#12290
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: picked v10.1.0

Development

Successfully merging this pull request may close these issues.

Blind tunneling breaks with Google Chrome and TLS Kyber cipher

5 participants