Skip to content

Handle ECH Retry - #9611

Open
yschimke wants to merge 4 commits into
lysine-dev:masterfrom
yschimke:retry_config
Open

Handle ECH Retry#9611
yschimke wants to merge 4 commits into
lysine-dev:masterfrom
yschimke:retry_config

Conversation

@yschimke

@yschimke yschimke commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator

A few assorted changes

  • grab the ech retry config and use it to retry when we get a mismatch
  • avoid ech retry more than once
  • avoid downgrading from ech to non ech

@yschimke
yschimke requested a review from swankjesse July 26, 2026 17:18
@yschimke

Copy link
Copy Markdown
Collaborator Author

fun differentPublicHostnameIsVerifiedBeforeRetry() {
// The outer certificate authenticates public.tls-ech.dev,
// so the retry config may be used if it matches.
// https://www.rfc-editor.org/rfc/rfc9849.html#section-6.1.6

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Think I got think backwards, re-reading.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Yes, you should only be verifying the public hostname against the certificate, not against the request. Conscrypt isn't able to do the hostname validation itself, which is why it's necessary to do it here in OkHttp.

FYI @tweksteen

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Just to confirm, at this point our SSLSession is dead, but we can safely read the certificates that were presented.

But are the certificates on the SSLSession trusted? Does Conscrypt already clean the certs?

@yschimke

Copy link
Copy Markdown
Collaborator Author

I'll ask at work tomorrow.

@yschimke
yschimke marked this pull request as draft July 26, 2026 17:38

@swankjesse swankjesse left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I’d like to be particularly careful with landing this as it introduces new attack vectors and is not yet possible to test with MockWebServer + JVM Conscrypt.

I think it’s definitely good to have special recovery code for ECH handshake failures. But my first instinct is that special recovery code should mostly be about reducing the opportunity for downgrade attacks.

This is attempting to do something else, and I would like to understand the problem it solves before we land this.

Comment thread okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/dns/-DnsMessage.kt Outdated
Comment thread okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectPlan.kt Outdated
Comment thread okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectPlan.kt Outdated
val echRetryConfig = Platform.get().getEchRetryConfig(e)
if (
echRetryConfig != null &&
route.address.hostnameVerifier!!.verify(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This surprises me. Is there an attack that this defends against?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@bjiang7

bjiang7 commented Jul 27, 2026

Copy link
Copy Markdown

Just chiming in here to state that the ECH recovery flow is a pretty important part of the spec, and so should be implemented if OkHttp is to say it supports ECH.

The reason why is because there's no other way to recover from a mismatch in ECH config between the client and server (i.e. synchronization issues). It's a performance hit to have to fall into this codepath (and shouldn't be happening in most cases), but it is needed so the consequences of things being out of sync is latency rather than outages.

I also asked BoringSSL a long time ago about this when doing the Android implementation, because I had the same question of how important the recovery flow was. Their stance was "This behavior is pretty crucial to allow servers to safely deploy ECH because DNS records can be stale and we need to make it possible for servers to recover from mismatches. The existence of any client that gets this wrong means a server now cannot deploy ECH in a rollback-safe way."

@swankjesse

Copy link
Copy Markdown
Collaborator

Making it safer for server operators to confidently deploy ECH is good.

@yschimke
yschimke marked this pull request as ready for review July 27, 2026 19:43
client
.newBuilder()
.connectionSpecs(listOf(ConnectionSpec.RESTRICTED_TLS, ConnectionSpec.MODERN_TLS))
.eventListener(

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

this wasn't valid, and after the refactor, isn't effective.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants