From 3c49c01b3f5c38ca1769185392f74847d8029598 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Fri, 17 Jul 2026 22:43:37 -0400 Subject: [PATCH 1/2] Successfully exercise ECH with Conscrypt This worked locally using a local build of @mnbogner's pull request https://github.com/google/conscrypt/pull/1406 # Conflicts: # gradle/libs.versions.toml --- gradle/libs.versions.toml | 2 +- .../okhttp3/dnsoverhttps/EchRemoteTest.kt | 73 +++++++++++++++++++ .../internal/platform/ConscryptPlatform.kt | 4 + settings.gradle.kts | 1 + 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/EchRemoteTest.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a463e40d9555..986d9d65df51 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -45,7 +45,7 @@ mrjar = "0.1.1" openjsse = "1.1.14" org-bouncycastle = "1.85" org-bouncycastle-patch = "1.85.1" -org-conscrypt = "2.6.1" +org-conscrypt = "2.6-SNAPSHOT" org-junit-jupiter = "5.13.4" playservices-safetynet = "18.1.0" robolectric = "4.17-beta-2" diff --git a/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/EchRemoteTest.kt b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/EchRemoteTest.kt new file mode 100644 index 000000000000..428deb78b9f5 --- /dev/null +++ b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/EchRemoteTest.kt @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2026 OkHttp Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package okhttp3.dnsoverhttps + +import assertk.assertThat +import assertk.assertions.matchesPredicate +import java.net.InetAddress +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.OkHttpClient +import okhttp3.OkHttpClientTestRule +import okhttp3.Request +import okhttp3.Response +import okhttp3.testing.PlatformRule +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.RegisterExtension + +@Tag("Remote") +class EchRemoteTest { + @RegisterExtension + val platform = PlatformRule(requiredPlatformName = PlatformRule.CONSCRYPT_PROPERTY) + + @RegisterExtension + val clientTestRule = OkHttpClientTestRule() + + private var client = clientTestRule.newClientBuilder() + .dns( + DnsOverHttps + .Builder() + .client(clientTestRule.newClient()) + .url("https://1.1.1.1/dns-query".toHttpUrl()) + .bootstrapDnsHosts(InetAddress.getByName("1.1.1.1")) + .includeHttps(true) + .build() + ) + .build() + + @Test + fun testHttpsRequest() { + val cloudflareBody = client.sendRequest( + Request.Builder().url("https://crypto.cloudflare.com/cdn-cgi/trace").build() + ) { + it.body.string() + } + assertThat(cloudflareBody).matchesPredicate { it.contains("sni=encrypted") } + + val tlsEchBody = client.sendRequest(Request.Builder().url("https://tls-ech.dev/").build()) { + it.body.string() + } + assertThat(tlsEchBody).matchesPredicate { it.contains("You are using ECH. :)") } + } + + private fun OkHttpClient.sendRequest(request: Request, fn: (Response) -> T): T { + val response = newCall(request).execute() + + return response.use { + fn(it) + } + } +} diff --git a/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/ConscryptPlatform.kt b/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/ConscryptPlatform.kt index c309dc598000..543543ad9130 100644 --- a/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/ConscryptPlatform.kt +++ b/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/ConscryptPlatform.kt @@ -29,6 +29,7 @@ import okhttp3.Protocol import okio.ByteString import org.conscrypt.Conscrypt import org.conscrypt.ConscryptHostnameVerifier +import org.conscrypt.EchParameters /** * Platform using Conscrypt (conscrypt.org) if installed as the first Security Provider. @@ -88,6 +89,9 @@ class ConscryptPlatform private constructor() : Platform() { // Enable ALPN. val names = alpnProtocolNames(protocols) Conscrypt.setApplicationProtocols(sslSocket, names.toTypedArray()) + + // Enable ECH parameters. + Conscrypt.setEchParameters(sslSocket, EchParameters(true, echConfigList?.toByteArray())) } else { super.configureTlsExtensions(sslSocket, hostname, protocols, echConfigList) } diff --git a/settings.gradle.kts b/settings.gradle.kts index 12a2b495f972..9f8fd1385710 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -15,6 +15,7 @@ dependencyResolutionManagement { repositories { mavenCentral() google() + mavenLocal() } } From 09b832de4942c8dc1fa2a416abf6d1aa75eb3167 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Mon, 10 Aug 2026 14:15:28 -0400 Subject: [PATCH 2/2] Track API changes --- .../src/test/java/okhttp3/dnsoverhttps/EchRemoteTest.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/EchRemoteTest.kt b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/EchRemoteTest.kt index 428deb78b9f5..d02296144908 100644 --- a/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/EchRemoteTest.kt +++ b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/EchRemoteTest.kt @@ -43,7 +43,6 @@ class EchRemoteTest { .client(clientTestRule.newClient()) .url("https://1.1.1.1/dns-query".toHttpUrl()) .bootstrapDnsHosts(InetAddress.getByName("1.1.1.1")) - .includeHttps(true) .build() ) .build()