mirror of
https://github.com/square/okhttp.git
synced 2025-08-08 23:42:08 +03:00
OpenJSSE Platform support (#5369)
Adds support for OpenJSSE when registered as the first security provider.
This commit is contained in:
@@ -140,6 +140,20 @@ jobs:
|
|||||||
- runtests:
|
- runtests:
|
||||||
platform: jdk8alpn
|
platform: jdk8alpn
|
||||||
|
|
||||||
|
testopenjsse:
|
||||||
|
docker:
|
||||||
|
- image: circleci/openjdk:8u171-jdk
|
||||||
|
|
||||||
|
environment:
|
||||||
|
JVM_OPTS: -Xmx1g
|
||||||
|
TERM: dumb
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
|
||||||
|
- runtests:
|
||||||
|
platform: openjsse
|
||||||
|
|
||||||
testjdk11:
|
testjdk11:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/openjdk:11.0.3-jdk-stretch
|
- image: circleci/openjdk:11.0.3-jdk-stretch
|
||||||
@@ -205,6 +219,11 @@ workflows:
|
|||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only: master
|
only: master
|
||||||
|
- testopenjsse:
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
ignore:
|
||||||
|
- gh-pages
|
||||||
- testjdk11:
|
- testjdk11:
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
@@ -236,6 +255,9 @@ workflows:
|
|||||||
- testjdk8alpn:
|
- testjdk8alpn:
|
||||||
requires:
|
requires:
|
||||||
- compile
|
- compile
|
||||||
|
- testopenjsse:
|
||||||
|
requires:
|
||||||
|
- compile
|
||||||
- testjdk11:
|
- testjdk11:
|
||||||
requires:
|
requires:
|
||||||
- compile
|
- compile
|
||||||
|
@@ -159,6 +159,10 @@ subprojects { project ->
|
|||||||
dependencies {
|
dependencies {
|
||||||
testRuntime "org.conscrypt:conscrypt-openjdk-uber:${versions.conscrypt}"
|
testRuntime "org.conscrypt:conscrypt-openjdk-uber:${versions.conscrypt}"
|
||||||
}
|
}
|
||||||
|
} else if (platform == "openjsse") {
|
||||||
|
dependencies {
|
||||||
|
testRuntime deps.openjsse
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@@ -3,6 +3,7 @@ dependencies {
|
|||||||
api deps.junit
|
api deps.junit
|
||||||
api deps.assertj
|
api deps.assertj
|
||||||
api deps.conscrypt
|
api deps.conscrypt
|
||||||
|
api deps.openjsse
|
||||||
|
|
||||||
compileOnly deps.jsr305
|
compileOnly deps.jsr305
|
||||||
}
|
}
|
||||||
|
@@ -15,12 +15,16 @@
|
|||||||
*/
|
*/
|
||||||
package okhttp3;
|
package okhttp3;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import okhttp3.internal.http2.Header;
|
import okhttp3.internal.http2.Header;
|
||||||
|
|
||||||
|
import static org.junit.Assume.assumeNoException;
|
||||||
|
|
||||||
public final class TestUtil {
|
public final class TestUtil {
|
||||||
public static final InetSocketAddress UNREACHABLE_ADDRESS
|
public static final InetSocketAddress UNREACHABLE_ADDRESS
|
||||||
= new InetSocketAddress("198.51.100.1", 8080);
|
= new InetSocketAddress("198.51.100.1", 8080);
|
||||||
@@ -52,4 +56,12 @@ public final class TestUtil {
|
|||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
System.runFinalization();
|
System.runFinalization();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void assumeNetwork() {
|
||||||
|
try {
|
||||||
|
InetAddress.getByName("www.google.com");
|
||||||
|
} catch (UnknownHostException uhe) {
|
||||||
|
assumeNoException(uhe);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,6 +18,7 @@ package okhttp3.testing
|
|||||||
import okhttp3.internal.platform.ConscryptPlatform
|
import okhttp3.internal.platform.ConscryptPlatform
|
||||||
import okhttp3.internal.platform.Jdk8WithJettyBootPlatform
|
import okhttp3.internal.platform.Jdk8WithJettyBootPlatform
|
||||||
import okhttp3.internal.platform.Jdk9Platform
|
import okhttp3.internal.platform.Jdk9Platform
|
||||||
|
import okhttp3.internal.platform.OpenJSSEPlatform
|
||||||
import okhttp3.internal.platform.Platform
|
import okhttp3.internal.platform.Platform
|
||||||
import org.conscrypt.Conscrypt
|
import org.conscrypt.Conscrypt
|
||||||
import org.hamcrest.BaseMatcher
|
import org.hamcrest.BaseMatcher
|
||||||
@@ -34,6 +35,7 @@ import org.junit.Assume.assumeTrue
|
|||||||
import org.junit.AssumptionViolatedException
|
import org.junit.AssumptionViolatedException
|
||||||
import org.junit.rules.TestRule
|
import org.junit.rules.TestRule
|
||||||
import org.junit.runners.model.Statement
|
import org.junit.runners.model.Statement
|
||||||
|
import org.openjsse.net.ssl.OpenJSSE
|
||||||
import java.security.Security
|
import java.security.Security
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,6 +59,8 @@ open class PlatformRule @JvmOverloads constructor(
|
|||||||
try {
|
try {
|
||||||
setupPlatform()
|
setupPlatform()
|
||||||
|
|
||||||
|
System.err.println("Running with ${Platform.get().javaClass.simpleName}")
|
||||||
|
|
||||||
base.evaluate()
|
base.evaluate()
|
||||||
} catch (e: AssumptionViolatedException) {
|
} catch (e: AssumptionViolatedException) {
|
||||||
throw e
|
throw e
|
||||||
@@ -95,6 +99,10 @@ open class PlatformRule @JvmOverloads constructor(
|
|||||||
expectFailure(platformMatches(CONSCRYPT_PROPERTY))
|
expectFailure(platformMatches(CONSCRYPT_PROPERTY))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun expectFailureOnOpenJSSEPlatform() {
|
||||||
|
expectFailure(platformMatches(OPENJSSE_PROPERTY))
|
||||||
|
}
|
||||||
|
|
||||||
fun expectFailureFromJdkVersion(majorVersion: Int) {
|
fun expectFailureFromJdkVersion(majorVersion: Int) {
|
||||||
expectFailure(fromMajor(majorVersion))
|
expectFailure(fromMajor(majorVersion))
|
||||||
}
|
}
|
||||||
@@ -118,7 +126,7 @@ open class PlatformRule @JvmOverloads constructor(
|
|||||||
|
|
||||||
fun fromMajor(version: Int): Matcher<PlatformVersion> {
|
fun fromMajor(version: Int): Matcher<PlatformVersion> {
|
||||||
return object : TypeSafeMatcher<PlatformVersion>() {
|
return object : TypeSafeMatcher<PlatformVersion>() {
|
||||||
override fun describeTo(description: org.hamcrest.Description) {
|
override fun describeTo(description: Description) {
|
||||||
description.appendText("JDK with version from $version")
|
description.appendText("JDK with version from $version")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,6 +179,11 @@ open class PlatformRule @JvmOverloads constructor(
|
|||||||
JDK9_PROPERTY))
|
JDK9_PROPERTY))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun assumeOpenJSSE() {
|
||||||
|
assumeThat(getPlatformSystemProperty(), equalTo(
|
||||||
|
OPENJSSE_PROPERTY))
|
||||||
|
}
|
||||||
|
|
||||||
fun assumeJdk8() {
|
fun assumeJdk8() {
|
||||||
assumeThat(getPlatformSystemProperty(), equalTo(
|
assumeThat(getPlatformSystemProperty(), equalTo(
|
||||||
JDK8_PROPERTY))
|
JDK8_PROPERTY))
|
||||||
@@ -206,6 +219,11 @@ open class PlatformRule @JvmOverloads constructor(
|
|||||||
JDK8_ALPN_PROPERTY))
|
JDK8_ALPN_PROPERTY))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun assumeNotOpenJSSE() {
|
||||||
|
assumeThat(getPlatformSystemProperty(), not(
|
||||||
|
OPENJSSE_PROPERTY))
|
||||||
|
}
|
||||||
|
|
||||||
fun assumeNotHttp2Support() {
|
fun assumeNotHttp2Support() {
|
||||||
assumeThat(getPlatformSystemProperty(), equalTo(
|
assumeThat(getPlatformSystemProperty(), equalTo(
|
||||||
JDK8_PROPERTY))
|
JDK8_PROPERTY))
|
||||||
@@ -221,6 +239,7 @@ open class PlatformRule @JvmOverloads constructor(
|
|||||||
const val JDK9_PROPERTY = "jdk9"
|
const val JDK9_PROPERTY = "jdk9"
|
||||||
const val JDK8_ALPN_PROPERTY = "jdk8alpn"
|
const val JDK8_ALPN_PROPERTY = "jdk8alpn"
|
||||||
const val JDK8_PROPERTY = "jdk8"
|
const val JDK8_PROPERTY = "jdk8"
|
||||||
|
const val OPENJSSE_PROPERTY = "openjsse"
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (getPlatformSystemProperty() == CONSCRYPT_PROPERTY && Security.getProviders()[0].name != "Conscrypt") {
|
if (getPlatformSystemProperty() == CONSCRYPT_PROPERTY && Security.getProviders()[0].name != "Conscrypt") {
|
||||||
@@ -238,7 +257,15 @@ open class PlatformRule @JvmOverloads constructor(
|
|||||||
if (isAlpnBootEnabled()) {
|
if (isAlpnBootEnabled()) {
|
||||||
System.err.println("Warning: ALPN Boot enabled unintentionally")
|
System.err.println("Warning: ALPN Boot enabled unintentionally")
|
||||||
}
|
}
|
||||||
|
} else if (getPlatformSystemProperty() == OPENJSSE_PROPERTY && Security.getProviders()[0].name != "OpenJSSE") {
|
||||||
|
if (!OpenJSSEPlatform.isSupported) {
|
||||||
|
System.err.println("Warning: OpenJSSE not available")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Security.insertProviderAt(OpenJSSE(), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform.resetForTests()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@@ -249,6 +276,7 @@ open class PlatformRule @JvmOverloads constructor(
|
|||||||
if (property == null) {
|
if (property == null) {
|
||||||
property = when (Platform.get()) {
|
property = when (Platform.get()) {
|
||||||
is ConscryptPlatform -> CONSCRYPT_PROPERTY
|
is ConscryptPlatform -> CONSCRYPT_PROPERTY
|
||||||
|
is OpenJSSEPlatform -> OPENJSSE_PROPERTY
|
||||||
is Jdk8WithJettyBootPlatform -> CONSCRYPT_PROPERTY
|
is Jdk8WithJettyBootPlatform -> CONSCRYPT_PROPERTY
|
||||||
is Jdk9Platform -> JDK9_PROPERTY
|
is Jdk9Platform -> JDK9_PROPERTY
|
||||||
else -> JDK8_PROPERTY
|
else -> JDK8_PROPERTY
|
||||||
@@ -261,6 +289,9 @@ open class PlatformRule @JvmOverloads constructor(
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun conscrypt() = PlatformRule(CONSCRYPT_PROPERTY)
|
fun conscrypt() = PlatformRule(CONSCRYPT_PROPERTY)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun openjsse() = PlatformRule(OPENJSSE_PROPERTY)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun jdk9() = PlatformRule(JDK9_PROPERTY)
|
fun jdk9() = PlatformRule(JDK9_PROPERTY)
|
||||||
|
|
||||||
|
@@ -26,6 +26,7 @@ dependencies {
|
|||||||
api deps.okio
|
api deps.okio
|
||||||
api deps.kotlinStdlib
|
api deps.kotlinStdlib
|
||||||
compileOnly deps.conscrypt
|
compileOnly deps.conscrypt
|
||||||
|
compileOnly deps.openjsse
|
||||||
compileOnly deps.android
|
compileOnly deps.android
|
||||||
compileOnly deps.jsr305
|
compileOnly deps.jsr305
|
||||||
compileOnly deps.animalSniffer
|
compileOnly deps.animalSniffer
|
||||||
|
@@ -542,3 +542,27 @@ inline fun Any.notify() = (this as Object).notify()
|
|||||||
|
|
||||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "NOTHING_TO_INLINE")
|
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "NOTHING_TO_INLINE")
|
||||||
inline fun Any.notifyAll() = (this as Object).notifyAll()
|
inline fun Any.notifyAll() = (this as Object).notifyAll()
|
||||||
|
|
||||||
|
fun <T> readFieldOrNull(instance: Any, fieldType: Class<T>, fieldName: String): T? {
|
||||||
|
var c: Class<*> = instance.javaClass
|
||||||
|
while (c != Any::class.java) {
|
||||||
|
try {
|
||||||
|
val field = c.getDeclaredField(fieldName)
|
||||||
|
field.isAccessible = true
|
||||||
|
val value = field.get(instance)
|
||||||
|
return if (!fieldType.isInstance(value)) null else fieldType.cast(value)
|
||||||
|
} catch (_: NoSuchFieldException) {
|
||||||
|
}
|
||||||
|
|
||||||
|
c = c.superclass
|
||||||
|
}
|
||||||
|
|
||||||
|
// Didn't find the field we wanted. As a last gasp attempt,
|
||||||
|
// try to find the value on a delegate.
|
||||||
|
if (fieldName != "delegate") {
|
||||||
|
val delegate = readFieldOrNull(instance, Any::class.java, "delegate")
|
||||||
|
if (delegate != null) return readFieldOrNull(delegate, fieldType, fieldName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package okhttp3.internal.platform
|
package okhttp3.internal.platform
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import okhttp3.Protocol
|
import okhttp3.Protocol
|
||||||
import okhttp3.internal.platform.android.CloseGuard
|
import okhttp3.internal.platform.android.CloseGuard
|
||||||
@@ -225,7 +224,6 @@ class AndroidPlatform : Platform() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@SuppressLint("PrivateApi")
|
|
||||||
val isSupported: Boolean = try {
|
val isSupported: Boolean = try {
|
||||||
// Trigger an early exception over a fatal error, prefer a RuntimeException over Error.
|
// Trigger an early exception over a fatal error, prefer a RuntimeException over Error.
|
||||||
Class.forName("com.android.org.conscrypt.OpenSSLSocketImpl")
|
Class.forName("com.android.org.conscrypt.OpenSSLSocketImpl")
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
package okhttp3.internal.platform
|
package okhttp3.internal.platform
|
||||||
|
|
||||||
import okhttp3.Protocol
|
import okhttp3.Protocol
|
||||||
|
import okhttp3.internal.readFieldOrNull
|
||||||
import org.conscrypt.Conscrypt
|
import org.conscrypt.Conscrypt
|
||||||
import java.security.Provider
|
import java.security.Provider
|
||||||
import javax.net.ssl.SSLContext
|
import javax.net.ssl.SSLContext
|
||||||
@@ -29,13 +30,9 @@ import javax.net.ssl.X509TrustManager
|
|||||||
* Requires org.conscrypt:conscrypt-openjdk-uber >= 2.1.0 on the classpath.
|
* Requires org.conscrypt:conscrypt-openjdk-uber >= 2.1.0 on the classpath.
|
||||||
*/
|
*/
|
||||||
class ConscryptPlatform private constructor() : Platform() {
|
class ConscryptPlatform private constructor() : Platform() {
|
||||||
private val provider: Provider
|
|
||||||
get() {
|
|
||||||
// n.b. We should consider defaulting to OpenJDK 11 trust manager
|
// n.b. We should consider defaulting to OpenJDK 11 trust manager
|
||||||
// https://groups.google.com/forum/#!topic/conscrypt/3vYzbesjOb4
|
// https://groups.google.com/forum/#!topic/conscrypt/3vYzbesjOb4
|
||||||
|
private val provider: Provider = Conscrypt.newProviderBuilder().provideTrustManager(true).build()
|
||||||
return Conscrypt.newProviderBuilder().provideTrustManager(true).build()
|
|
||||||
}
|
|
||||||
|
|
||||||
// See release notes https://groups.google.com/forum/#!forum/conscrypt
|
// See release notes https://groups.google.com/forum/#!forum/conscrypt
|
||||||
// for version differences
|
// for version differences
|
||||||
|
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.internal.platform
|
||||||
|
|
||||||
|
import okhttp3.Protocol
|
||||||
|
import java.security.KeyStore
|
||||||
|
import java.security.Provider
|
||||||
|
import javax.net.ssl.SSLContext
|
||||||
|
import javax.net.ssl.SSLSocket
|
||||||
|
import javax.net.ssl.SSLSocketFactory
|
||||||
|
import javax.net.ssl.TrustManagerFactory
|
||||||
|
import javax.net.ssl.X509TrustManager
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Platform using OpenJSSE (https://github.com/openjsse/openjsse) if installed as the first
|
||||||
|
* Security Provider.
|
||||||
|
*
|
||||||
|
* Requires org.openjsse:openjsse >= 1.1.0 on the classpath.
|
||||||
|
*/
|
||||||
|
class OpenJSSEPlatform private constructor() : Platform() {
|
||||||
|
private val provider: Provider = org.openjsse.net.ssl.OpenJSSE()
|
||||||
|
|
||||||
|
// Selects TLSv1.3 so we are specific about our intended version ranges (not just 1.3)
|
||||||
|
// and because it's a common pattern for VMs to have differences between supported and
|
||||||
|
// defaulted versions for TLS based on what is requested.
|
||||||
|
override fun newSSLContext(): SSLContext =
|
||||||
|
SSLContext.getInstance("TLSv1.3", provider)
|
||||||
|
|
||||||
|
override fun platformTrustManager(): X509TrustManager {
|
||||||
|
val factory = TrustManagerFactory.getInstance(
|
||||||
|
TrustManagerFactory.getDefaultAlgorithm(), provider)
|
||||||
|
factory.init(null as KeyStore?)
|
||||||
|
val trustManagers = factory.trustManagers!!
|
||||||
|
check(trustManagers.size == 1 && trustManagers[0] is X509TrustManager) {
|
||||||
|
"Unexpected default trust managers: ${trustManagers.contentToString()}"
|
||||||
|
}
|
||||||
|
return trustManagers[0] as X509TrustManager
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager? =
|
||||||
|
throw UnsupportedOperationException(
|
||||||
|
"clientBuilder.sslSocketFactory(SSLSocketFactory) not supported with OpenJSSE")
|
||||||
|
|
||||||
|
override fun configureTlsExtensions(
|
||||||
|
sslSocket: SSLSocket,
|
||||||
|
hostname: String?,
|
||||||
|
protocols: List<Protocol>
|
||||||
|
) {
|
||||||
|
if (sslSocket is org.openjsse.javax.net.ssl.SSLSocket) {
|
||||||
|
val sslParameters = sslSocket.sslParameters
|
||||||
|
|
||||||
|
if (sslParameters is org.openjsse.javax.net.ssl.SSLParameters) {
|
||||||
|
// Enable ALPN.
|
||||||
|
val names = alpnProtocolNames(protocols)
|
||||||
|
sslParameters.applicationProtocols = names.toTypedArray()
|
||||||
|
|
||||||
|
sslSocket.sslParameters = sslParameters
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.configureTlsExtensions(sslSocket, hostname, protocols)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSelectedProtocol(sslSocket: SSLSocket): String? =
|
||||||
|
if (sslSocket is org.openjsse.javax.net.ssl.SSLSocket) {
|
||||||
|
when (val protocol = sslSocket.applicationProtocol) {
|
||||||
|
// Handles both un-configured and none selected.
|
||||||
|
null, "" -> null
|
||||||
|
else -> protocol
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.getSelectedProtocol(sslSocket)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val isSupported: Boolean = try {
|
||||||
|
// Trigger an early exception over a fatal error, prefer a RuntimeException over Error.
|
||||||
|
Class.forName("org.openjsse.net.ssl.OpenJSSE")
|
||||||
|
|
||||||
|
true
|
||||||
|
} catch (_: ClassNotFoundException) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun buildIfSupported(): OpenJSSEPlatform? = if (isSupported) OpenJSSEPlatform() else null
|
||||||
|
}
|
||||||
|
}
|
@@ -18,6 +18,7 @@ package okhttp3.internal.platform
|
|||||||
|
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Protocol
|
import okhttp3.Protocol
|
||||||
|
import okhttp3.internal.readFieldOrNull
|
||||||
import okhttp3.internal.tls.BasicCertificateChainCleaner
|
import okhttp3.internal.tls.BasicCertificateChainCleaner
|
||||||
import okhttp3.internal.tls.BasicTrustRootIndex
|
import okhttp3.internal.tls.BasicTrustRootIndex
|
||||||
import okhttp3.internal.tls.CertificateChainCleaner
|
import okhttp3.internal.tls.CertificateChainCleaner
|
||||||
@@ -193,12 +194,18 @@ open class Platform {
|
|||||||
fun alpnProtocolNames(protocols: List<Protocol>) =
|
fun alpnProtocolNames(protocols: List<Protocol>) =
|
||||||
protocols.filter { it != Protocol.HTTP_1_0 }.map { it.toString() }
|
protocols.filter { it != Protocol.HTTP_1_0 }.map { it.toString() }
|
||||||
|
|
||||||
val isConscryptPreferred: Boolean
|
private val isConscryptPreferred: Boolean
|
||||||
get() {
|
get() {
|
||||||
val preferredProvider = Security.getProviders()[0].name
|
val preferredProvider = Security.getProviders()[0].name
|
||||||
return "Conscrypt" == preferredProvider
|
return "Conscrypt" == preferredProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val isOpenJSSEPreferred: Boolean
|
||||||
|
get() {
|
||||||
|
val preferredProvider = Security.getProviders()[0].name
|
||||||
|
return "OpenJSSE" == preferredProvider
|
||||||
|
}
|
||||||
|
|
||||||
/** Attempt to match the host runtime to a capable Platform implementation. */
|
/** Attempt to match the host runtime to a capable Platform implementation. */
|
||||||
private fun findPlatform(): Platform {
|
private fun findPlatform(): Platform {
|
||||||
val android = AndroidPlatform.buildIfSupported()
|
val android = AndroidPlatform.buildIfSupported()
|
||||||
@@ -215,6 +222,14 @@ open class Platform {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isOpenJSSEPreferred) {
|
||||||
|
val openJSSE = OpenJSSEPlatform.buildIfSupported()
|
||||||
|
|
||||||
|
if (openJSSE != null) {
|
||||||
|
return openJSSE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val jdk9 = Jdk9Platform.buildIfSupported()
|
val jdk9 = Jdk9Platform.buildIfSupported()
|
||||||
|
|
||||||
if (jdk9 != null) {
|
if (jdk9 != null) {
|
||||||
@@ -239,29 +254,5 @@ open class Platform {
|
|||||||
}
|
}
|
||||||
return result.readByteArray()
|
return result.readByteArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> readFieldOrNull(instance: Any, fieldType: Class<T>, fieldName: String): T? {
|
|
||||||
var c: Class<*> = instance.javaClass
|
|
||||||
while (c != Any::class.java) {
|
|
||||||
try {
|
|
||||||
val field = c.getDeclaredField(fieldName)
|
|
||||||
field.isAccessible = true
|
|
||||||
val value = field.get(instance)
|
|
||||||
return if (!fieldType.isInstance(value)) null else fieldType.cast(value)
|
|
||||||
} catch (_: NoSuchFieldException) {
|
|
||||||
}
|
|
||||||
|
|
||||||
c = c.superclass
|
|
||||||
}
|
|
||||||
|
|
||||||
// Didn't find the field we wanted. As a last gasp attempt,
|
|
||||||
// try to find the value on a delegate.
|
|
||||||
if (fieldName != "delegate") {
|
|
||||||
val delegate = readFieldOrNull(instance, Any::class.java, "delegate")
|
|
||||||
if (delegate != null) return readFieldOrNull(delegate, fieldType, fieldName)
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
package okhttp3.internal.platform.android
|
package okhttp3.internal.platform.android
|
||||||
|
|
||||||
import okhttp3.internal.platform.Platform
|
import okhttp3.internal.platform.Platform
|
||||||
|
import okhttp3.internal.readFieldOrNull
|
||||||
import javax.net.ssl.SSLSocket
|
import javax.net.ssl.SSLSocket
|
||||||
import javax.net.ssl.SSLSocketFactory
|
import javax.net.ssl.SSLSocketFactory
|
||||||
import javax.net.ssl.X509TrustManager
|
import javax.net.ssl.X509TrustManager
|
||||||
@@ -35,11 +36,11 @@ class StandardAndroidSocketAdapter(
|
|||||||
|
|
||||||
override fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager? {
|
override fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager? {
|
||||||
val context: Any? =
|
val context: Any? =
|
||||||
Platform.readFieldOrNull(sslSocketFactory, paramClass,
|
readFieldOrNull(sslSocketFactory, paramClass,
|
||||||
"sslParameters")
|
"sslParameters")
|
||||||
val x509TrustManager = Platform.readFieldOrNull(
|
val x509TrustManager = readFieldOrNull(
|
||||||
context!!, X509TrustManager::class.java, "x509TrustManager")
|
context!!, X509TrustManager::class.java, "x509TrustManager")
|
||||||
return x509TrustManager ?: Platform.readFieldOrNull(context,
|
return x509TrustManager ?: readFieldOrNull(context,
|
||||||
X509TrustManager::class.java,
|
X509TrustManager::class.java,
|
||||||
"trustManager")
|
"trustManager")
|
||||||
}
|
}
|
||||||
|
@@ -40,6 +40,7 @@ import okhttp3.internal.platform.Platform;
|
|||||||
import okhttp3.mockwebserver.MockResponse;
|
import okhttp3.mockwebserver.MockResponse;
|
||||||
import okhttp3.mockwebserver.MockWebServer;
|
import okhttp3.mockwebserver.MockWebServer;
|
||||||
import okhttp3.mockwebserver.RecordedRequest;
|
import okhttp3.mockwebserver.RecordedRequest;
|
||||||
|
import okhttp3.testing.PlatformRule;
|
||||||
import okhttp3.tls.HandshakeCertificates;
|
import okhttp3.tls.HandshakeCertificates;
|
||||||
import okio.Buffer;
|
import okio.Buffer;
|
||||||
import okio.BufferedSink;
|
import okio.BufferedSink;
|
||||||
@@ -65,6 +66,7 @@ public final class CacheTest {
|
|||||||
@Rule public MockWebServer server2 = new MockWebServer();
|
@Rule public MockWebServer server2 = new MockWebServer();
|
||||||
@Rule public InMemoryFileSystem fileSystem = new InMemoryFileSystem();
|
@Rule public InMemoryFileSystem fileSystem = new InMemoryFileSystem();
|
||||||
@Rule public final OkHttpClientTestRule clientTestRule = new OkHttpClientTestRule();
|
@Rule public final OkHttpClientTestRule clientTestRule = new OkHttpClientTestRule();
|
||||||
|
@Rule public final PlatformRule platform = new PlatformRule();
|
||||||
|
|
||||||
private final HandshakeCertificates handshakeCertificates = localhost();
|
private final HandshakeCertificates handshakeCertificates = localhost();
|
||||||
private OkHttpClient client;
|
private OkHttpClient client;
|
||||||
@@ -72,6 +74,8 @@ public final class CacheTest {
|
|||||||
private final CookieManager cookieManager = new CookieManager();
|
private final CookieManager cookieManager = new CookieManager();
|
||||||
|
|
||||||
@Before public void setUp() throws Exception {
|
@Before public void setUp() throws Exception {
|
||||||
|
platform.assumeNotOpenJSSE();
|
||||||
|
|
||||||
server.setProtocolNegotiationEnabled(false);
|
server.setProtocolNegotiationEnabled(false);
|
||||||
cache = new Cache(new File("/cache/"), Integer.MAX_VALUE, fileSystem);
|
cache = new Cache(new File("/cache/"), Integer.MAX_VALUE, fileSystem);
|
||||||
client = clientTestRule.newClientBuilder()
|
client = clientTestRule.newClientBuilder()
|
||||||
@@ -82,8 +86,11 @@ public final class CacheTest {
|
|||||||
|
|
||||||
@After public void tearDown() throws Exception {
|
@After public void tearDown() throws Exception {
|
||||||
ResponseCache.setDefault(null);
|
ResponseCache.setDefault(null);
|
||||||
|
|
||||||
|
if (cache != null) {
|
||||||
cache.delete();
|
cache.delete();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that response caching is consistent with the RI and the spec.
|
* Test that response caching is consistent with the RI and the spec.
|
||||||
|
@@ -117,6 +117,8 @@ public final class CallTest {
|
|||||||
private Logger logger = Logger.getLogger(OkHttpClient.class.getName());
|
private Logger logger = Logger.getLogger(OkHttpClient.class.getName());
|
||||||
|
|
||||||
@Before public void setUp() {
|
@Before public void setUp() {
|
||||||
|
platform.assumeNotOpenJSSE();
|
||||||
|
|
||||||
logger.addHandler(logHandler);
|
logger.addHandler(logHandler);
|
||||||
client = clientTestRule.newClientBuilder()
|
client = clientTestRule.newClientBuilder()
|
||||||
.eventListener(listener)
|
.eventListener(listener)
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package okhttp3
|
package okhttp3
|
||||||
|
|
||||||
|
import okhttp3.TestUtil.assumeNetwork
|
||||||
import okhttp3.internal.platform.ConscryptPlatform
|
import okhttp3.internal.platform.ConscryptPlatform
|
||||||
import okhttp3.internal.platform.Platform
|
import okhttp3.internal.platform.Platform
|
||||||
import okhttp3.testing.PlatformRule
|
import okhttp3.testing.PlatformRule
|
||||||
@@ -22,13 +23,10 @@ import org.assertj.core.api.Assertions.assertThat
|
|||||||
import org.conscrypt.Conscrypt
|
import org.conscrypt.Conscrypt
|
||||||
import org.junit.Assert.assertFalse
|
import org.junit.Assert.assertFalse
|
||||||
import org.junit.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Assume
|
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Ignore
|
import org.junit.Ignore
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.net.InetAddress
|
|
||||||
import java.net.UnknownHostException
|
|
||||||
|
|
||||||
class ConscryptTest {
|
class ConscryptTest {
|
||||||
@Suppress("RedundantVisibilityModifier")
|
@Suppress("RedundantVisibilityModifier")
|
||||||
@@ -49,14 +47,6 @@ class ConscryptTest {
|
|||||||
assertThat(Conscrypt.isConscrypt(Platform.get().platformTrustManager())).isTrue()
|
assertThat(Conscrypt.isConscrypt(Platform.get().platformTrustManager())).isTrue()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assumeNetwork() {
|
|
||||||
try {
|
|
||||||
InetAddress.getByName("www.google.com")
|
|
||||||
} catch (uhe: UnknownHostException) {
|
|
||||||
Assume.assumeNoException(uhe)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
@Ignore
|
||||||
fun testMozilla() {
|
fun testMozilla() {
|
||||||
|
@@ -54,6 +54,7 @@ public final class DuplexTest {
|
|||||||
private OkHttpClient client;
|
private OkHttpClient client;
|
||||||
|
|
||||||
@Before public void setUp() {
|
@Before public void setUp() {
|
||||||
|
platform.assumeNotOpenJSSE();
|
||||||
platform.assumeHttp2Support();
|
platform.assumeHttp2Support();
|
||||||
client = clientTestRule.newClientBuilder()
|
client = clientTestRule.newClientBuilder()
|
||||||
.eventListener(listener)
|
.eventListener(listener)
|
||||||
|
@@ -86,6 +86,8 @@ public final class EventListenerTest {
|
|||||||
private SocksProxy socksProxy;
|
private SocksProxy socksProxy;
|
||||||
|
|
||||||
@Before public void setUp() {
|
@Before public void setUp() {
|
||||||
|
platform.assumeNotOpenJSSE();
|
||||||
|
|
||||||
client = clientTestRule.newClientBuilder()
|
client = clientTestRule.newClientBuilder()
|
||||||
.eventListener(listener)
|
.eventListener(listener)
|
||||||
.build();
|
.build();
|
||||||
|
@@ -15,23 +15,22 @@
|
|||||||
*/
|
*/
|
||||||
package okhttp3
|
package okhttp3
|
||||||
|
|
||||||
import okhttp3.Protocol.HTTP_2
|
import okhttp3.TestUtil.assumeNetwork
|
||||||
|
import okhttp3.internal.platform.OpenJSSEPlatform
|
||||||
import okhttp3.mockwebserver.MockResponse
|
import okhttp3.mockwebserver.MockResponse
|
||||||
import okhttp3.mockwebserver.MockWebServer
|
import okhttp3.mockwebserver.MockWebServer
|
||||||
import okhttp3.testing.PlatformRule
|
import okhttp3.testing.PlatformRule
|
||||||
import okhttp3.tls.HandshakeCertificates
|
import okhttp3.tls.HandshakeCertificates
|
||||||
import okhttp3.tls.HeldCertificate
|
import okhttp3.tls.HeldCertificate
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.After
|
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
|
import org.junit.Ignore
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.openjsse.net.ssl.OpenJSSE
|
|
||||||
import org.openjsse.sun.security.ssl.SSLSocketFactoryImpl
|
import org.openjsse.sun.security.ssl.SSLSocketFactoryImpl
|
||||||
import org.openjsse.sun.security.ssl.SSLSocketImpl
|
import org.openjsse.sun.security.ssl.SSLSocketImpl
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
import java.security.Security
|
|
||||||
|
|
||||||
class OpenJSSETest {
|
class OpenJSSETest {
|
||||||
@JvmField @Rule var platform = PlatformRule()
|
@JvmField @Rule var platform = PlatformRule()
|
||||||
@@ -41,17 +40,11 @@ class OpenJSSETest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
platform.assumeJdk8()
|
platform.assumeOpenJSSE()
|
||||||
|
|
||||||
Security.insertProviderAt(OpenJSSE(), 1)
|
|
||||||
client = clientTestRule.newClient()
|
client = clientTestRule.newClient()
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
|
||||||
fun cleanup() {
|
|
||||||
Security.removeProvider("OpenJSSE")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testTlsv13Works() {
|
fun testTlsv13Works() {
|
||||||
enableTls()
|
enableTls()
|
||||||
@@ -65,7 +58,7 @@ class OpenJSSETest {
|
|||||||
response.use {
|
response.use {
|
||||||
assertEquals(200, response.code)
|
assertEquals(200, response.code)
|
||||||
assertEquals(TlsVersion.TLS_1_3, response.handshake?.tlsVersion)
|
assertEquals(TlsVersion.TLS_1_3, response.handshake?.tlsVersion)
|
||||||
assertEquals(Protocol.HTTP_1_1, response.protocol)
|
assertEquals(Protocol.HTTP_2, response.protocol)
|
||||||
|
|
||||||
assertThat(response.exchange?.connection()?.socket()).isInstanceOf(SSLSocketImpl::class.java)
|
assertThat(response.exchange?.connection()?.socket()).isInstanceOf(SSLSocketImpl::class.java)
|
||||||
}
|
}
|
||||||
@@ -76,14 +69,31 @@ class OpenJSSETest {
|
|||||||
val factory = SSLSocketFactoryImpl()
|
val factory = SSLSocketFactoryImpl()
|
||||||
val s = factory.createSocket() as SSLSocketImpl
|
val s = factory.createSocket() as SSLSocketImpl
|
||||||
|
|
||||||
// A Public API available is available to use in a custom Platform
|
|
||||||
s.setHandshakeApplicationProtocolSelector { _, _ -> HTTP_2.toString() }
|
|
||||||
assertEquals(listOf("TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1"), s.enabledProtocols.toList())
|
assertEquals(listOf("TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1"), s.enabledProtocols.toList())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
fun testMozilla() {
|
||||||
|
assumeNetwork()
|
||||||
|
|
||||||
|
val request = Request.Builder().url("https://mozilla.org/robots.txt").build()
|
||||||
|
|
||||||
|
client.newCall(request).execute().use {
|
||||||
|
assertThat(it.protocol).isEqualTo(Protocol.HTTP_2)
|
||||||
|
assertThat(it.handshake!!.tlsVersion).isEqualTo(TlsVersion.TLS_1_3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBuildIfSupported() {
|
||||||
|
val actual = OpenJSSEPlatform.buildIfSupported()
|
||||||
|
assertThat(actual).isNotNull
|
||||||
|
}
|
||||||
|
|
||||||
private fun enableTls() {
|
private fun enableTls() {
|
||||||
// Generate a self-signed cert for the server to serve and the client to trust.
|
// Generate a self-signed cert for the server to serve and the client to trust.
|
||||||
// can't use localhost with a non OpenJSSE trust manager
|
// can't use TlsUtil.localhost with a non OpenJSSE trust manager
|
||||||
val heldCertificate = HeldCertificate.Builder()
|
val heldCertificate = HeldCertificate.Builder()
|
||||||
.commonName("localhost")
|
.commonName("localhost")
|
||||||
.addSubjectAlternativeName(InetAddress.getByName("localhost").canonicalHostName)
|
.addSubjectAlternativeName(InetAddress.getByName("localhost").canonicalHostName)
|
||||||
|
@@ -129,6 +129,8 @@ public final class HttpOverHttp2Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Before public void setUp() {
|
@Before public void setUp() {
|
||||||
|
platform.assumeNotOpenJSSE();
|
||||||
|
|
||||||
if (protocol == Protocol.HTTP_2) {
|
if (protocol == Protocol.HTTP_2) {
|
||||||
platform.assumeHttp2Support();
|
platform.assumeHttp2Support();
|
||||||
server.useHttps(handshakeCertificates.sslSocketFactory(), false);
|
server.useHttps(handshakeCertificates.sslSocketFactory(), false);
|
||||||
|
@@ -65,6 +65,8 @@ public final class ClientAuthTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
platform.assumeNotOpenJSSE();
|
||||||
|
|
||||||
serverRootCa = new HeldCertificate.Builder()
|
serverRootCa = new HeldCertificate.Builder()
|
||||||
.serialNumber(1L)
|
.serialNumber(1L)
|
||||||
.certificateAuthority(1)
|
.certificateAuthority(1)
|
||||||
|
@@ -42,6 +42,7 @@ import okhttp3.mockwebserver.MockWebServer;
|
|||||||
import okhttp3.mockwebserver.RecordedRequest;
|
import okhttp3.mockwebserver.RecordedRequest;
|
||||||
import okhttp3.mockwebserver.SocketPolicy;
|
import okhttp3.mockwebserver.SocketPolicy;
|
||||||
import okhttp3.testing.Flaky;
|
import okhttp3.testing.Flaky;
|
||||||
|
import okhttp3.testing.PlatformRule;
|
||||||
import okhttp3.tls.HandshakeCertificates;
|
import okhttp3.tls.HandshakeCertificates;
|
||||||
import okio.Buffer;
|
import okio.Buffer;
|
||||||
import okio.ByteString;
|
import okio.ByteString;
|
||||||
@@ -65,6 +66,7 @@ public final class WebSocketHttpTest {
|
|||||||
|
|
||||||
@Rule public final MockWebServer webServer = new MockWebServer();
|
@Rule public final MockWebServer webServer = new MockWebServer();
|
||||||
@Rule public final OkHttpClientTestRule clientTestRule = new OkHttpClientTestRule();
|
@Rule public final OkHttpClientTestRule clientTestRule = new OkHttpClientTestRule();
|
||||||
|
@Rule public final PlatformRule platform = new PlatformRule();
|
||||||
|
|
||||||
private final HandshakeCertificates handshakeCertificates = localhost();
|
private final HandshakeCertificates handshakeCertificates = localhost();
|
||||||
private final WebSocketRecorder clientListener = new WebSocketRecorder("client");
|
private final WebSocketRecorder clientListener = new WebSocketRecorder("client");
|
||||||
@@ -73,6 +75,8 @@ public final class WebSocketHttpTest {
|
|||||||
private OkHttpClient client;
|
private OkHttpClient client;
|
||||||
|
|
||||||
@Before public void setUp() {
|
@Before public void setUp() {
|
||||||
|
platform.assumeNotOpenJSSE();
|
||||||
|
|
||||||
client = clientTestRule.newClientBuilder()
|
client = clientTestRule.newClientBuilder()
|
||||||
.writeTimeout(500, TimeUnit.MILLISECONDS)
|
.writeTimeout(500, TimeUnit.MILLISECONDS)
|
||||||
.readTimeout(500, TimeUnit.MILLISECONDS)
|
.readTimeout(500, TimeUnit.MILLISECONDS)
|
||||||
|
Reference in New Issue
Block a user