From a9a9f7aef5393f14dbe05d53ac9dab2734a7f260 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Fri, 17 Jul 2026 22:46:08 -0400 Subject: [PATCH] Create a place for ECH in our configureTlsExtensions API --- .../okhttp/android/test/AndroidSocketAdapterTest.kt | 4 ++-- .../src/main/kotlin/mockwebserver3/MockWebServer.kt | 7 ++++++- .../java/mockwebserver3/internal/http2/Http2Server.kt | 7 ++++++- .../kotlin/okhttp3/internal/platform/Android10Platform.kt | 4 +++- .../kotlin/okhttp3/internal/platform/AndroidPlatform.kt | 4 +++- .../internal/platform/android/Android10SocketAdapter.kt | 2 ++ .../internal/platform/android/AndroidSocketAdapter.kt | 2 ++ .../platform/android/BouncyCastleSocketAdapter.kt | 2 ++ .../internal/platform/android/ConscryptSocketAdapter.kt | 2 ++ .../internal/platform/android/DeferredSocketAdapter.kt | 4 +++- .../okhttp3/internal/platform/android/SocketAdapter.kt | 2 ++ .../kotlin/okhttp3/internal/connection/ConnectPlan.kt | 8 +++++++- .../kotlin/okhttp3/internal/platform/Jdk9Platform.kt | 2 ++ .../kotlin/okhttp3/internal/platform/Platform.kt | 2 ++ .../okhttp3/internal/platform/BouncyCastlePlatform.kt | 4 +++- .../kotlin/okhttp3/internal/platform/ConscryptPlatform.kt | 4 +++- .../internal/platform/Jdk8WithJettyBootPlatform.kt | 2 ++ .../kotlin/okhttp3/internal/platform/OpenJSSEPlatform.kt | 4 +++- 18 files changed, 55 insertions(+), 11 deletions(-) diff --git a/android-test/src/test/kotlin/okhttp/android/test/AndroidSocketAdapterTest.kt b/android-test/src/test/kotlin/okhttp/android/test/AndroidSocketAdapterTest.kt index 59fc723ab598..e62c5885eb79 100644 --- a/android-test/src/test/kotlin/okhttp/android/test/AndroidSocketAdapterTest.kt +++ b/android-test/src/test/kotlin/okhttp/android/test/AndroidSocketAdapterTest.kt @@ -58,7 +58,7 @@ class AndroidSocketAdapterTest( val sslSocket = socketFactory.createSocket() as SSLSocket assertTrue(adapter.matchesSocket(sslSocket)) - adapter.configureTlsExtensions(sslSocket, null, listOf(HTTP_2, HTTP_1_1)) + adapter.configureTlsExtensions(sslSocket, null, listOf(HTTP_2, HTTP_1_1), null) // not connected assertNull(adapter.getSelectedProtocol(sslSocket)) } @@ -89,7 +89,7 @@ class AndroidSocketAdapterTest( object : DelegatingSSLSocket(context.socketFactory.createSocket() as SSLSocket) {} assertFalse(adapter.matchesSocket(sslSocket)) - adapter.configureTlsExtensions(sslSocket, null, listOf(HTTP_2, HTTP_1_1)) + adapter.configureTlsExtensions(sslSocket, null, listOf(HTTP_2, HTTP_1_1), null) // not connected assertNull(adapter.getSelectedProtocol(sslSocket)) } diff --git a/mockwebserver/src/main/kotlin/mockwebserver3/MockWebServer.kt b/mockwebserver/src/main/kotlin/mockwebserver3/MockWebServer.kt index 60b0d28034e1..a4ef8311953c 100644 --- a/mockwebserver/src/main/kotlin/mockwebserver3/MockWebServer.kt +++ b/mockwebserver/src/main/kotlin/mockwebserver3/MockWebServer.kt @@ -473,7 +473,12 @@ public class MockWebServer : Closeable { openClientSockets.add(sslSocket) if (protocolNegotiationEnabled) { - Platform.get().configureTlsExtensions(sslSocket, null, protocols) + Platform.get().configureTlsExtensions( + sslSocket = sslSocket, + hostname = null, + protocols = protocols, + echConfigList = null, + ) } sslSocket.startHandshake() diff --git a/mockwebserver/src/test/java/mockwebserver3/internal/http2/Http2Server.kt b/mockwebserver/src/test/java/mockwebserver3/internal/http2/Http2Server.kt index bc9a3a12b4cd..a8c53fe6e0c8 100644 --- a/mockwebserver/src/test/java/mockwebserver3/internal/http2/Http2Server.kt +++ b/mockwebserver/src/test/java/mockwebserver3/internal/http2/Http2Server.kt @@ -82,7 +82,12 @@ class Http2Server( true, ) as SSLSocket sslSocket.useClientMode = false - Platform.get().configureTlsExtensions(sslSocket, null, listOf(Protocol.HTTP_2)) + Platform.get().configureTlsExtensions( + sslSocket = sslSocket, + hostname = null, + protocols = listOf(Protocol.HTTP_2), + echConfigList = null, + ) sslSocket.startHandshake() return sslSocket } diff --git a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/Android10Platform.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/Android10Platform.kt index 671427de4e67..00cbe21a7079 100644 --- a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/Android10Platform.kt +++ b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/Android10Platform.kt @@ -37,6 +37,7 @@ import okhttp3.internal.platform.android.ConscryptSocketAdapter import okhttp3.internal.platform.android.DeferredSocketAdapter import okhttp3.internal.tls.CertificateChainCleaner import okhttp3.internal.tls.TrustRootIndex +import okio.ByteString /** Android 10+ (API 29+). */ @SuppressSignatureCheck @@ -75,11 +76,12 @@ class Android10Platform : sslSocket: SSLSocket, hostname: String?, protocols: List, + echConfigList: ByteString?, ) { // No TLS extensions if the socket class is custom. socketAdapters .find { it.matchesSocket(sslSocket) } - ?.configureTlsExtensions(sslSocket, hostname, protocols) + ?.configureTlsExtensions(sslSocket, hostname, protocols, echConfigList) } override fun getSelectedProtocol(sslSocket: SSLSocket): String? = diff --git a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/AndroidPlatform.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/AndroidPlatform.kt index 4f94d192b034..0acf655366f9 100644 --- a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/AndroidPlatform.kt +++ b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/AndroidPlatform.kt @@ -42,6 +42,7 @@ import okhttp3.internal.platform.android.StandardAndroidSocketAdapter import okhttp3.internal.tls.BasicTrustRootIndex import okhttp3.internal.tls.CertificateChainCleaner import okhttp3.internal.tls.TrustRootIndex +import okio.ByteString /** Android 5 to 9 (API 21 to 28). */ @SuppressSignatureCheck @@ -93,11 +94,12 @@ class AndroidPlatform : sslSocket: SSLSocket, hostname: String?, protocols: List<@JvmSuppressWildcards Protocol>, + echConfigList: ByteString?, ) { // No TLS extensions if the socket class is custom. socketAdapters .find { it.matchesSocket(sslSocket) } - ?.configureTlsExtensions(sslSocket, hostname, protocols) + ?.configureTlsExtensions(sslSocket, hostname, protocols, echConfigList) } override fun getSelectedProtocol(sslSocket: SSLSocket): String? = diff --git a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/Android10SocketAdapter.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/Android10SocketAdapter.kt index 83a3f4f41cbb..d8e83eabcd10 100644 --- a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/Android10SocketAdapter.kt +++ b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/Android10SocketAdapter.kt @@ -25,6 +25,7 @@ import okhttp3.Protocol import okhttp3.internal.SuppressSignatureCheck import okhttp3.internal.platform.Platform import okhttp3.internal.platform.Platform.Companion.isAndroid +import okio.ByteString /** * Simple non-reflection SocketAdapter for Android Q+. @@ -57,6 +58,7 @@ class Android10SocketAdapter : SocketAdapter { sslSocket: SSLSocket, hostname: String?, protocols: List, + echConfigList: ByteString?, ) { try { SSLSockets.setUseSessionTickets(sslSocket, true) diff --git a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/AndroidSocketAdapter.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/AndroidSocketAdapter.kt index 5913600873c5..1c57942272d3 100644 --- a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/AndroidSocketAdapter.kt +++ b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/AndroidSocketAdapter.kt @@ -22,6 +22,7 @@ import javax.net.ssl.SSLSocket import okhttp3.Protocol import okhttp3.internal.platform.AndroidPlatform import okhttp3.internal.platform.Platform +import okio.ByteString /** * Modern reflection based SocketAdapter for Conscrypt class SSLSockets. @@ -48,6 +49,7 @@ open class AndroidSocketAdapter( sslSocket: SSLSocket, hostname: String?, protocols: List, + echConfigList: ByteString?, ) { // No TLS extensions if the socket class is custom. if (matchesSocket(sslSocket)) { diff --git a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/BouncyCastleSocketAdapter.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/BouncyCastleSocketAdapter.kt index 6d2b8beb0e62..1673a0b312bc 100644 --- a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/BouncyCastleSocketAdapter.kt +++ b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/BouncyCastleSocketAdapter.kt @@ -18,6 +18,7 @@ package okhttp3.internal.platform.android import javax.net.ssl.SSLSocket import okhttp3.Protocol import okhttp3.internal.platform.Platform +import okio.ByteString import org.bouncycastle.jsse.BCSSLSocket /** @@ -41,6 +42,7 @@ class BouncyCastleSocketAdapter : SocketAdapter { sslSocket: SSLSocket, hostname: String?, protocols: List, + echConfigList: ByteString?, ) { // No TLS extensions if the socket class is custom. if (matchesSocket(sslSocket)) { diff --git a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/ConscryptSocketAdapter.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/ConscryptSocketAdapter.kt index 006e593b7bcf..48dec2683938 100644 --- a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/ConscryptSocketAdapter.kt +++ b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/ConscryptSocketAdapter.kt @@ -18,6 +18,7 @@ package okhttp3.internal.platform.android import javax.net.ssl.SSLSocket import okhttp3.Protocol import okhttp3.internal.platform.Platform +import okio.ByteString import org.conscrypt.Conscrypt /** @@ -39,6 +40,7 @@ class ConscryptSocketAdapter : SocketAdapter { sslSocket: SSLSocket, hostname: String?, protocols: List, + echConfigList: ByteString?, ) { // No TLS extensions if the socket class is custom. if (matchesSocket(sslSocket)) { diff --git a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/DeferredSocketAdapter.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/DeferredSocketAdapter.kt index 10b619dec831..f968e4747546 100644 --- a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/DeferredSocketAdapter.kt +++ b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/DeferredSocketAdapter.kt @@ -17,6 +17,7 @@ package okhttp3.internal.platform.android import javax.net.ssl.SSLSocket import okhttp3.Protocol +import okio.ByteString /** * Deferred implementation of SocketAdapter that works by observing the socket @@ -39,8 +40,9 @@ class DeferredSocketAdapter( sslSocket: SSLSocket, hostname: String?, protocols: List, + echConfigList: ByteString?, ) { - getDelegate(sslSocket)?.configureTlsExtensions(sslSocket, hostname, protocols) + getDelegate(sslSocket)?.configureTlsExtensions(sslSocket, hostname, protocols, echConfigList) } override fun getSelectedProtocol(sslSocket: SSLSocket): String? = getDelegate(sslSocket)?.getSelectedProtocol(sslSocket) diff --git a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/SocketAdapter.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/SocketAdapter.kt index 40776f6bfb17..fa6a62614140 100644 --- a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/SocketAdapter.kt +++ b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/SocketAdapter.kt @@ -19,6 +19,7 @@ import javax.net.ssl.SSLSocket import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager import okhttp3.Protocol +import okio.ByteString interface SocketAdapter { fun isSupported(): Boolean @@ -33,6 +34,7 @@ interface SocketAdapter { sslSocket: SSLSocket, hostname: String?, protocols: List, + echConfigList: ByteString?, ) fun getSelectedProtocol(sslSocket: SSLSocket): String? diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectPlan.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectPlan.kt index 9fe3bbbd2008..407fc7fc2624 100644 --- a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectPlan.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectPlan.kt @@ -18,6 +18,7 @@ package okhttp3.internal.connection import java.io.IOException import java.net.ConnectException import java.net.HttpURLConnection +import java.net.NoRouteToHostException import java.net.ProtocolException import java.net.Proxy import java.net.Socket as JavaNetSocket @@ -345,7 +346,12 @@ class ConnectPlan internal constructor( var success = false try { if (connectionSpec.supportsTlsExtensions) { - Platform.get().configureTlsExtensions(sslSocket, address.url.host, address.protocols) + Platform.get().configureTlsExtensions( + sslSocket = sslSocket, + hostname = address.url.host, + protocols = address.protocols, + echConfigList = route.echConfigList + ) } // Force handshake. This can throw! diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/Jdk9Platform.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/Jdk9Platform.kt index 6247d485331f..c014e1b82456 100644 --- a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/Jdk9Platform.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/Jdk9Platform.kt @@ -22,6 +22,7 @@ import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager import okhttp3.Protocol import okhttp3.internal.SuppressSignatureCheck +import okio.ByteString /** * OpenJDK 9+ and JDK8 build 252+. @@ -35,6 +36,7 @@ open class Jdk9Platform : Platform() { sslSocket: SSLSocket, hostname: String?, protocols: List<@JvmSuppressWildcards Protocol>, + echConfigList: ByteString?, ) { val sslParameters = sslSocket.sslParameters diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/Platform.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/Platform.kt index f33d97972b94..d65df2df3df3 100644 --- a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/Platform.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/Platform.kt @@ -40,6 +40,7 @@ import okhttp3.internal.tls.BasicTrustRootIndex import okhttp3.internal.tls.CertificateChainCleaner import okhttp3.internal.tls.TrustRootIndex import okio.Buffer +import okio.ByteString import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement /** @@ -116,6 +117,7 @@ open class Platform { sslSocket: SSLSocket, hostname: String?, protocols: List<@JvmSuppressWildcards Protocol>, + echConfigList: ByteString?, ) { } diff --git a/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/BouncyCastlePlatform.kt b/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/BouncyCastlePlatform.kt index 83e2e57ee61b..c0239d37bf53 100644 --- a/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/BouncyCastlePlatform.kt +++ b/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/BouncyCastlePlatform.kt @@ -23,6 +23,7 @@ import javax.net.ssl.SSLSocketFactory import javax.net.ssl.TrustManagerFactory import javax.net.ssl.X509TrustManager import okhttp3.Protocol +import okio.ByteString import org.bouncycastle.jsse.BCSSLSocket import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider @@ -59,6 +60,7 @@ class BouncyCastlePlatform private constructor() : Platform() { sslSocket: SSLSocket, hostname: String?, protocols: List<@JvmSuppressWildcards Protocol>, + echConfigList: ByteString?, ) { if (sslSocket is BCSSLSocket) { val sslParameters = sslSocket.parameters @@ -69,7 +71,7 @@ class BouncyCastlePlatform private constructor() : Platform() { sslSocket.parameters = sslParameters } else { - super.configureTlsExtensions(sslSocket, hostname, protocols) + super.configureTlsExtensions(sslSocket, hostname, protocols, echConfigList) } } diff --git a/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/ConscryptPlatform.kt b/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/ConscryptPlatform.kt index 51ef4ca4b3c2..c309dc598000 100644 --- a/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/ConscryptPlatform.kt +++ b/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/ConscryptPlatform.kt @@ -26,6 +26,7 @@ import javax.net.ssl.TrustManager import javax.net.ssl.TrustManagerFactory import javax.net.ssl.X509TrustManager import okhttp3.Protocol +import okio.ByteString import org.conscrypt.Conscrypt import org.conscrypt.ConscryptHostnameVerifier @@ -78,6 +79,7 @@ class ConscryptPlatform private constructor() : Platform() { sslSocket: SSLSocket, hostname: String?, protocols: List<@JvmSuppressWildcards Protocol>, + echConfigList: ByteString?, ) { if (Conscrypt.isConscrypt(sslSocket)) { // Enable session tickets. @@ -87,7 +89,7 @@ class ConscryptPlatform private constructor() : Platform() { val names = alpnProtocolNames(protocols) Conscrypt.setApplicationProtocols(sslSocket, names.toTypedArray()) } else { - super.configureTlsExtensions(sslSocket, hostname, protocols) + super.configureTlsExtensions(sslSocket, hostname, protocols, echConfigList) } } diff --git a/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/Jdk8WithJettyBootPlatform.kt b/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/Jdk8WithJettyBootPlatform.kt index 5ae0567cd212..4efb364d5e90 100644 --- a/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/Jdk8WithJettyBootPlatform.kt +++ b/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/Jdk8WithJettyBootPlatform.kt @@ -21,6 +21,7 @@ import java.lang.reflect.Method import java.lang.reflect.Proxy import javax.net.ssl.SSLSocket import okhttp3.Protocol +import okio.ByteString /** OpenJDK 8 with `org.mortbay.jetty.alpn:alpn-boot` in the boot class path. */ class Jdk8WithJettyBootPlatform( @@ -34,6 +35,7 @@ class Jdk8WithJettyBootPlatform( sslSocket: SSLSocket, hostname: String?, protocols: List, + echConfigList: ByteString?, ) { val names = alpnProtocolNames(protocols) diff --git a/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/OpenJSSEPlatform.kt b/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/OpenJSSEPlatform.kt index e4d50a391144..cbdabc767406 100644 --- a/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/OpenJSSEPlatform.kt +++ b/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/OpenJSSEPlatform.kt @@ -23,6 +23,7 @@ import javax.net.ssl.SSLSocketFactory import javax.net.ssl.TrustManagerFactory import javax.net.ssl.X509TrustManager import okhttp3.Protocol +import okio.ByteString /** * Platform using OpenJSSE (https://github.com/openjsse/openjsse) if installed as the first @@ -63,6 +64,7 @@ class OpenJSSEPlatform private constructor() : Platform() { sslSocket: SSLSocket, hostname: String?, protocols: List<@JvmSuppressWildcards Protocol>, + echConfigList: ByteString?, ) { if (sslSocket is org.openjsse.javax.net.ssl.SSLSocket) { val sslParameters = sslSocket.sslParameters @@ -75,7 +77,7 @@ class OpenJSSEPlatform private constructor() : Platform() { sslSocket.sslParameters = sslParameters } } else { - super.configureTlsExtensions(sslSocket, hostname, protocols) + super.configureTlsExtensions(sslSocket, hostname, protocols, echConfigList) } }