1
0
mirror of https://github.com/square/okhttp.git synced 2025-11-24 18:41:06 +03:00

HandshakeCertificates.Builder.addInsecureHost()

This API continues the work started here:
https://github.com/square/okhttp/pull/5872
This commit is contained in:
Jesse Wilson
2020-05-09 22:04:50 -04:00
parent e31cb03d86
commit 1364ea44ae
11 changed files with 368 additions and 313 deletions

View File

@@ -13,6 +13,7 @@ dependencies {
implementation deps.bouncycastlepkix
implementation deps.bouncycastletls
compileOnly deps.jsr305
compileOnly deps.animalSniffer
testImplementation project(':okhttp-testing-support')
testImplementation deps.junit

View File

@@ -18,6 +18,7 @@ package okhttp3.tls
import java.security.SecureRandom
import java.security.cert.X509Certificate
import java.util.Collections
import javax.net.ssl.HostnameVerifier
import javax.net.ssl.KeyManager
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocketFactory
@@ -26,6 +27,7 @@ import javax.net.ssl.X509KeyManager
import javax.net.ssl.X509TrustManager
import okhttp3.CertificatePinner
import okhttp3.internal.platform.Platform
import okhttp3.internal.toImmutableList
import okhttp3.tls.internal.TlsUtil.newKeyManager
import okhttp3.tls.internal.TlsUtil.newTrustManager
@@ -97,6 +99,7 @@ class HandshakeCertificates private constructor(
private var heldCertificate: HeldCertificate? = null
private var intermediates: Array<X509Certificate>? = null
private val trustedCertificates = mutableListOf<X509Certificate>()
private val insecureHosts = mutableListOf<String>()
/**
* Configure the certificate chain to use when being authenticated. The first certificate is
@@ -140,9 +143,37 @@ class HandshakeCertificates private constructor(
Collections.addAll(trustedCertificates, *platformTrustManager.acceptedIssuers)
}
/**
* Configures this to not authenticate the HTTPS server on to [hostname]. This makes the user
* vulnerable to man-in-the-middle attacks and should only be used only in private development
* environments and only to carry test data.
*
* The servers TLS certificate **does not need to be signed** by a trusted certificate
* authority. Instead, it will trust any well-formed certificate, even if it is self-signed.
* This is necessary for testing against localhost or in development environments where a
* certificate authority is not possible.
*
* The servers TLS certificate still must match the requested hostname. For example, if the
* certificate is issued to `example.com` and the request is to `localhost`, the connection will
* fail. Use a custom [HostnameVerifier] to ignore such problems.
*
* Other TLS features are still used but provide no security benefits in absence of the above
* gaps. For example, an insecure TLS connection is capable of negotiating HTTP/2 with ALPN and
* it also has a regular-looking handshake.
*
* **This feature is not supported on Android API levels less than 24.** Prior releases lacked
* a mechanism to trust some hosts and not others.
*
* @param hostname the exact hostname from the URL for insecure connections.
*/
fun addInsecureHost(hostname: String) = apply {
insecureHosts += hostname
}
fun build(): HandshakeCertificates {
val immutableInsecureHosts = insecureHosts.toImmutableList()
val keyManager = newKeyManager(null, heldCertificate, *(intermediates ?: emptyArray()))
val trustManager = newTrustManager(null, trustedCertificates)
val trustManager = newTrustManager(null, trustedCertificates, immutableInsecureHosts)
return HandshakeCertificates(keyManager, trustManager)
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2020 Square, Inc.
*
* 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.tls.internal
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
import java.security.cert.Certificate
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import javax.net.ssl.X509TrustManager
/** This extends [X509TrustManager] for Android to disable verification for a set of hosts. */
internal class InsecureAndroidTrustManager(
private val delegate: X509TrustManager,
private val insecureHosts: List<String>
) : X509TrustManager {
private val checkServerTrustedMethod: Method? = try {
delegate::class.java.getMethod("checkServerTrusted",
Array<X509Certificate>::class.java, String::class.java, String::class.java)
} catch (_: NoSuchMethodException) {
null
}
/** Android method to clean and sort certificates, called via reflection. */
@Suppress("unused", "UNCHECKED_CAST")
fun checkServerTrusted(
chain: Array<out X509Certificate>,
authType: String,
host: String
): List<Certificate> {
if (host in insecureHosts) return listOf()
try {
val method = checkServerTrustedMethod
?: throw CertificateException("Failed to call checkServerTrusted")
return method.invoke(this, chain, authType, host) as List<Certificate>
} catch (e: InvocationTargetException) {
throw e.targetException
}
}
override fun getAcceptedIssuers(): Array<X509Certificate> = delegate.acceptedIssuers
override fun checkClientTrusted(chain: Array<out X509Certificate>, authType: String?) =
throw CertificateException("Unsupported operation")
override fun checkServerTrusted(chain: Array<out X509Certificate>, authType: String) =
throw CertificateException("Unsupported operation")
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2020 Square, Inc.
*
* 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.tls.internal
import java.net.Socket
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import javax.net.ssl.SSLEngine
import javax.net.ssl.X509ExtendedTrustManager
import okhttp3.internal.peerName
import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
/**
* This extends [X509ExtendedTrustManager] to disable verification for a set of hosts.
*
* Note that the superclass [X509ExtendedTrustManager] isn't available on Android until version 7
* (API level 24).
*/
@IgnoreJRERequirement
internal class InsecureExtendedTrustManager(
private val delegate: X509ExtendedTrustManager,
private val insecureHosts: List<String>
) : X509ExtendedTrustManager() {
override fun getAcceptedIssuers(): Array<X509Certificate> = delegate.acceptedIssuers
override fun checkServerTrusted(
chain: Array<out X509Certificate>,
authType: String,
socket: Socket
) {
if (socket.peerName() !in insecureHosts) {
delegate.checkServerTrusted(chain, authType, socket)
}
}
override fun checkServerTrusted(
chain: Array<out X509Certificate>,
authType: String,
engine: SSLEngine
) {
if (engine.peerHost !in insecureHosts) {
delegate.checkServerTrusted(chain, authType, engine)
}
}
override fun checkServerTrusted(chain: Array<out X509Certificate>, authType: String) =
throw CertificateException("Unsupported operation")
override fun checkClientTrusted(chain: Array<out X509Certificate>, authType: String?) =
throw CertificateException("Unsupported operation")
override fun checkClientTrusted(
chain: Array<out X509Certificate>,
authType: String,
engine: SSLEngine?
) = throw CertificateException("Unsupported operation")
override fun checkClientTrusted(
chain: Array<out X509Certificate>,
authType: String,
socket: Socket?
) = throw CertificateException("Unsupported operation")
}

View File

@@ -22,10 +22,13 @@ import java.security.cert.Certificate
import java.security.cert.X509Certificate
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509ExtendedTrustManager
import javax.net.ssl.X509KeyManager
import javax.net.ssl.X509TrustManager
import okhttp3.internal.platform.AndroidPlatform
import okhttp3.tls.HandshakeCertificates
import okhttp3.tls.HeldCertificate
import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
object TlsUtil {
val password = "password".toCharArray()
@@ -47,10 +50,11 @@ object TlsUtil {
fun localhost(): HandshakeCertificates = localhost
/** Returns a trust manager that trusts `trustedCertificates`. */
@JvmStatic
@JvmStatic @IgnoreJRERequirement
fun newTrustManager(
keyStoreType: String?,
trustedCertificates: List<X509Certificate>
trustedCertificates: List<X509Certificate>,
insecureHosts: List<String>
): X509TrustManager {
val trustStore = newEmptyKeyStore(keyStoreType)
for (i in trustedCertificates.indices) {
@@ -64,7 +68,13 @@ object TlsUtil {
"Unexpected trust managers: ${result.contentToString()}"
}
return result[0] as X509TrustManager
val trustManager = result[0] as X509TrustManager
return when {
insecureHosts.isEmpty() -> trustManager
AndroidPlatform.isAndroid -> InsecureAndroidTrustManager(trustManager, insecureHosts)
else -> InsecureExtendedTrustManager(trustManager as X509ExtendedTrustManager, insecureHosts)
}
}
/**

View File

@@ -0,0 +1,114 @@
/*
* Copyright (C) 2020 Square, Inc.
*
* 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
import javax.net.ssl.SSLException
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import okhttp3.testing.PlatformRule
import okhttp3.tls.HandshakeCertificates
import okhttp3.tls.HeldCertificate
import okhttp3.tls.internal.TlsUtil.localhost
import org.assertj.core.api.Assertions.assertThat
import org.junit.Assert.fail
import org.junit.Rule
import org.junit.Test
class InsecureForHostTest {
@JvmField @Rule val platform = PlatformRule()
@JvmField @Rule val server = MockWebServer()
@JvmField @Rule val clientTestRule = OkHttpClientTestRule()
@Test fun `untrusted host in insecureHosts connects successfully`() {
val serverCertificates = localhost()
server.useHttps(serverCertificates.sslSocketFactory(), false)
server.enqueue(MockResponse())
val clientCertificates = HandshakeCertificates.Builder()
.addPlatformTrustedCertificates()
.addInsecureHost(server.hostName)
.build()
val client = clientTestRule.newClientBuilder()
.sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager)
.build()
val call = client.newCall(Request.Builder()
.url(server.url("/"))
.build())
val response = call.execute()
assertThat(response.code).isEqualTo(200)
assertThat(response.handshake!!.cipherSuite).isNotNull()
assertThat(response.handshake!!.tlsVersion).isNotNull()
assertThat(response.handshake!!.localCertificates).isEmpty()
assertThat(response.handshake!!.localPrincipal).isNull()
assertThat(response.handshake!!.peerCertificates).isEmpty()
assertThat(response.handshake!!.peerPrincipal).isNull()
}
@Test fun `bad certificates host in insecureHosts fails with SSLException`() {
val heldCertificate = HeldCertificate.Builder()
.addSubjectAlternativeName("example.com")
.build()
val serverCertificates = HandshakeCertificates.Builder()
.heldCertificate(heldCertificate)
.build()
server.useHttps(serverCertificates.sslSocketFactory(), false)
server.enqueue(MockResponse())
val clientCertificates = HandshakeCertificates.Builder()
.addPlatformTrustedCertificates()
.addInsecureHost(server.hostName)
.build()
val client = clientTestRule.newClientBuilder()
.sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager)
.build()
val call = client.newCall(Request.Builder()
.url(server.url("/"))
.build())
try {
call.execute()
fail()
} catch (expected: SSLException) {
}
}
@Test fun `untrusted host not in insecureHosts fails with SSLException`() {
val serverCertificates = localhost()
server.useHttps(serverCertificates.sslSocketFactory(), false)
server.enqueue(MockResponse())
val clientCertificates = HandshakeCertificates.Builder()
.addPlatformTrustedCertificates()
.addInsecureHost("${server.hostName}2")
.build()
val client = clientTestRule.newClientBuilder()
.sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager)
.build()
val call = client.newCall(Request.Builder()
.url(server.url("/"))
.build())
try {
call.execute()
fail()
} catch (expected: SSLException) {
}
}
}

View File

@@ -355,7 +355,8 @@ public final class CertificatePinnerChainValidationTest {
// http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/2c1c21d11e58/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java#l596
String keystoreType = platform.isJdk9() ? "JKS" : null;
X509KeyManager x509KeyManager = newKeyManager(keystoreType, heldCertificate, intermediates);
X509TrustManager trustManager = newTrustManager(keystoreType, Collections.emptyList());
X509TrustManager trustManager = newTrustManager(
keystoreType, Collections.emptyList(), Collections.emptyList());
SSLContext sslContext = Platform.get().newSSLContext();
sslContext.init(new KeyManager[] {x509KeyManager}, new TrustManager[] {trustManager},
new SecureRandom());

View File

@@ -19,6 +19,7 @@ import java.net.SocketException;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Collections;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
@@ -286,8 +287,8 @@ public final class ClientAuthTest {
try {
X509KeyManager keyManager = newKeyManager(
null, serverCert, serverIntermediateCa.certificate());
X509TrustManager trustManager = newTrustManager(
null, asList(serverRootCa.certificate(), clientRootCa.certificate()));
X509TrustManager trustManager = newTrustManager(null,
asList(serverRootCa.certificate(), clientRootCa.certificate()), Collections.emptyList());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(new KeyManager[] {keyManager}, new TrustManager[] {trustManager},
new SecureRandom());

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2020 Square, Inc.
*
* 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.recipes.kt
import java.io.IOException
import java.net.HttpURLConnection.HTTP_MOVED_TEMP
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import okhttp3.tls.HandshakeCertificates
import okhttp3.tls.internal.TlsUtil
class DevServer {
val handshakeCertificates = TlsUtil.localhost()
val server = MockWebServer().apply {
useHttps(handshakeCertificates.sslSocketFactory(), false)
enqueue(MockResponse()
.setResponseCode(HTTP_MOVED_TEMP)
.setHeader("Location", "https://www.google.com/robots.txt"))
}
val clientCertificates = HandshakeCertificates.Builder()
.addPlatformTrustedCertificates()
.addInsecureHost(server.hostName)
.build()
val client = OkHttpClient.Builder()
.sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager)
.build()
fun run() {
try {
val request = Request.Builder()
.url(server.url("/"))
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw IOException("Unexpected code $response")
println(response.request.url)
}
} finally {
server.shutdown()
}
}
}
fun main() {
DevServer().run()
}

View File

@@ -1,152 +0,0 @@
/*
* Copyright (C) 2020 Square, Inc.
*
* 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.recipes.kt
import java.io.IOException
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
import java.net.HttpURLConnection.HTTP_MOVED_TEMP
import java.security.KeyStore
import java.security.cert.Certificate
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.internal.platform.Platform
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import okhttp3.tls.internal.TlsUtil
class AndroidAllowlistedTrustManager(
private val delegate: X509TrustManager,
private vararg val hosts: String
) : X509TrustManager {
val delegateMethod = lookupDelegateMethod()
override fun checkClientTrusted(chain: Array<out X509Certificate>, authType: String?) {
delegate.checkClientTrusted(chain, authType)
}
override fun checkServerTrusted(chain: Array<out X509Certificate>, authType: String) {
throw CertificateException("Unsupported operation")
}
/**
* Android method to clean and sort certificates, called via reflection.
*/
fun checkServerTrusted(
chain: Array<out X509Certificate>,
authType: String,
host: String
): List<Certificate> {
if (isAllowed(host)) {
println("Skipping security checks for $host")
println(chain.map { it.subjectDN.name })
return listOf()
}
println("Running security checks for $host")
println(chain.map { it.subjectDN.name }.take(1))
if (delegateMethod != null) {
return invokeDelegateMethod(delegateMethod, chain, authType, host)
}
throw CertificateException("Failed to call checkServerTrusted")
}
fun isAllowed(host: String): Boolean = hosts.contains(host)
override fun getAcceptedIssuers(): Array<X509Certificate> = delegate.acceptedIssuers
private fun lookupDelegateMethod(): Method? {
return try {
delegate.javaClass.getMethod("checkServerTrusted",
Array<X509Certificate>::class.java, String::class.java, String::class.java)
} catch (nsme: NoSuchMethodException) {
null
}
}
@Suppress("UNCHECKED_CAST")
private fun invokeDelegateMethod(
delegateMethod: Method,
chain: Array<out X509Certificate>,
authType: String,
host: String
): List<Certificate> {
try {
return delegateMethod.invoke(delegate, chain, authType, host) as List<Certificate>
} catch (ite: InvocationTargetException) {
throw ite.targetException
}
}
}
class DevServerAndroid {
val handshakeCertificates = TlsUtil.localhost()
val server = MockWebServer().apply {
useHttps(handshakeCertificates.sslSocketFactory(), false)
enqueue(MockResponse()
.setResponseCode(HTTP_MOVED_TEMP)
.setHeader("Location", "https://www.google.com/robots.txt"))
}
val hosts = arrayOf(server.hostName)
val platformTrustManager = platformTrustManager()
val trustManager = AndroidAllowlistedTrustManager(platformTrustManager, *hosts)
val sslSocketFactory = Platform.get().newSSLContext().apply {
init(null, arrayOf(trustManager), null)
}.socketFactory
val client = OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustManager)
.build()
fun platformTrustManager(): X509TrustManager {
val factory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm())
factory.init(null as KeyStore?)
return factory.trustManagers!![0] as X509TrustManager
}
fun run() {
try {
val request = Request.Builder()
.url(server.url("/"))
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw IOException("Unexpected code $response")
println(response.request.url)
}
} finally {
server.shutdown()
}
}
}
fun main() {
DevServerAndroid().run()
}

View File

@@ -1,154 +0,0 @@
/*
* Copyright (C) 2020 Square, Inc.
*
* 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.recipes.kt
import java.io.IOException
import java.net.HttpURLConnection.HTTP_MOVED_TEMP
import java.net.Socket
import java.security.KeyStore
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import javax.net.ssl.SSLEngine
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509ExtendedTrustManager
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.internal.platform.Platform
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import okhttp3.tls.internal.TlsUtil
import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
@IgnoreJRERequirement
class JvmAllowlistedTrustManager(
private val delegate: X509ExtendedTrustManager,
private vararg val hosts: String
) : X509ExtendedTrustManager() {
override fun checkClientTrusted(chain: Array<out X509Certificate>, authType: String?) {
throw CertificateException("Unsupported client operation")
}
override fun checkClientTrusted(
chain: Array<out X509Certificate>?,
authType: String?,
engine: SSLEngine?
) {
throw CertificateException("Unsupported client operation")
}
override fun checkClientTrusted(
chain: Array<out X509Certificate>?,
authType: String?,
socket: Socket?
) {
throw CertificateException("Unsupported client operation")
}
override fun checkServerTrusted(chain: Array<out X509Certificate>, authType: String) {
throw CertificateException("Unsupported operation")
}
override fun checkServerTrusted(
chain: Array<out X509Certificate>,
authType: String,
socket: Socket
) {
val host = socket.inetAddress.hostName
if (isAllowed(host)) {
println("Skipping security checks for $host")
println(chain.map { it.subjectDN.name })
} else {
println("Running security checks for $host")
println(chain.map { it.subjectDN.name }.take(1))
delegate.checkServerTrusted(chain, authType, socket)
}
}
override fun checkServerTrusted(
chain: Array<out X509Certificate>,
authType: String,
engine: SSLEngine
) {
val host = engine.peerHost
if (isAllowed(host)) {
println("Skipping security checks for $host")
println(chain.map { it.subjectDN.name })
} else {
println("Running security checks for $host")
println(chain.map { it.subjectDN.name }.take(1))
delegate.checkServerTrusted(chain, authType, engine)
}
}
fun isAllowed(host: String): Boolean = hosts.contains(host)
override fun getAcceptedIssuers(): Array<X509Certificate> = delegate.acceptedIssuers
}
@IgnoreJRERequirement
class DevServerJvm {
val handshakeCertificates = TlsUtil.localhost()
val server = MockWebServer().apply {
useHttps(handshakeCertificates.sslSocketFactory(), false)
enqueue(MockResponse()
.setResponseCode(HTTP_MOVED_TEMP)
.setHeader("Location", "https://www.google.com/robots.txt"))
}
val hosts = arrayOf(server.hostName)
val platformTrustManager = platformTrustManager()
val trustManager = JvmAllowlistedTrustManager(platformTrustManager, *hosts)
val sslSocketFactory = Platform.get().newSSLContext().apply {
init(null, arrayOf(trustManager), null)
}.socketFactory
val client = OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustManager)
.build()
fun platformTrustManager(): X509ExtendedTrustManager {
val factory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm())
factory.init(null as KeyStore?)
return factory.trustManagers!![0] as X509ExtendedTrustManager
}
fun run() {
try {
val request = Request.Builder()
.url(server.url("/"))
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw IOException("Unexpected code $response")
println(response.request.url)
}
} finally {
server.shutdown()
}
}
}
fun main() {
DevServerJvm().run()
}