Skip to content

Abort TLS transport on session verification failure#3323

Open
He-Pin wants to merge 1 commit into
apache:mainfrom
He-Pin:fix/3245-tls-handshake-failure
Open

Abort TLS transport on session verification failure#3323
He-Pin wants to merge 1 commit into
apache:mainfrom
He-Pin:fix/3245-tls-handshake-failure

Conversation

@He-Pin

@He-Pin He-Pin commented Jul 11, 2026

Copy link
Copy Markdown
Member

Motivation

A failed post-handshake session verifier was handled as if the SSLEngine itself had failed. When the verifier returned an SSLException, the GraphStage TLS implementation caught it in the engine failure path and called closeOutbound(). Because the handshake had already succeeded and there was no pending fatal alert, this generated close_notify and completed the transport gracefully instead of aborting it.

Engine-originated handshake failures are intentionally left unchanged: those paths must continue wrapping and flushing pending fatal alerts such as certificate_unknown.

Modification

  • Handle a failed verifySession result as an explicit TLS stage failure.
  • Stop wrap/unwrap handshake processing immediately after the verifier rejects the session.
  • Add a directional regression test that observes the cipher-side transport termination and checks that the original verifier exception fails it.
  • Run the shared test for both the GraphStage and legacy actor implementations, covering TLS 1.2 and TLS 1.3.

Result

Post-handshake session verification failures now abort the transport with the original exception. The GraphStage behavior matches the legacy TLS actor, while engine-originated TLS failures continue to flush their fatal alerts.

Tests

  • stream-tests / Test / testOnly org.apache.pekko.stream.io.TlsGraphStageSpec — 113 passed
  • stream-tests / Test / testOnly org.apache.pekko.stream.io.TlsSpec — 113 passed
  • +headerCheckAll — passed
  • checkCodeStyle — passed
  • validatePullRequest — environment failure: leveldbjni-all 1.8 has no macOS ARM64 binary; remaining unrelated tests were stopped
  • Qoder blocker review — no must-fix findings

References

Fixes #3245

Motivation:
A failed post-handshake session verifier was handled as an SSLEngine failure, causing the GraphStage TLS implementation to emit close_notify instead of aborting the transport.

Modification:
Handle verifier failures as an explicit TLS stage failure and stop handshake processing. Add a regression test shared by the GraphStage and legacy actor implementations for TLS 1.2 and TLS 1.3.

Result:
Session verification failures now fail the transport with the original exception while engine-originated TLS failures still flush their fatal alerts.

Tests:
- stream-tests / Test / testOnly org.apache.pekko.stream.io.TlsGraphStageSpec (113 passed)
- stream-tests / Test / testOnly org.apache.pekko.stream.io.TlsSpec (113 passed)
- +headerCheckAll (passed)
- checkCodeStyle (passed)
- validatePullRequest (environment failure: leveldbjni-all 1.8 has no macOS ARM64 binary; remaining unrelated tests stopped)

References:
Fixes apache#3245
@He-Pin He-Pin added this to the 2.0.0-M4 milestone Jul 11, 2026
@He-Pin He-Pin requested a review from pjfanning July 11, 2026 10:26
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.

TLS handshake failure sends close_notify instead of fatal alert

1 participant