diff --git a/benchmarks/src/main/java/okhttp3/benchmarks/ApacheHttpClient.java b/benchmarks/src/main/java/okhttp3/benchmarks/ApacheHttpClient.java index 2f97519a29f7..a5c632fa0fce 100644 --- a/benchmarks/src/main/java/okhttp3/benchmarks/ApacheHttpClient.java +++ b/benchmarks/src/main/java/okhttp3/benchmarks/ApacheHttpClient.java @@ -19,9 +19,8 @@ import java.io.InputStream; import java.util.concurrent.TimeUnit; import java.util.zip.GZIPInputStream; -import javax.net.ssl.SSLContext; import okhttp3.HttpUrl; -import okhttp3.internal.SslContextBuilder; +import okhttp3.internal.tls.SslClient; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; @@ -42,9 +41,9 @@ class ApacheHttpClient extends SynchronousHttpClient { super.prepare(benchmark); ClientConnectionManager connectionManager = new PoolingClientConnectionManager(); if (benchmark.tls) { - SSLContext sslContext = SslContextBuilder.localhost(); + SslClient sslClient = SslClient.localhost(); connectionManager.getSchemeRegistry().register( - new Scheme("https", 443, new SSLSocketFactory(sslContext))); + new Scheme("https", 443, new SSLSocketFactory(sslClient.sslContext))); } client = new DefaultHttpClient(connectionManager); } diff --git a/benchmarks/src/main/java/okhttp3/benchmarks/Benchmark.java b/benchmarks/src/main/java/okhttp3/benchmarks/Benchmark.java index d69530fe0ea3..8d4d04386ae0 100644 --- a/benchmarks/src/main/java/okhttp3/benchmarks/Benchmark.java +++ b/benchmarks/src/main/java/okhttp3/benchmarks/Benchmark.java @@ -26,10 +26,9 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; -import javax.net.ssl.SSLContext; import okhttp3.HttpUrl; import okhttp3.Protocol; -import okhttp3.internal.SslContextBuilder; +import okhttp3.internal.tls.SslClient; import okhttp3.mockwebserver.Dispatcher; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; @@ -161,8 +160,8 @@ private MockWebServer startServer() throws IOException { MockWebServer server = new MockWebServer(); if (tls) { - SSLContext sslContext = SslContextBuilder.localhost(); - server.useHttps(sslContext.getSocketFactory(), false); + SslClient sslClient = SslClient.localhost(); + server.useHttps(sslClient.socketFactory, false); server.setProtocols(protocols); } diff --git a/benchmarks/src/main/java/okhttp3/benchmarks/NettyHttpClient.java b/benchmarks/src/main/java/okhttp3/benchmarks/NettyHttpClient.java index 8caa046c7315..01e6f6e257c4 100644 --- a/benchmarks/src/main/java/okhttp3/benchmarks/NettyHttpClient.java +++ b/benchmarks/src/main/java/okhttp3/benchmarks/NettyHttpClient.java @@ -42,10 +42,9 @@ import java.util.ArrayDeque; import java.util.Deque; import java.util.concurrent.TimeUnit; -import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import okhttp3.HttpUrl; -import okhttp3.internal.SslContextBuilder; +import okhttp3.internal.tls.SslClient; /** Netty isn't an HTTP client, but it's almost one. */ class NettyHttpClient implements HttpClient { @@ -69,8 +68,8 @@ class NettyHttpClient implements HttpClient { ChannelPipeline pipeline = channel.pipeline(); if (benchmark.tls) { - SSLContext sslContext = SslContextBuilder.localhost(); - SSLEngine engine = sslContext.createSSLEngine(); + SslClient sslClient = SslClient.localhost(); + SSLEngine engine = sslClient.sslContext.createSSLEngine(); engine.setUseClientMode(true); pipeline.addLast("ssl", new SslHandler(engine)); } diff --git a/benchmarks/src/main/java/okhttp3/benchmarks/OkHttp.java b/benchmarks/src/main/java/okhttp3/benchmarks/OkHttp.java index 05eb5044d20b..7c90e5e6b5f3 100644 --- a/benchmarks/src/main/java/okhttp3/benchmarks/OkHttp.java +++ b/benchmarks/src/main/java/okhttp3/benchmarks/OkHttp.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.util.concurrent.TimeUnit; import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocketFactory; import okhttp3.Call; @@ -26,7 +25,7 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.ResponseBody; -import okhttp3.internal.SslContextBuilder; +import okhttp3.internal.tls.SslClient; class OkHttp extends SynchronousHttpClient { private static final boolean VERBOSE = false; @@ -40,15 +39,15 @@ class OkHttp extends SynchronousHttpClient { .build(); if (benchmark.tls) { - SSLContext sslContext = SslContextBuilder.localhost(); - SSLSocketFactory socketFactory = sslContext.getSocketFactory(); + SslClient sslClient = SslClient.localhost(); + SSLSocketFactory socketFactory = sslClient.socketFactory; HostnameVerifier hostnameVerifier = new HostnameVerifier() { @Override public boolean verify(String s, SSLSession session) { return true; } }; client = new OkHttpClient.Builder() - .sslSocketFactory(socketFactory) + .sslSocketFactory(socketFactory, sslClient.trustManager) .hostnameVerifier(hostnameVerifier) .build(); } diff --git a/benchmarks/src/main/java/okhttp3/benchmarks/OkHttpAsync.java b/benchmarks/src/main/java/okhttp3/benchmarks/OkHttpAsync.java index 09bd3a73e352..57cb75cacc02 100644 --- a/benchmarks/src/main/java/okhttp3/benchmarks/OkHttpAsync.java +++ b/benchmarks/src/main/java/okhttp3/benchmarks/OkHttpAsync.java @@ -21,7 +21,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocketFactory; import okhttp3.Call; @@ -32,7 +31,7 @@ import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; -import okhttp3.internal.SslContextBuilder; +import okhttp3.internal.tls.SslClient; class OkHttpAsync implements HttpClient { private static final boolean VERBOSE = false; @@ -55,15 +54,15 @@ class OkHttpAsync implements HttpClient { .build(); if (benchmark.tls) { - SSLContext sslContext = SslContextBuilder.localhost(); - SSLSocketFactory socketFactory = sslContext.getSocketFactory(); + SslClient sslClient = SslClient.localhost(); + SSLSocketFactory socketFactory = sslClient.socketFactory; HostnameVerifier hostnameVerifier = new HostnameVerifier() { @Override public boolean verify(String s, SSLSession session) { return true; } }; client = client.newBuilder() - .sslSocketFactory(socketFactory) + .sslSocketFactory(socketFactory, sslClient.trustManager) .hostnameVerifier(hostnameVerifier) .build(); } diff --git a/benchmarks/src/main/java/okhttp3/benchmarks/UrlConnection.java b/benchmarks/src/main/java/okhttp3/benchmarks/UrlConnection.java index f5c02ce0b6db..f75d16083550 100644 --- a/benchmarks/src/main/java/okhttp3/benchmarks/UrlConnection.java +++ b/benchmarks/src/main/java/okhttp3/benchmarks/UrlConnection.java @@ -22,11 +22,10 @@ import java.util.zip.GZIPInputStream; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocketFactory; import okhttp3.HttpUrl; -import okhttp3.internal.SslContextBuilder; +import okhttp3.internal.tls.SslClient; class UrlConnection extends SynchronousHttpClient { private static final boolean VERBOSE = false; @@ -34,8 +33,8 @@ class UrlConnection extends SynchronousHttpClient { @Override public void prepare(Benchmark benchmark) { super.prepare(benchmark); if (benchmark.tls) { - SSLContext sslContext = SslContextBuilder.localhost(); - SSLSocketFactory socketFactory = sslContext.getSocketFactory(); + SslClient sslClient = SslClient.localhost(); + SSLSocketFactory socketFactory = sslClient.socketFactory; HostnameVerifier hostnameVerifier = new HostnameVerifier() { @Override public boolean verify(String s, SSLSession session) { return true; diff --git a/mockwebserver/src/main/java/okhttp3/internal/SslContextBuilder.java b/mockwebserver/src/main/java/okhttp3/internal/SslContextBuilder.java deleted file mode 100644 index b161e106e2aa..000000000000 --- a/mockwebserver/src/main/java/okhttp3/internal/SslContextBuilder.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2012 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; - -import java.io.IOException; -import java.io.InputStream; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.security.GeneralSecurityException; -import java.security.KeyStore; -import java.security.SecureRandom; -import java.security.cert.Certificate; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.List; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManagerFactory; - -/** - * Constructs an SSL context for testing. This uses Bouncy Castle to generate a self-signed - * certificate for a single hostname such as "localhost". - * - *

The crypto performed by this class is relatively slow. Clients should reuse SSL context - * instances where possible. - */ -public final class SslContextBuilder { - private static SSLContext localhost; // Lazily initialized. - - /** Returns a new SSL context for this host's current localhost address. */ - public static synchronized SSLContext localhost() { - if (localhost != null) return localhost; - - try { - // Generate a self-signed cert for the server to serve and the client to trust. - HeldCertificate heldCertificate = new HeldCertificate.Builder() - .serialNumber("1") - .commonName(InetAddress.getByName("localhost").getHostName()) - .build(); - - localhost = new SslContextBuilder() - .certificateChain(heldCertificate) - .addTrustedCertificate(heldCertificate.certificate) - .build(); - - return localhost; - } catch (GeneralSecurityException e) { - throw new RuntimeException(e); - } catch (UnknownHostException e) { - throw new RuntimeException(e); - } - } - - private HeldCertificate[] chain; - private List trustedCertificates = new ArrayList<>(); - - /** - * Configure the certificate chain to use when serving HTTPS responses. The first certificate - * in this chain is the server's certificate, further certificates are included in the handshake - * so the client can build a trusted path to a CA certificate. - */ - public SslContextBuilder certificateChain(HeldCertificate... chain) { - this.chain = chain; - return this; - } - - /** - * Add a certificate authority that this client trusts. Servers that provide certificate chains - * signed by these roots (or their intermediates) will be accepted. - */ - public SslContextBuilder addTrustedCertificate(X509Certificate certificate) { - trustedCertificates.add(certificate); - return this; - } - - public SSLContext build() throws GeneralSecurityException { - // Put the certificate in a key store. - char[] password = "password".toCharArray(); - KeyStore keyStore = newEmptyKeyStore(password); - - if (chain != null) { - Certificate[] certificates = new Certificate[chain.length]; - for (int i = 0; i < chain.length; i++) { - certificates[i] = chain[i].certificate; - } - keyStore.setKeyEntry("private", chain[0].keyPair.getPrivate(), password, certificates); - } - - for (int i = 0; i < trustedCertificates.size(); i++) { - keyStore.setCertificateEntry("cert_" + i, trustedCertificates.get(i)); - } - - // Wrap it up in an SSL context. - KeyManagerFactory keyManagerFactory = - KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - keyManagerFactory.init(keyStore, password); - TrustManagerFactory trustManagerFactory = - TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - trustManagerFactory.init(keyStore); - SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), - new SecureRandom()); - return sslContext; - } - - private KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException { - try { - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - InputStream in = null; // By convention, 'null' creates an empty key store. - keyStore.load(in, password); - return keyStore; - } catch (IOException e) { - throw new AssertionError(e); - } - } -} diff --git a/mockwebserver/src/main/java/okhttp3/internal/framed/FramedServer.java b/mockwebserver/src/main/java/okhttp3/internal/framed/FramedServer.java index 4ac8159d6c3b..2a555be68e35 100644 --- a/mockwebserver/src/main/java/okhttp3/internal/framed/FramedServer.java +++ b/mockwebserver/src/main/java/okhttp3/internal/framed/FramedServer.java @@ -29,8 +29,8 @@ import javax.net.ssl.SSLSocketFactory; import okhttp3.Protocol; import okhttp3.internal.Platform; -import okhttp3.internal.SslContextBuilder; import okhttp3.internal.Util; +import okhttp3.internal.tls.SslClient; import okio.BufferedSink; import okio.Okio; import okio.Source; @@ -184,7 +184,7 @@ public static void main(String... args) throws Exception { } FramedServer server = new FramedServer(new File(args[0]), - SslContextBuilder.localhost().getSocketFactory()); + SslClient.localhost().sslContext.getSocketFactory()); server.run(); } } diff --git a/mockwebserver/src/main/java/okhttp3/internal/HeldCertificate.java b/mockwebserver/src/main/java/okhttp3/internal/tls/HeldCertificate.java similarity index 99% rename from mockwebserver/src/main/java/okhttp3/internal/HeldCertificate.java rename to mockwebserver/src/main/java/okhttp3/internal/tls/HeldCertificate.java index d6c45bd30be2..a7fe81f0ef64 100644 --- a/mockwebserver/src/main/java/okhttp3/internal/HeldCertificate.java +++ b/mockwebserver/src/main/java/okhttp3/internal/tls/HeldCertificate.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package okhttp3.internal; +package okhttp3.internal.tls; import java.math.BigInteger; import java.security.GeneralSecurityException; diff --git a/mockwebserver/src/main/java/okhttp3/internal/tls/SslClient.java b/mockwebserver/src/main/java/okhttp3/internal/tls/SslClient.java new file mode 100644 index 000000000000..7cc061b66881 --- /dev/null +++ b/mockwebserver/src/main/java/okhttp3/internal/tls/SslClient.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2012 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.tls; + +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +/** + * Combines an SSL socket factory and trust manager, a pairing enough for OkHttp or MockWebServer to + * create a secure connection. + */ +public final class SslClient { + private static SslClient localhost; // Lazily initialized. + + public final SSLContext sslContext; + public final SSLSocketFactory socketFactory; + public final X509TrustManager trustManager; + + private SslClient(SSLContext sslContext, X509TrustManager trustManager) { + this.sslContext = sslContext; + this.socketFactory = sslContext.getSocketFactory(); + this.trustManager = trustManager; + } + + /** Returns an SSL client for this host's localhost address. */ + public static synchronized SslClient localhost() { + if (localhost != null) return localhost; + + try { + // Generate a self-signed cert for the server to serve and the client to trust. + HeldCertificate heldCertificate = new HeldCertificate.Builder() + .serialNumber("1") + .commonName(InetAddress.getByName("localhost").getHostName()) + .build(); + + localhost = new Builder() + .certificateChain(heldCertificate.keyPair, heldCertificate.certificate) + .addTrustedCertificate(heldCertificate.certificate) + .build(); + + return localhost; + } catch (GeneralSecurityException | UnknownHostException e) { + throw new RuntimeException(e); + } + } + + public static class Builder { + private final List chainCertificates = new ArrayList<>(); + private final List certificates = new ArrayList<>(); + private KeyPair keyPair; + + /** + * Configure the certificate chain to use when serving HTTPS responses. The first certificate is + * the server's certificate, further certificates are included in the handshake so the client + * can build a trusted path to a CA certificate. + */ + public Builder certificateChain(HeldCertificate serverCert, HeldCertificate... chain) { + X509Certificate[] certificates = new X509Certificate[chain.length]; + for (int i = 0; i < chain.length; i++) { + certificates[i] = chain[i].certificate; + } + return certificateChain(serverCert.keyPair, serverCert.certificate, certificates); + } + + public SslClient.Builder certificateChain(KeyPair keyPair, X509Certificate keyCert, + X509Certificate... certificates) { + this.keyPair = keyPair; + this.chainCertificates.add(keyCert); + this.chainCertificates.addAll(Arrays.asList(certificates)); + this.certificates.addAll(Arrays.asList(certificates)); + return this; + } + + /** + * Add a certificate authority that this client trusts. Servers that provide certificate chains + * signed by these roots (or their intermediates) will be accepted. + */ + public Builder addTrustedCertificate(X509Certificate certificate) { + this.certificates.add(certificate); + return this; + } + + public SslClient build() { + try { + // Put the certificate in a key store. + char[] password = "password".toCharArray(); + KeyStore keyStore = newEmptyKeyStore(password); + + if (keyPair != null) { + Certificate[] certificates = chainCertificates.toArray( + new Certificate[chainCertificates.size()]); + keyStore.setKeyEntry("private", keyPair.getPrivate(), password, certificates); + } + + for (int i = 0; i < certificates.size(); i++) { + keyStore.setCertificateEntry("cert_" + i, certificates.get(i)); + } + + // Wrap it up in an SSL context. + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance( + KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, password); + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(keyStore); + TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); + + if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) { + throw new IllegalStateException("Unexpected default trust managers:" + + Arrays.toString(trustManagers)); + } + + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(keyManagerFactory.getKeyManagers(), trustManagers, new SecureRandom()); + + return new SslClient(sslContext, (X509TrustManager) trustManagers[0]); + } catch (GeneralSecurityException gse) { + throw new AssertionError(gse); + } + } + + private KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException { + try { + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + InputStream in = null; // By convention, 'null' creates an empty key store. + keyStore.load(in, password); + return keyStore; + } catch (IOException e) { + throw new AssertionError(e); + } + } + } +} diff --git a/okcurl/src/main/java/okhttp3/curl/Main.java b/okcurl/src/main/java/okhttp3/curl/Main.java index 15e4f030d198..aa8f4872c199 100644 --- a/okcurl/src/main/java/okhttp3/curl/Main.java +++ b/okcurl/src/main/java/okhttp3/curl/Main.java @@ -23,7 +23,6 @@ import io.airlift.airline.SingleCommand; import java.io.IOException; import java.io.InputStream; -import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.List; import java.util.Properties; @@ -179,7 +178,9 @@ private OkHttpClient createClient() { builder.readTimeout(readTimeout, SECONDS); } if (allowInsecure) { - builder.sslSocketFactory(createInsecureSslSocketFactory()); + X509TrustManager trustManager = createInsecureTrustManager(); + SSLSocketFactory sslSocketFactory = createInsecureSslSocketFactory(trustManager); + builder.sslSocketFactory(sslSocketFactory, trustManager); builder.hostnameVerifier(createInsecureHostnameVerifier()); } return builder.build(); @@ -240,23 +241,24 @@ private void close() { client.connectionPool().evictAll(); // Close any persistent connections. } - private static SSLSocketFactory createInsecureSslSocketFactory() { - try { - SSLContext context = SSLContext.getInstance("TLS"); - TrustManager permissive = new X509TrustManager() { - @Override public void checkClientTrusted(X509Certificate[] chain, String authType) - throws CertificateException { - } + private static X509TrustManager createInsecureTrustManager() { + return new X509TrustManager() { + @Override public void checkClientTrusted(X509Certificate[] chain, String authType) { + } - @Override public void checkServerTrusted(X509Certificate[] chain, String authType) - throws CertificateException { - } + @Override public void checkServerTrusted(X509Certificate[] chain, String authType) { + } - @Override public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } - }; - context.init(null, new TrustManager[] {permissive}, null); + @Override public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + }; + } + + private static SSLSocketFactory createInsecureSslSocketFactory(TrustManager trustManager) { + try { + SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, new TrustManager[] {trustManager}, null); return context.getSocketFactory(); } catch (Exception e) { throw new AssertionError(e); diff --git a/okhttp-android-support/src/test/java/okhttp3/internal/huc/CacheAdapterTest.java b/okhttp-android-support/src/test/java/okhttp3/internal/huc/CacheAdapterTest.java index 81aeaf2b9a2b..e24c7264ad60 100644 --- a/okhttp-android-support/src/test/java/okhttp3/internal/huc/CacheAdapterTest.java +++ b/okhttp-android-support/src/test/java/okhttp3/internal/huc/CacheAdapterTest.java @@ -29,16 +29,15 @@ import java.util.Map; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; import okhttp3.AbstractResponseCache; import okhttp3.OkHttpClient; import okhttp3.OkUrlFactory; +import okhttp3.RecordingHostnameVerifier; import okhttp3.internal.Internal; import okhttp3.internal.InternalCache; -import okhttp3.internal.SslContextBuilder; +import okhttp3.internal.tls.SslClient; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; -import okhttp3.RecordingHostnameVerifier; import okio.Buffer; import org.junit.After; import org.junit.Before; @@ -59,7 +58,7 @@ * */ public class CacheAdapterTest { - private SSLContext sslContext = SslContextBuilder.localhost(); + private SslClient sslClient = SslClient.localhost(); private HostnameVerifier hostnameVerifier = new RecordingHostnameVerifier(); private MockWebServer server; private OkHttpClient client; @@ -116,7 +115,7 @@ public class CacheAdapterTest { }; setInternalCache(new CacheAdapter(responseCache)); client = client.newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(hostnameVerifier) .build(); @@ -234,7 +233,7 @@ public class CacheAdapterTest { }; setInternalCache(new CacheAdapter(responseCache)); client = client.newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(hostnameVerifier) .build(); @@ -262,7 +261,7 @@ private URL configureServer(MockResponse mockResponse) throws Exception { } private URL configureHttpsServer(MockResponse mockResponse) throws Exception { - server.useHttps(sslContext.getSocketFactory(), false /* tunnelProxy */); + server.useHttps(sslClient.socketFactory, false /* tunnelProxy */); server.enqueue(mockResponse); server.start(); return server.url("/").url(); diff --git a/okhttp-android-support/src/test/java/okhttp3/internal/huc/ResponseCacheTest.java b/okhttp-android-support/src/test/java/okhttp3/internal/huc/ResponseCacheTest.java index a73ca5485457..a533b919b768 100644 --- a/okhttp-android-support/src/test/java/okhttp3/internal/huc/ResponseCacheTest.java +++ b/okhttp-android-support/src/test/java/okhttp3/internal/huc/ResponseCacheTest.java @@ -54,21 +54,20 @@ import java.util.concurrent.atomic.AtomicReference; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; import okhttp3.AbstractResponseCache; import okhttp3.AndroidInternal; import okhttp3.AndroidShimResponseCache; import okhttp3.Headers; import okhttp3.OkHttpClient; import okhttp3.OkUrlFactory; +import okhttp3.RecordingHostnameVerifier; import okhttp3.internal.Internal; import okhttp3.internal.InternalCache; -import okhttp3.internal.SslContextBuilder; +import okhttp3.internal.tls.SslClient; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.RecordedRequest; import okhttp3.mockwebserver.SocketPolicy; -import okhttp3.RecordingHostnameVerifier; import okio.Buffer; import okio.BufferedSink; import okio.GzipSink; @@ -96,7 +95,7 @@ public final class ResponseCacheTest { @Rule public MockWebServer server2 = new MockWebServer(); private HostnameVerifier hostnameVerifier = new RecordingHostnameVerifier(); - private SSLContext sslContext = SslContextBuilder.localhost(); + private SslClient sslClient = SslClient.localhost(); private ResponseCache cache; private CookieManager cookieManager; private OkUrlFactory urlFactory; @@ -267,14 +266,14 @@ private void testResponseCaching(TransferKind transferKind) throws IOException { } @Test public void secureResponseCaching() throws IOException { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse() .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) .setBody("ABC")); HttpsURLConnection c1 = (HttpsURLConnection) openConnection(server.url("/").url()); - c1.setSSLSocketFactory(sslContext.getSocketFactory()); + c1.setSSLSocketFactory(sslClient.socketFactory); c1.setHostnameVerifier(hostnameVerifier); assertEquals("ABC", readAscii(c1)); @@ -286,7 +285,7 @@ private void testResponseCaching(TransferKind transferKind) throws IOException { Principal localPrincipal = c1.getLocalPrincipal(); HttpsURLConnection c2 = (HttpsURLConnection) openConnection(server.url("/").url()); // cached! - c2.setSSLSocketFactory(sslContext.getSocketFactory()); + c2.setSSLSocketFactory(sslClient.socketFactory); c2.setHostnameVerifier(hostnameVerifier); assertEquals("ABC", readAscii(c2)); @@ -345,7 +344,7 @@ private void testResponseCaching(TransferKind transferKind) throws IOException { } @Test public void secureResponseCachingAndRedirects() throws IOException { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse() .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) @@ -359,7 +358,7 @@ private void testResponseCaching(TransferKind transferKind) throws IOException { .setBody("DEF")); urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(hostnameVerifier) .build()); @@ -383,7 +382,7 @@ private void testResponseCaching(TransferKind transferKind) throws IOException { * https://github.com/square/okhttp/issues/214 */ @Test public void secureResponseCachingAndProtocolRedirects() throws IOException { - server2.useHttps(sslContext.getSocketFactory(), false); + server2.useHttps(sslClient.socketFactory, false); server2.enqueue(new MockResponse() .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) @@ -398,7 +397,7 @@ private void testResponseCaching(TransferKind transferKind) throws IOException { .addHeader("Location: " + server2.url("/").url())); urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(hostnameVerifier) .build()); @@ -1461,7 +1460,7 @@ private RecordedRequest assertClientSuppliedCondition(MockResponse seed, String } @Test public void varyAndHttps() throws Exception { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse() .addHeader("Cache-Control: max-age=60") .addHeader("Vary: Accept-Language") @@ -1470,7 +1469,7 @@ private RecordedRequest assertClientSuppliedCondition(MockResponse seed, String .setBody("B")); urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(hostnameVerifier) .build()); @@ -1981,20 +1980,20 @@ private InsecureResponseCache(ResponseCache delegate) { } @Test public void cacheReturnsInsecureResponseForSecureRequest() throws IOException { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().setBody("ABC")); server.enqueue(new MockResponse().setBody("DEF")); AndroidInternal.setResponseCache(urlFactory, new InsecureResponseCache(cache)); HttpsURLConnection connection1 = (HttpsURLConnection) openConnection(server.url("/").url()); - connection1.setSSLSocketFactory(sslContext.getSocketFactory()); + connection1.setSSLSocketFactory(sslClient.socketFactory); connection1.setHostnameVerifier(hostnameVerifier); assertEquals("ABC", readAscii(connection1)); // Not cached! HttpsURLConnection connection2 = (HttpsURLConnection) openConnection(server.url("/").url()); - connection2.setSSLSocketFactory(sslContext.getSocketFactory()); + connection2.setSSLSocketFactory(sslClient.socketFactory); connection2.setHostnameVerifier(hostnameVerifier); assertEquals("DEF", readAscii(connection2)); } diff --git a/okhttp-tests/pom.xml b/okhttp-tests/pom.xml index 5585632fc252..fd07ff95086e 100644 --- a/okhttp-tests/pom.xml +++ b/okhttp-tests/pom.xml @@ -1,6 +1,8 @@ - + 4.0.0 diff --git a/okhttp-tests/src/test/java/okhttp3/CacheTest.java b/okhttp-tests/src/test/java/okhttp3/CacheTest.java index 418f7bd293af..33565e31e9f9 100644 --- a/okhttp-tests/src/test/java/okhttp3/CacheTest.java +++ b/okhttp-tests/src/test/java/okhttp3/CacheTest.java @@ -37,12 +37,11 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import okhttp3.internal.Internal; -import okhttp3.internal.SslContextBuilder; import okhttp3.internal.Util; import okhttp3.internal.io.InMemoryFileSystem; +import okhttp3.internal.tls.SslClient; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.RecordedRequest; @@ -75,7 +74,7 @@ public final class CacheTest { @Rule public MockWebServer server2 = new MockWebServer(); @Rule public InMemoryFileSystem fileSystem = new InMemoryFileSystem(); - private final SSLContext sslContext = SslContextBuilder.localhost(); + private final SslClient sslClient = SslClient.localhost(); private OkHttpClient client; private Cache cache; private final CookieManager cookieManager = new CookieManager(); @@ -256,14 +255,14 @@ private void testResponseCaching(TransferKind transferKind) throws IOException { } @Test public void secureResponseCaching() throws IOException { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse() .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) .setBody("ABC")); client = client.newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(NULL_HOSTNAME_VERIFIER) .build(); @@ -352,7 +351,7 @@ private void testResponseCaching(TransferKind transferKind) throws IOException { } @Test public void secureResponseCachingAndRedirects() throws IOException { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse() .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) @@ -366,7 +365,7 @@ private void testResponseCaching(TransferKind transferKind) throws IOException { .setBody("DEF")); client = client.newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(NULL_HOSTNAME_VERIFIER) .build(); @@ -392,7 +391,7 @@ private void testResponseCaching(TransferKind transferKind) throws IOException { * https://github.com/square/okhttp/issues/214 */ @Test public void secureResponseCachingAndProtocolRedirects() throws IOException { - server2.useHttps(sslContext.getSocketFactory(), false); + server2.useHttps(sslClient.socketFactory, false); server2.enqueue(new MockResponse() .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) @@ -407,7 +406,7 @@ private void testResponseCaching(TransferKind transferKind) throws IOException { .addHeader("Location: " + server2.url("/"))); client = client.newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(NULL_HOSTNAME_VERIFIER) .build(); @@ -1681,7 +1680,7 @@ private RecordedRequest assertClientSuppliedCondition(MockResponse seed, String } @Test public void varyAndHttps() throws Exception { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse() .addHeader("Cache-Control: max-age=60") .addHeader("Vary: Accept-Language") @@ -1690,7 +1689,7 @@ private RecordedRequest assertClientSuppliedCondition(MockResponse seed, String .setBody("B")); client = client.newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(NULL_HOSTNAME_VERIFIER) .build(); diff --git a/okhttp-tests/src/test/java/okhttp3/CallTest.java b/okhttp-tests/src/test/java/okhttp3/CallTest.java index 18ede8338d0f..c2470c920bd4 100644 --- a/okhttp-tests/src/test/java/okhttp3/CallTest.java +++ b/okhttp-tests/src/test/java/okhttp3/CallTest.java @@ -47,7 +47,6 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Logger; import javax.net.ServerSocketFactory; -import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLProtocolException; @@ -56,11 +55,11 @@ import okhttp3.internal.DoubleInetAddressDns; import okhttp3.internal.RecordingOkAuthenticator; import okhttp3.internal.SingleInetAddressDns; -import okhttp3.internal.SslContextBuilder; import okhttp3.internal.Util; import okhttp3.internal.Version; import okhttp3.internal.http.RecordingProxySelector; import okhttp3.internal.io.InMemoryFileSystem; +import okhttp3.internal.tls.SslClient; import okhttp3.mockwebserver.Dispatcher; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; @@ -94,7 +93,7 @@ public final class CallTest { @Rule public final MockWebServer server2 = new MockWebServer(); @Rule public final InMemoryFileSystem fileSystem = new InMemoryFileSystem(); - private SSLContext sslContext = SslContextBuilder.localhost(); + private SslClient sslClient = SslClient.localhost(); private OkHttpClient client = defaultClient(); private RecordingCallback callback = new RecordingCallback(); private TestLogHandler logHandler = new TestLogHandler(); @@ -964,14 +963,14 @@ private void postBodyRetransmittedAfterAuthorizationFail(String body) throws Exc } @Test public void recoverFromTlsHandshakeFailure() throws Exception { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE)); server.enqueue(new MockResponse().setBody("abc")); client = client.newBuilder() .hostnameVerifier(new RecordingHostnameVerifier()) .dns(new SingleInetAddressDns()) - .sslSocketFactory(suppressTlsFallbackClientSocketFactory()) + .sslSocketFactory(suppressTlsFallbackClientSocketFactory(), sslClient.trustManager) .build(); executeSynchronously("/").assertBody("abc"); @@ -980,19 +979,19 @@ private void postBodyRetransmittedAfterAuthorizationFail(String body) throws Exc @Test public void recoverFromTlsHandshakeFailure_tlsFallbackScsvEnabled() throws Exception { final String tlsFallbackScsv = "TLS_FALLBACK_SCSV"; List supportedCiphers = - Arrays.asList(sslContext.getSocketFactory().getSupportedCipherSuites()); + Arrays.asList(sslClient.socketFactory.getSupportedCipherSuites()); if (!supportedCiphers.contains(tlsFallbackScsv)) { // This only works if the client socket supports TLS_FALLBACK_SCSV. return; } - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE)); RecordingSSLSocketFactory clientSocketFactory = - new RecordingSSLSocketFactory(sslContext.getSocketFactory()); + new RecordingSSLSocketFactory(sslClient.socketFactory); client = client.newBuilder() - .sslSocketFactory(clientSocketFactory) + .sslSocketFactory(clientSocketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .dns(new SingleInetAddressDns()) .build(); @@ -1012,13 +1011,13 @@ private void postBodyRetransmittedAfterAuthorizationFail(String body) throws Exc } @Test public void recoverFromTlsHandshakeFailure_Async() throws Exception { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE)); server.enqueue(new MockResponse().setBody("abc")); client = client.newBuilder() .hostnameVerifier(new RecordingHostnameVerifier()) - .sslSocketFactory(suppressTlsFallbackClientSocketFactory()) + .sslSocketFactory(suppressTlsFallbackClientSocketFactory(), sslClient.trustManager) .build(); Request request = new Request.Builder() @@ -1034,10 +1033,10 @@ private void postBodyRetransmittedAfterAuthorizationFail(String body) throws Exc .connectionSpecs(Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT)) .hostnameVerifier(new RecordingHostnameVerifier()) .dns(new SingleInetAddressDns()) - .sslSocketFactory(suppressTlsFallbackClientSocketFactory()) + .sslSocketFactory(suppressTlsFallbackClientSocketFactory(), sslClient.trustManager) .build(); - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE)); Request request = new Request.Builder().url(server.url("/")).build(); @@ -2206,7 +2205,7 @@ private InetSocketAddress startNullServer() throws IOException { /** Test which headers are sent unencrypted to the HTTP proxy. */ @Test public void proxyConnectOmitsApplicationHeaders() throws Exception { - server.useHttps(sslContext.getSocketFactory(), true); + server.useHttps(sslClient.socketFactory, true); server.enqueue(new MockResponse() .setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END) .clearHeaders()); @@ -2215,7 +2214,7 @@ private InetSocketAddress startNullServer() throws IOException { RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier(); client = client.newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .proxy(server.toProxyAddress()) .hostnameVerifier(hostnameVerifier) .build(); @@ -2243,7 +2242,7 @@ private InetSocketAddress startNullServer() throws IOException { /** Respond to a proxy authorization challenge. */ @Test public void proxyAuthenticateOnConnect() throws Exception { - server.useHttps(sslContext.getSocketFactory(), true); + server.useHttps(sslClient.socketFactory, true); server.enqueue(new MockResponse() .setResponseCode(407) .addHeader("Proxy-Authenticate: Basic realm=\"localhost\"")); @@ -2254,7 +2253,7 @@ private InetSocketAddress startNullServer() throws IOException { .setBody("response body")); client = client.newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .proxy(server.toProxyAddress()) .proxyAuthenticator(new RecordingOkAuthenticator("password")) .hostnameVerifier(new RecordingHostnameVerifier()) @@ -2312,7 +2311,7 @@ private InetSocketAddress startNullServer() throws IOException { * a TLS tunnel. https://github.com/square/okhttp/issues/2426 */ @Test public void proxyAuthenticateOnConnectWithConnectionClose() throws Exception { - server.useHttps(sslContext.getSocketFactory(), true); + server.useHttps(sslClient.socketFactory, true); server.setProtocols(Collections.singletonList(Protocol.HTTP_1_1)); server.enqueue(new MockResponse() .setResponseCode(407) @@ -2325,7 +2324,7 @@ private InetSocketAddress startNullServer() throws IOException { .setBody("response body")); client = client.newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .proxy(server.toProxyAddress()) .proxyAuthenticator(new RecordingOkAuthenticator("password")) .hostnameVerifier(new RecordingHostnameVerifier()) @@ -2348,7 +2347,7 @@ private InetSocketAddress startNullServer() throws IOException { } @Test public void tooManyProxyAuthFailuresWithConnectionClose() throws IOException { - server.useHttps(sslContext.getSocketFactory(), true); + server.useHttps(sslClient.socketFactory, true); server.setProtocols(Collections.singletonList(Protocol.HTTP_1_1)); for (int i = 0; i < 21; i++) { server.enqueue(new MockResponse() @@ -2358,7 +2357,7 @@ private InetSocketAddress startNullServer() throws IOException { } client = client.newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .proxy(server.toProxyAddress()) .proxyAuthenticator(new RecordingOkAuthenticator("password")) .hostnameVerifier(new RecordingHostnameVerifier()) @@ -2380,7 +2379,7 @@ private InetSocketAddress startNullServer() throws IOException { * credentials. Worse, that approach leaks proxy credentials to the origin server. */ @Test public void noProactiveProxyAuthorization() throws Exception { - server.useHttps(sslContext.getSocketFactory(), true); + server.useHttps(sslClient.socketFactory, true); server.enqueue(new MockResponse() .setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END) .clearHeaders()); @@ -2388,7 +2387,7 @@ private InetSocketAddress startNullServer() throws IOException { .setBody("response body")); client = client.newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .proxy(server.toProxyAddress()) .hostnameVerifier(new RecordingHostnameVerifier()) .build(); @@ -2536,7 +2535,7 @@ private void upload( /** https://github.com/square/okhttp/issues/2344 */ @Test public void ipv6HostHasSquareBraces() throws Exception { // Use a proxy to fake IPv6 connectivity, even if localhost doesn't have IPv6. - server.useHttps(sslContext.getSocketFactory(), true); + server.useHttps(sslClient.socketFactory, true); server.setProtocols(Collections.singletonList(Protocol.HTTP_1_1)); server.enqueue(new MockResponse() .setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END) @@ -2545,7 +2544,7 @@ private void upload( .setBody("response body")); client = client.newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .proxy(server.toProxyAddress()) .build(); @@ -2658,10 +2657,10 @@ private void enableProtocol(Protocol protocol) { private void enableTls() { client = client.newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .build(); - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); } private Buffer gzip(String data) throws IOException { @@ -2710,6 +2709,6 @@ public List getSocketsCreated() { * for details. */ private FallbackTestClientSocketFactory suppressTlsFallbackClientSocketFactory() { - return new FallbackTestClientSocketFactory(sslContext.getSocketFactory()); + return new FallbackTestClientSocketFactory(sslClient.socketFactory); } } diff --git a/okhttp-tests/src/test/java/okhttp3/CertificateChainCleanerTest.java b/okhttp-tests/src/test/java/okhttp3/CertificateChainCleanerTest.java index 8bfcb8c2aed2..261c99f8b65b 100644 --- a/okhttp-tests/src/test/java/okhttp3/CertificateChainCleanerTest.java +++ b/okhttp-tests/src/test/java/okhttp3/CertificateChainCleanerTest.java @@ -21,7 +21,7 @@ import java.util.ArrayList; import java.util.List; import javax.net.ssl.SSLPeerUnverifiedException; -import okhttp3.internal.HeldCertificate; +import okhttp3.internal.tls.HeldCertificate; import okhttp3.internal.tls.CertificateChainCleaner; import org.junit.Test; diff --git a/okhttp-tests/src/test/java/okhttp3/CertificatePinnerTest.java b/okhttp-tests/src/test/java/okhttp3/CertificatePinnerTest.java index 9442ddaf713f..54a51b5d7dd6 100644 --- a/okhttp-tests/src/test/java/okhttp3/CertificatePinnerTest.java +++ b/okhttp-tests/src/test/java/okhttp3/CertificatePinnerTest.java @@ -21,7 +21,7 @@ import java.util.List; import javax.net.ssl.SSLPeerUnverifiedException; import okhttp3.CertificatePinner.Pin; -import okhttp3.internal.HeldCertificate; +import okhttp3.internal.tls.HeldCertificate; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/okhttp-tests/src/test/java/okhttp3/ConnectionReuseTest.java b/okhttp-tests/src/test/java/okhttp3/ConnectionReuseTest.java index 2dc6bd9fd6ed..5d45f0b7217b 100644 --- a/okhttp-tests/src/test/java/okhttp3/ConnectionReuseTest.java +++ b/okhttp-tests/src/test/java/okhttp3/ConnectionReuseTest.java @@ -21,7 +21,7 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; import javax.net.ssl.SSLSocketFactory; -import okhttp3.internal.SslContextBuilder; +import okhttp3.internal.tls.SslClient; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.SocketPolicy; @@ -39,7 +39,7 @@ public final class ConnectionReuseTest { @Rule public final TestRule timeout = new Timeout(30_000); @Rule public final MockWebServer server = new MockWebServer(); - private SSLContext sslContext = SslContextBuilder.localhost(); + private SslClient sslClient = SslClient.localhost(); private OkHttpClient client = defaultClient(); @Test public void connectionsAreReused() throws Exception { @@ -335,11 +335,11 @@ private void enableHttp2() { private void enableHttpsAndAlpn(Protocol... protocols) { client = client.newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .protocols(Arrays.asList(protocols)) .build(); - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.setProtocols(client.protocols()); } diff --git a/okhttp-tests/src/test/java/okhttp3/DelegatingSSLSocket.java b/okhttp-tests/src/test/java/okhttp3/DelegatingSSLSocket.java index f07559387b6a..fc863c202205 100644 --- a/okhttp-tests/src/test/java/okhttp3/DelegatingSSLSocket.java +++ b/okhttp-tests/src/test/java/okhttp3/DelegatingSSLSocket.java @@ -18,10 +18,14 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.InvocationTargetException; import java.net.InetAddress; +import java.net.Socket; import java.net.SocketAddress; import java.net.SocketException; +import java.net.SocketOption; import java.nio.channels.SocketChannel; +import java.util.Set; import javax.net.ssl.HandshakeCompletedListener; import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSession; @@ -280,4 +284,55 @@ public DelegatingSSLSocket(SSLSocket delegate) { @Override public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { delegate.setPerformancePreferences(connectionTime, latency, bandwidth); } + + // Java 9 methods. + + public SSLSession getHandshakeSession() { + try { + return (SSLSession) SSLSocket.class.getMethod("getHandshakeSession").invoke(delegate); + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + throw new AssertionError(); + } + } + + public String getApplicationProtocol() { + try { + return (String) SSLSocket.class.getMethod("getApplicationProtocol").invoke(delegate); + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + throw new AssertionError(); + } + } + + public String getHandshakeApplicationProtocol() { + try { + return (String) SSLSocket.class.getMethod("getHandshakeApplicationProtocol").invoke(delegate); + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + throw new AssertionError(); + } + } + + public Socket setOption(SocketOption name, T value) throws IOException { + try { + SSLSocket.class.getMethod("setOption", SocketOption.class, Object.class).invoke(delegate, name, value); + return this; + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + throw new AssertionError(); + } + } + + public T getOption(SocketOption name) throws IOException { + try { + return (T) SSLSocket.class.getMethod("getOption", SocketOption.class).invoke(delegate, name); + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + throw new AssertionError(); + } + } + + public Set> supportedOptions() { + try { + return (Set>) SSLSocket.class.getMethod("supportedOptions").invoke(delegate); + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + throw new AssertionError(); + } + } } diff --git a/okhttp-tests/src/test/java/okhttp3/URLConnectionTest.java b/okhttp-tests/src/test/java/okhttp3/URLConnectionTest.java index 2c3c8bde1e68..cdfc26a76d91 100644 --- a/okhttp-tests/src/test/java/okhttp3/URLConnectionTest.java +++ b/okhttp-tests/src/test/java/okhttp3/URLConnectionTest.java @@ -34,7 +34,7 @@ import java.net.URL; import java.net.URLConnection; import java.net.UnknownHostException; -import java.security.SecureRandom; +import java.security.KeyStore; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; @@ -56,16 +56,16 @@ import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import okhttp3.internal.DoubleInetAddressDns; import okhttp3.internal.Internal; -import okhttp3.internal.Platform; import okhttp3.internal.RecordingAuthenticator; import okhttp3.internal.RecordingOkAuthenticator; import okhttp3.internal.SingleInetAddressDns; -import okhttp3.internal.SslContextBuilder; import okhttp3.internal.Util; import okhttp3.internal.Version; +import okhttp3.internal.tls.SslClient; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.RecordedRequest; @@ -101,6 +101,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; /** Android's URLConnectionTest. */ public final class URLConnectionTest { @@ -108,7 +109,7 @@ public final class URLConnectionTest { @Rule public final MockWebServer server2 = new MockWebServer(); @Rule public final TemporaryFolder tempDir = new TemporaryFolder(); - private SSLContext sslContext = SslContextBuilder.localhost(); + private SslClient sslClient = SslClient.localhost(); private OkUrlFactory urlFactory; private HttpURLConnection connection; private Cache cache; @@ -519,11 +520,11 @@ private void doUpload(TransferKind uploadKind, WriteKind writeKind) throws Excep } @Test public void connectViaHttps() throws Exception { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().setBody("this response comes via HTTPS")); urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .build()); connection = urlFactory.open(server.url("/foo").url()); @@ -535,11 +536,11 @@ private void doUpload(TransferKind uploadKind, WriteKind writeKind) throws Excep } @Test public void inspectHandshakeThroughoutRequestLifecycle() throws Exception { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse()); urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .build()); @@ -567,16 +568,16 @@ private void doUpload(TransferKind uploadKind, WriteKind writeKind) throws Excep } @Test public void connectViaHttpsReusingConnections() throws IOException, InterruptedException { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().setBody("this response comes via HTTPS")); server.enqueue(new MockResponse().setBody("another response via HTTPS")); // The pool will only reuse sockets if the SSL socket factories are the same. - SSLSocketFactory clientSocketFactory = sslContext.getSocketFactory(); + SSLSocketFactory clientSocketFactory = sslClient.socketFactory; RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier(); urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(clientSocketFactory) + .sslSocketFactory(clientSocketFactory, sslClient.trustManager) .hostnameVerifier(hostnameVerifier) .build()); connection = urlFactory.open(server.url("/").url()); @@ -590,13 +591,13 @@ private void doUpload(TransferKind uploadKind, WriteKind writeKind) throws Excep } @Test public void connectViaHttpsReusingConnectionsDifferentFactories() throws Exception { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().setBody("this response comes via HTTPS")); server.enqueue(new MockResponse().setBody("another response via HTTPS")); // install a custom SSL socket factory so the server can be authorized urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .build()); HttpURLConnection connection1 = urlFactory.open(server.url("/").url()); @@ -605,8 +606,14 @@ private void doUpload(TransferKind uploadKind, WriteKind writeKind) throws Excep SSLContext sslContext2 = SSLContext.getInstance("TLS"); sslContext2.init(null, null, null); SSLSocketFactory sslSocketFactory2 = sslContext2.getSocketFactory(); + + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init((KeyStore) null); + X509TrustManager trustManager = (X509TrustManager) trustManagerFactory.getTrustManagers()[0]; + urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(sslSocketFactory2) + .sslSocketFactory(sslSocketFactory2, trustManager) .build()); HttpURLConnection connection2 = urlFactory.open(server.url("/").url()); try { @@ -619,13 +626,13 @@ private void doUpload(TransferKind uploadKind, WriteKind writeKind) throws Excep // TODO(jwilson): tests below this marker need to be migrated to OkHttp's request/response API. @Test public void connectViaHttpsWithSSLFallback() throws Exception { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().setSocketPolicy(FAIL_HANDSHAKE)); server.enqueue(new MockResponse().setBody("this response comes via SSL")); urlFactory.setClient(urlFactory.client().newBuilder() .hostnameVerifier(new RecordingHostnameVerifier()) - .sslSocketFactory(suppressTlsFallbackClientSocketFactory()) + .sslSocketFactory(suppressTlsFallbackClientSocketFactory(), sslClient.trustManager) .build()); connection = urlFactory.open(server.url("/foo").url()); @@ -640,14 +647,14 @@ private void doUpload(TransferKind uploadKind, WriteKind writeKind) throws Excep } @Test public void connectViaHttpsWithSSLFallbackFailuresRecorded() throws Exception { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().setSocketPolicy(FAIL_HANDSHAKE)); server.enqueue(new MockResponse().setSocketPolicy(FAIL_HANDSHAKE)); urlFactory.setClient(urlFactory.client().newBuilder() .dns(new SingleInetAddressDns()) .hostnameVerifier(new RecordingHostnameVerifier()) - .sslSocketFactory(suppressTlsFallbackClientSocketFactory()) + .sslSocketFactory(suppressTlsFallbackClientSocketFactory(), sslClient.trustManager) .build()); connection = urlFactory.open(server.url("/foo").url()); @@ -666,7 +673,7 @@ private void doUpload(TransferKind uploadKind, WriteKind writeKind) throws Excep * https://github.com/square/okhttp/issues/515 */ @Test public void sslFallbackNotUsedWhenRecycledConnectionFails() throws Exception { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse() .setBody("abc") .setSocketPolicy(DISCONNECT_AT_END)); @@ -674,7 +681,7 @@ private void doUpload(TransferKind uploadKind, WriteKind writeKind) throws Excep urlFactory.setClient(urlFactory.client().newBuilder() .hostnameVerifier(new RecordingHostnameVerifier()) - .sslSocketFactory(suppressTlsFallbackClientSocketFactory()) + .sslSocketFactory(suppressTlsFallbackClientSocketFactory(), sslClient.trustManager) .build()); assertContent("abc", urlFactory.open(server.url("/").url())); @@ -700,7 +707,7 @@ private void doUpload(TransferKind uploadKind, WriteKind writeKind) throws Excep * http://code.google.com/p/android/issues/detail?id=13178 */ @Test public void connectViaHttpsToUntrustedServer() throws IOException, InterruptedException { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse()); // unused connection = urlFactory.open(server.url("/foo").url()); @@ -782,9 +789,9 @@ public Socket createSocket(String host, int port, InetAddress localHost, int loc }; if (useHttps) { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .build()); } @@ -862,12 +869,12 @@ public Socket createSocket(String host, int port, InetAddress localHost, int loc } private void testConnectViaDirectProxyToHttps(ProxyConfig proxyConfig) throws Exception { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().setBody("this response comes via HTTPS")); URL url = server.url("/foo").url(); urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .build()); connection = proxyConfig.connect(server, urlFactory, url); @@ -901,14 +908,14 @@ private void testConnectViaDirectProxyToHttps(ProxyConfig proxyConfig) throws Ex private void testConnectViaHttpProxyToHttps(ProxyConfig proxyConfig) throws Exception { RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier(); - server.useHttps(sslContext.getSocketFactory(), true); + server.useHttps(sslClient.socketFactory, true); server.enqueue( new MockResponse().setSocketPolicy(UPGRADE_TO_SSL_AT_END).clearHeaders()); server.enqueue(new MockResponse().setBody("this response comes via a secure proxy")); URL url = new URL("https://android.com/foo"); urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(hostnameVerifier) .build()); connection = proxyConfig.connect(server, urlFactory, url); @@ -930,7 +937,7 @@ private void testConnectViaHttpProxyToHttps(ProxyConfig proxyConfig) throws Exce @Test public void connectViaHttpProxyToHttpsUsingBadProxyAndHttpResponseCache() throws Exception { initResponseCache(); - server.useHttps(sslContext.getSocketFactory(), true); + server.useHttps(sslClient.socketFactory, true); // The inclusion of a body in the response to a CONNECT is key to reproducing b/6754912. MockResponse badProxyResponse = new MockResponse() .setSocketPolicy(UPGRADE_TO_SSL_AT_END) @@ -942,7 +949,7 @@ private void testConnectViaHttpProxyToHttps(ProxyConfig proxyConfig) throws Exce // failure to fail permanently. urlFactory.setClient(urlFactory.client().newBuilder() .dns(new SingleInetAddressDns()) - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .connectionSpecs(Util.immutableList(ConnectionSpec.MODERN_TLS)) .hostnameVerifier(new RecordingHostnameVerifier()) .proxy(server.toProxyAddress()) @@ -969,14 +976,14 @@ private void initResponseCache() throws IOException { throws IOException, InterruptedException { RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier(); - server.useHttps(sslContext.getSocketFactory(), true); + server.useHttps(sslClient.socketFactory, true); server.enqueue( new MockResponse().setSocketPolicy(UPGRADE_TO_SSL_AT_END).clearHeaders()); server.enqueue(new MockResponse().setBody("encrypted response from the origin server")); urlFactory.setClient(urlFactory.client().newBuilder() .proxy(server.toProxyAddress()) - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(hostnameVerifier) .build()); @@ -1001,7 +1008,7 @@ private void initResponseCache() throws IOException { @Test public void proxyAuthenticateOnConnect() throws Exception { Authenticator.setDefault(new RecordingAuthenticator()); - server.useHttps(sslContext.getSocketFactory(), true); + server.useHttps(sslClient.socketFactory, true); server.enqueue(new MockResponse().setResponseCode(407) .addHeader("Proxy-Authenticate: Basic realm=\"localhost\"")); server.enqueue( @@ -1011,7 +1018,7 @@ private void initResponseCache() throws IOException { urlFactory.setClient(urlFactory.client().newBuilder() .proxyAuthenticator(new JavaNetAuthenticator()) .proxy(server.toProxyAddress()) - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .build()); @@ -1036,14 +1043,14 @@ private void initResponseCache() throws IOException { // Don't disconnect after building a tunnel with CONNECT // http://code.google.com/p/android/issues/detail?id=37221 @Test public void proxyWithConnectionClose() throws IOException { - server.useHttps(sslContext.getSocketFactory(), true); + server.useHttps(sslClient.socketFactory, true); server.enqueue( new MockResponse().setSocketPolicy(UPGRADE_TO_SSL_AT_END).clearHeaders()); server.enqueue(new MockResponse().setBody("this response comes via a proxy")); urlFactory.setClient(urlFactory.client().newBuilder() .proxy(server.toProxyAddress()) - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .build()); @@ -1055,7 +1062,7 @@ private void initResponseCache() throws IOException { } @Test public void proxyWithConnectionReuse() throws IOException { - SSLSocketFactory socketFactory = sslContext.getSocketFactory(); + SSLSocketFactory socketFactory = sslClient.socketFactory; RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier(); server.useHttps(socketFactory, true); @@ -1066,7 +1073,7 @@ private void initResponseCache() throws IOException { urlFactory.setClient(urlFactory.client().newBuilder() .proxy(server.toProxyAddress()) - .sslSocketFactory(socketFactory) + .sslSocketFactory(socketFactory, sslClient.trustManager) .hostnameVerifier(hostnameVerifier) .build()); URL url = new URL("https://android.com/foo"); @@ -1304,11 +1311,11 @@ private void testMarkAndReset(TransferKind transferKind) throws IOException { private void testClientConfiguredGzipContentEncodingAndConnectionReuse(TransferKind transferKind, boolean tls) throws Exception { if (tls) { - SSLSocketFactory socketFactory = sslContext.getSocketFactory(); + SSLSocketFactory socketFactory = sslClient.socketFactory; RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier(); server.useHttps(socketFactory, false); urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(socketFactory) + .sslSocketFactory(socketFactory, sslClient.trustManager) .hostnameVerifier(hostnameVerifier) .build()); } @@ -1744,11 +1751,11 @@ private void assertInvalidRequestMethod(String requestMethod) throws Exception { * http://code.google.com/p/android/issues/detail?id=12860 */ private void testSecureStreamingPost(StreamingMode streamingMode) throws Exception { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().setBody("Success!")); urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .build()); connection = urlFactory.open(server.url("/").url()); @@ -1929,14 +1936,14 @@ private void testRedirected(TransferKind transferKind, boolean reuse) throws Exc } @Test public void redirectedOnHttps() throws IOException, InterruptedException { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) .addHeader("Location: /foo") .setBody("This page has moved!")); server.enqueue(new MockResponse().setBody("This is the new location!")); urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .build()); connection = urlFactory.open(server.url("/").url()); @@ -1951,14 +1958,14 @@ private void testRedirected(TransferKind transferKind, boolean reuse) throws Exc } @Test public void notRedirectedFromHttpsToHttp() throws IOException, InterruptedException { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) .addHeader("Location: http://anyhost/foo") .setBody("This page has moved!")); urlFactory.setClient(urlFactory.client().newBuilder() .followSslRedirects(false) - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .build()); connection = urlFactory.open(server.url("/").url()); @@ -1980,13 +1987,13 @@ private void testRedirected(TransferKind transferKind, boolean reuse) throws Exc @Test public void redirectedFromHttpsToHttpFollowingProtocolRedirects() throws Exception { server2.enqueue(new MockResponse().setBody("This is insecure HTTP!")); - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) .addHeader("Location: " + server2.url("/").url()) .setBody("This page has moved!")); urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .followSslRedirects(true) .build()); @@ -2000,7 +2007,7 @@ private void testRedirected(TransferKind transferKind, boolean reuse) throws Exc } @Test public void redirectedFromHttpToHttpsFollowingProtocolRedirects() throws Exception { - server2.useHttps(sslContext.getSocketFactory(), false); + server2.useHttps(sslClient.socketFactory, false); server2.enqueue(new MockResponse().setBody("This is secure HTTPS!")); server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) @@ -2008,7 +2015,7 @@ private void testRedirected(TransferKind transferKind, boolean reuse) throws Exc .setBody("This page has moved!")); urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .followSslRedirects(true) .build()); @@ -2027,11 +2034,11 @@ private void testRedirected(TransferKind transferKind, boolean reuse) throws Exc private void redirectToAnotherOriginServer(boolean https) throws Exception { if (https) { - server.useHttps(sslContext.getSocketFactory(), false); - server2.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); + server2.useHttps(sslClient.socketFactory, false); server2.setProtocolNegotiationEnabled(false); urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .build()); } @@ -2309,15 +2316,15 @@ private void testRedirect(boolean temporary, String method) throws Exception { @Test public void httpsWithCustomTrustManager() throws Exception { RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier(); - RecordingTrustManager trustManager = new RecordingTrustManager(sslContext); - SSLContext sc = SSLContext.getInstance("TLS"); - sc.init(null, new TrustManager[] {trustManager}, new SecureRandom()); + RecordingTrustManager trustManager = new RecordingTrustManager(sslClient.trustManager); + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, new TrustManager[] { trustManager }, null); urlFactory.setClient(urlFactory.client().newBuilder() .hostnameVerifier(hostnameVerifier) - .sslSocketFactory(sc.getSocketFactory()) + .sslSocketFactory(sslContext.getSocketFactory(), trustManager) .build()); - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().setBody("ABC")); server.enqueue(new MockResponse().setBody("DEF")); server.enqueue(new MockResponse().setBody("GHI")); @@ -3451,6 +3458,18 @@ private void zeroLengthPayload(String method) testInstanceFollowsRedirects("https://www.google.com/"); } + @Test public void setSslSocketFactoryFailsOnJdk9() throws Exception { + assumeTrue(getPlatform().equals("jdk9")); + + URL url = server.url("/").url(); + HttpsURLConnection connection = (HttpsURLConnection) urlFactory.open(url); + try { + connection.setSSLSocketFactory(sslClient.socketFactory); + fail(); + } catch (UnsupportedOperationException expected) { + } + } + private void testInstanceFollowsRedirects(String spec) throws Exception { URL url = new URL(spec); HttpURLConnection urlConnection = urlFactory.open(url); @@ -3589,8 +3608,8 @@ private static class RecordingTrustManager implements X509TrustManager { private final List calls = new ArrayList(); private final X509TrustManager delegate; - public RecordingTrustManager(SSLContext sslContext) { - this.delegate = Platform.get().trustManager(sslContext.getSocketFactory()); + public RecordingTrustManager(X509TrustManager delegate) { + this.delegate = delegate; } public X509Certificate[] getAcceptedIssuers() { @@ -3622,11 +3641,11 @@ private String certificatesToString(X509Certificate[] certificates) { */ private void enableProtocol(Protocol protocol) { urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .protocols(Arrays.asList(protocol, Protocol.HTTP_1_1)) .build()); - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.setProtocolNegotiationEnabled(true); server.setProtocols(urlFactory.client().protocols()); } @@ -3637,6 +3656,10 @@ private void enableProtocol(Protocol protocol) { * for details. */ private FallbackTestClientSocketFactory suppressTlsFallbackClientSocketFactory() { - return new FallbackTestClientSocketFactory(sslContext.getSocketFactory()); + return new FallbackTestClientSocketFactory(sslClient.socketFactory); + } + + private String getPlatform() { + return System.getProperty("okhttp.platform", "platform"); } } diff --git a/okhttp-tests/src/test/java/okhttp3/internal/ConnectionSpecSelectorTest.java b/okhttp-tests/src/test/java/okhttp3/internal/ConnectionSpecSelectorTest.java index b6aa5344c2c8..96c6585a3415 100644 --- a/okhttp-tests/src/test/java/okhttp3/internal/ConnectionSpecSelectorTest.java +++ b/okhttp-tests/src/test/java/okhttp3/internal/ConnectionSpecSelectorTest.java @@ -20,11 +20,11 @@ import java.util.Arrays; import java.util.LinkedHashSet; import java.util.Set; -import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLSocket; import okhttp3.ConnectionSpec; import okhttp3.TlsVersion; +import okhttp3.internal.tls.SslClient; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -39,7 +39,7 @@ public class ConnectionSpecSelectorTest { public static final SSLHandshakeException RETRYABLE_EXCEPTION = new SSLHandshakeException( "Simulated handshake exception"); - private SSLContext sslContext = SslContextBuilder.localhost(); + private SslClient sslClient = SslClient.localhost(); @Test public void nonRetryableIOException() throws Exception { @@ -120,7 +120,7 @@ private static ConnectionSpecSelector createConnectionSpecSelector( } private SSLSocket createSocketWithEnabledProtocols(TlsVersion... tlsVersions) throws IOException { - SSLSocket socket = (SSLSocket) sslContext.getSocketFactory().createSocket(); + SSLSocket socket = (SSLSocket) sslClient.socketFactory.createSocket(); socket.setEnabledProtocols(javaNames(tlsVersions)); return socket; } diff --git a/okhttp-tests/src/test/java/okhttp3/internal/framed/HttpOverSpdyTest.java b/okhttp-tests/src/test/java/okhttp3/internal/framed/HttpOverSpdyTest.java index c189d6be1a3b..23923d9cb4b3 100644 --- a/okhttp-tests/src/test/java/okhttp3/internal/framed/HttpOverSpdyTest.java +++ b/okhttp-tests/src/test/java/okhttp3/internal/framed/HttpOverSpdyTest.java @@ -25,7 +25,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLContext; import okhttp3.Cache; import okhttp3.Call; import okhttp3.Cookie; @@ -41,8 +40,8 @@ import okhttp3.internal.DoubleInetAddressDns; import okhttp3.internal.RecordingOkAuthenticator; import okhttp3.internal.SingleInetAddressDns; -import okhttp3.internal.SslContextBuilder; import okhttp3.internal.Util; +import okhttp3.internal.tls.SslClient; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.RecordedRequest; @@ -74,7 +73,7 @@ public abstract class HttpOverSpdyTest { private final Protocol protocol; protected String hostHeader = ":host"; - protected SSLContext sslContext = SslContextBuilder.localhost(); + protected SslClient sslClient = SslClient.localhost(); protected HostnameVerifier hostnameVerifier = new RecordingHostnameVerifier(); protected OkHttpClient client; protected Cache cache; @@ -84,12 +83,12 @@ protected HttpOverSpdyTest(Protocol protocol) { } @Before public void setUp() throws Exception { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); cache = new Cache(tempDir.getRoot(), Integer.MAX_VALUE); client = new OkHttpClient.Builder() .protocols(Arrays.asList(protocol, Protocol.HTTP_1_1)) .dns(new SingleInetAddressDns()) - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(hostnameVerifier) .build(); } diff --git a/okhttp-tests/src/test/java/okhttp3/internal/http/RouteSelectorTest.java b/okhttp-tests/src/test/java/okhttp3/internal/http/RouteSelectorTest.java index 7f0b47037d30..b1e3fca3052f 100644 --- a/okhttp-tests/src/test/java/okhttp3/internal/http/RouteSelectorTest.java +++ b/okhttp-tests/src/test/java/okhttp3/internal/http/RouteSelectorTest.java @@ -30,7 +30,6 @@ import javax.net.SocketFactory; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import okhttp3.Address; import okhttp3.Authenticator; @@ -39,8 +38,8 @@ import okhttp3.Protocol; import okhttp3.Route; import okhttp3.internal.RouteDatabase; -import okhttp3.internal.SslContextBuilder; import okhttp3.internal.Util; +import okhttp3.internal.tls.SslClient; import org.junit.Before; import org.junit.Test; @@ -68,8 +67,8 @@ public final class RouteSelectorTest { private int uriPort = 1003; private SocketFactory socketFactory; - private final SSLContext sslContext = SslContextBuilder.localhost(); - private final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); + private final SslClient sslClient = SslClient.localhost(); + private final SSLSocketFactory sslSocketFactory = sslClient.socketFactory; private HostnameVerifier hostnameVerifier; private final Authenticator authenticator = Authenticator.NONE; diff --git a/okhttp-tests/src/test/java/okhttp3/internal/tls/CertificatePinnerChainValidationTest.java b/okhttp-tests/src/test/java/okhttp3/internal/tls/CertificatePinnerChainValidationTest.java index 8c50399878e8..4b59edbf6e1e 100644 --- a/okhttp-tests/src/test/java/okhttp3/internal/tls/CertificatePinnerChainValidationTest.java +++ b/okhttp-tests/src/test/java/okhttp3/internal/tls/CertificatePinnerChainValidationTest.java @@ -15,7 +15,6 @@ */ package okhttp3.internal.tls; -import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLPeerUnverifiedException; import okhttp3.Call; @@ -24,8 +23,6 @@ import okhttp3.RecordingHostnameVerifier; import okhttp3.Request; import okhttp3.Response; -import okhttp3.internal.HeldCertificate; -import okhttp3.internal.SslContextBuilder; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.SocketPolicy; @@ -60,19 +57,19 @@ public final class CertificatePinnerChainValidationTest { CertificatePinner certificatePinner = new CertificatePinner.Builder() .add(server.getHostName(), CertificatePinner.pin(rootCa.certificate)) .build(); - SSLContext clientContext = new SslContextBuilder() + SslClient sslClient = new SslClient.Builder() .addTrustedCertificate(rootCa.certificate) .build(); OkHttpClient client = new OkHttpClient.Builder() - .sslSocketFactory(clientContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .certificatePinner(certificatePinner) .build(); - SSLContext serverSslContext = new SslContextBuilder() + SslClient serverSslClient = new SslClient.Builder() .certificateChain(certificate, intermediateCa) .build(); - server.useHttps(serverSslContext.getSocketFactory(), false); + server.useHttps(serverSslClient.socketFactory, false); // The request should complete successfully. server.enqueue(new MockResponse() @@ -116,19 +113,19 @@ public final class CertificatePinnerChainValidationTest { CertificatePinner certificatePinner = new CertificatePinner.Builder() .add(server.getHostName(), CertificatePinner.pin(intermediateCa.certificate)) .build(); - SSLContext clientContext = new SslContextBuilder() + SslClient contextBuilder = new SslClient.Builder() .addTrustedCertificate(rootCa.certificate) .build(); OkHttpClient client = new OkHttpClient.Builder() - .sslSocketFactory(clientContext.getSocketFactory()) + .sslSocketFactory(contextBuilder.socketFactory, contextBuilder.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .certificatePinner(certificatePinner) .build(); - SSLContext serverSslContext = new SslContextBuilder() - .certificateChain(certificate, intermediateCa) + SslClient serverSslContext = new SslClient.Builder() + .certificateChain(certificate.keyPair, certificate.certificate, intermediateCa.certificate) .build(); - server.useHttps(serverSslContext.getSocketFactory(), false); + server.useHttps(serverSslContext.socketFactory, false); // The request should complete successfully. server.enqueue(new MockResponse() @@ -176,11 +173,11 @@ public final class CertificatePinnerChainValidationTest { CertificatePinner certificatePinner = new CertificatePinner.Builder() .add(server.getHostName(), CertificatePinner.pin(goodCertificate.certificate)) .build(); - SSLContext clientContext = new SslContextBuilder() + SslClient clientContextBuilder = new SslClient.Builder() .addTrustedCertificate(rootCa.certificate) .build(); OkHttpClient client = new OkHttpClient.Builder() - .sslSocketFactory(clientContext.getSocketFactory()) + .sslSocketFactory(clientContextBuilder.socketFactory, clientContextBuilder.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .certificatePinner(certificatePinner) .build(); @@ -200,10 +197,10 @@ public final class CertificatePinnerChainValidationTest { .issuedBy(compromisedIntermediateCa) .commonName(server.getHostName()) .build(); - SSLContext serverSslContext = new SslContextBuilder() - .certificateChain(rogueCertificate, compromisedIntermediateCa, goodCertificate, rootCa) + SslClient serverSslContext = new SslClient.Builder() + .certificateChain(rogueCertificate.keyPair, rogueCertificate.certificate, compromisedIntermediateCa.certificate, goodCertificate.certificate, rootCa.certificate) .build(); - server.useHttps(serverSslContext.getSocketFactory(), false); + server.useHttps(serverSslContext.socketFactory, false); server.enqueue(new MockResponse() .setBody("abc") .addHeader("Content-Type: text/plain")); @@ -249,12 +246,12 @@ public final class CertificatePinnerChainValidationTest { CertificatePinner certificatePinner = new CertificatePinner.Builder() .add(server.getHostName(), CertificatePinner.pin(goodIntermediateCa.certificate)) .build(); - SSLContext clientContext = new SslContextBuilder() + SslClient clientContextBuilder = new SslClient.Builder() .addTrustedCertificate(rootCa.certificate) .addTrustedCertificate(compromisedRootCa.certificate) .build(); OkHttpClient client = new OkHttpClient.Builder() - .sslSocketFactory(clientContext.getSocketFactory()) + .sslSocketFactory(clientContextBuilder.socketFactory, clientContextBuilder.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .certificatePinner(certificatePinner) .build(); @@ -274,11 +271,11 @@ public final class CertificatePinnerChainValidationTest { .issuedBy(compromisedIntermediateCa) .commonName(server.getHostName()) .build(); - SSLContext serverSslContext = new SslContextBuilder() + SslClient serverSslContext = new SslClient.Builder() .certificateChain( - rogueCertificate, goodIntermediateCa, compromisedIntermediateCa, compromisedRootCa) + rogueCertificate.keyPair, rogueCertificate.certificate, goodIntermediateCa.certificate, compromisedIntermediateCa.certificate, compromisedRootCa.certificate) .build(); - server.useHttps(serverSslContext.getSocketFactory(), false); + server.useHttps(serverSslContext.socketFactory, false); server.enqueue(new MockResponse() .setBody("abc") .addHeader("Content-Type: text/plain")); diff --git a/okhttp-urlconnection/src/main/java/okhttp3/internal/huc/HttpsURLConnectionImpl.java b/okhttp-urlconnection/src/main/java/okhttp3/internal/huc/HttpsURLConnectionImpl.java index 1bf1fa6566ee..05e26353c415 100644 --- a/okhttp-urlconnection/src/main/java/okhttp3/internal/huc/HttpsURLConnectionImpl.java +++ b/okhttp-urlconnection/src/main/java/okhttp3/internal/huc/HttpsURLConnectionImpl.java @@ -63,6 +63,7 @@ public HttpsURLConnectionImpl(HttpURLConnectionImpl delegate) { } @Override public void setSSLSocketFactory(SSLSocketFactory sslSocketFactory) { + // This fails in JDK 9 because OkHttp is unable to extract the trust manager. delegate.client = delegate.client.newBuilder() .sslSocketFactory(sslSocketFactory) .build(); diff --git a/okhttp-urlconnection/src/test/java/okhttp3/OkUrlFactoryTest.java b/okhttp-urlconnection/src/test/java/okhttp3/OkUrlFactoryTest.java index 39f6066805dd..985e545c7fd1 100644 --- a/okhttp-urlconnection/src/test/java/okhttp3/OkUrlFactoryTest.java +++ b/okhttp-urlconnection/src/test/java/okhttp3/OkUrlFactoryTest.java @@ -11,11 +11,10 @@ import java.util.TimeZone; import java.util.concurrent.TimeUnit; import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; -import okhttp3.internal.SslContextBuilder; import okhttp3.internal.URLFilter; import okhttp3.internal.http.OkHeaders; import okhttp3.internal.io.InMemoryFileSystem; +import okhttp3.internal.tls.SslClient; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import okio.BufferedSource; @@ -184,10 +183,10 @@ public void testURLFilterRedirect() throws Exception { .setBody("Blocked!")); final URL blockedURL = cleartextServer.url("/").url(); - SSLContext context = SslContextBuilder.localhost(); - server.useHttps(context.getSocketFactory(), false); + SslClient contextBuilder = SslClient.localhost(); + server.useHttps(contextBuilder.socketFactory, false); factory.setClient(factory.client().newBuilder() - .sslSocketFactory(context.getSocketFactory()) + .sslSocketFactory(contextBuilder.socketFactory, contextBuilder.trustManager) .followSslRedirects(true) .build()); factory.setUrlFilter(new URLFilter() { diff --git a/okhttp-urlconnection/src/test/java/okhttp3/UrlConnectionCacheTest.java b/okhttp-urlconnection/src/test/java/okhttp3/UrlConnectionCacheTest.java index a5b1107868f6..693af67443ab 100644 --- a/okhttp-urlconnection/src/test/java/okhttp3/UrlConnectionCacheTest.java +++ b/okhttp-urlconnection/src/test/java/okhttp3/UrlConnectionCacheTest.java @@ -40,12 +40,11 @@ import java.util.concurrent.TimeUnit; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import okhttp3.internal.Internal; -import okhttp3.internal.SslContextBuilder; import okhttp3.internal.Util; import okhttp3.internal.io.InMemoryFileSystem; +import okhttp3.internal.tls.SslClient; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.RecordedRequest; @@ -66,6 +65,7 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; /** Test caching with {@link OkUrlFactory}. */ public final class UrlConnectionCacheTest { @@ -79,7 +79,7 @@ public final class UrlConnectionCacheTest { @Rule public MockWebServer server2 = new MockWebServer(); @Rule public InMemoryFileSystem fileSystem = new InMemoryFileSystem(); - private final SSLContext sslContext = SslContextBuilder.localhost(); + private final SslClient sslClient = SslClient.localhost(); private OkUrlFactory urlFactory = new OkUrlFactory(new OkHttpClient()); private Cache cache; private final CookieManager cookieManager = new CookieManager(); @@ -257,13 +257,15 @@ private void testResponseCaching(TransferKind transferKind) throws IOException { } @Test public void secureResponseCaching() throws IOException { - server.useHttps(sslContext.getSocketFactory(), false); + assumeFalse(getPlatform().equals("jdk9")); + + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) .setBody("ABC")); HttpsURLConnection c1 = (HttpsURLConnection) urlFactory.open(server.url("/").url()); - c1.setSSLSocketFactory(sslContext.getSocketFactory()); + c1.setSSLSocketFactory(sslClient.socketFactory); c1.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); assertEquals("ABC", readAscii(c1)); @@ -275,7 +277,7 @@ private void testResponseCaching(TransferKind transferKind) throws IOException { Principal localPrincipal = c1.getLocalPrincipal(); HttpsURLConnection c2 = (HttpsURLConnection) urlFactory.open(server.url("/").url()); // cached! - c2.setSSLSocketFactory(sslContext.getSocketFactory()); + c2.setSSLSocketFactory(sslClient.socketFactory); c2.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); assertEquals("ABC", readAscii(c2)); @@ -335,7 +337,7 @@ private void testResponseCaching(TransferKind transferKind) throws IOException { } @Test public void secureResponseCachingAndRedirects() throws IOException { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) @@ -346,7 +348,7 @@ private void testResponseCaching(TransferKind transferKind) throws IOException { server.enqueue(new MockResponse().setBody("DEF")); urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(NULL_HOSTNAME_VERIFIER) .build()); @@ -372,7 +374,7 @@ private void testResponseCaching(TransferKind transferKind) throws IOException { * https://github.com/square/okhttp/issues/214 */ @Test public void secureResponseCachingAndProtocolRedirects() throws IOException { - server2.useHttps(sslContext.getSocketFactory(), false); + server2.useHttps(sslClient.socketFactory, false); server2.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) .setBody("ABC")); @@ -384,7 +386,7 @@ private void testResponseCaching(TransferKind transferKind) throws IOException { .addHeader("Location: " + server2.url("/").url())); urlFactory.setClient(urlFactory.client().newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(NULL_HOSTNAME_VERIFIER) .build()); @@ -1400,7 +1402,9 @@ private RecordedRequest assertClientSuppliedCondition(MockResponse seed, String } @Test public void varyAndHttps() throws Exception { - server.useHttps(sslContext.getSocketFactory(), false); + assumeFalse(getPlatform().equals("jdk9")); + + server.useHttps(sslClient.socketFactory, false); server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") .addHeader("Vary: Accept-Language") .setBody("A")); @@ -1408,13 +1412,13 @@ private RecordedRequest assertClientSuppliedCondition(MockResponse seed, String URL url = server.url("/").url(); HttpsURLConnection connection1 = (HttpsURLConnection) urlFactory.open(url); - connection1.setSSLSocketFactory(sslContext.getSocketFactory()); + connection1.setSSLSocketFactory(sslClient.socketFactory); connection1.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); connection1.addRequestProperty("Accept-Language", "en-US"); assertEquals("A", readAscii(connection1)); HttpsURLConnection connection2 = (HttpsURLConnection) urlFactory.open(url); - connection2.setSSLSocketFactory(sslContext.getSocketFactory()); + connection2.setSSLSocketFactory(sslClient.socketFactory); connection2.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); connection2.addRequestProperty("Accept-Language", "en-US"); assertEquals("A", readAscii(connection2)); @@ -1834,4 +1838,8 @@ public Buffer gzip(String data) throws IOException { sink.close(); return result; } + + private String getPlatform() { + return System.getProperty("okhttp.platform", "platform"); + } } diff --git a/okhttp-ws-tests/src/test/java/okhttp3/ws/WebSocketCallTest.java b/okhttp-ws-tests/src/test/java/okhttp3/ws/WebSocketCallTest.java index 2e66deca89cc..06dd4a2e281c 100644 --- a/okhttp-ws-tests/src/test/java/okhttp3/ws/WebSocketCallTest.java +++ b/okhttp-ws-tests/src/test/java/okhttp3/ws/WebSocketCallTest.java @@ -21,16 +21,15 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; -import javax.net.ssl.SSLContext; import okhttp3.OkHttpClient; +import okhttp3.RecordingHostnameVerifier; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; -import okhttp3.internal.SslContextBuilder; +import okhttp3.internal.tls.SslClient; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; -import okhttp3.RecordingHostnameVerifier; import okio.Buffer; import org.junit.After; import org.junit.Rule; @@ -41,7 +40,7 @@ public final class WebSocketCallTest { @Rule public final MockWebServer server = new MockWebServer(); - private final SSLContext sslContext = SslContextBuilder.localhost(); + private final SslClient sslClient = SslClient.localhost(); private final WebSocketRecorder listener = new WebSocketRecorder(); private final Random random = new Random(0); private OkHttpClient client = new OkHttpClient(); @@ -185,9 +184,9 @@ public final class WebSocketCallTest { } @Test public void wssScheme() throws IOException { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); client = client.newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .build(); @@ -195,9 +194,9 @@ public final class WebSocketCallTest { } @Test public void httpsScheme() throws IOException { - server.useHttps(sslContext.getSocketFactory(), false); + server.useHttps(sslClient.socketFactory, false); client = client.newBuilder() - .sslSocketFactory(sslContext.getSocketFactory()) + .sslSocketFactory(sslClient.socketFactory, sslClient.trustManager) .hostnameVerifier(new RecordingHostnameVerifier()) .build(); diff --git a/okhttp/src/main/java/okhttp3/internal/Jdk9Platform.java b/okhttp/src/main/java/okhttp3/internal/Jdk9Platform.java index 94677ebe225c..1cd04f965af0 100644 --- a/okhttp/src/main/java/okhttp3/internal/Jdk9Platform.java +++ b/okhttp/src/main/java/okhttp3/internal/Jdk9Platform.java @@ -20,6 +20,8 @@ import java.util.List; import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.X509TrustManager; import okhttp3.Protocol; /** @@ -36,14 +38,14 @@ public Jdk9Platform(Method setProtocolMethod, Method getProtocolMethod) { @Override public void configureTlsExtensions(SSLSocket sslSocket, String hostname, - List protocols) { + List protocols) { try { SSLParameters sslParameters = sslSocket.getSSLParameters(); List names = alpnProtocolNames(protocols); setProtocolMethod.invoke(sslParameters, - new Object[]{names.toArray(new String[names.size()])}); + new Object[] {names.toArray(new String[names.size()])}); sslSocket.setSSLParameters(sslParameters); } catch (IllegalAccessException | InvocationTargetException e) { @@ -68,6 +70,15 @@ public String getSelectedProtocol(SSLSocket socket) { } } + @Override public X509TrustManager trustManager(SSLSocketFactory sslSocketFactory) { + // Not supported due to access checks on JDK 9+: + // java.lang.reflect.InaccessibleObjectException: Unable to make member of class + // sun.security.ssl.SSLSocketFactoryImpl accessible: module java.base does not export + // sun.security.ssl to unnamed module @xxx + throw new UnsupportedOperationException( + "clientBuilder.sslSocketFactory(SSLSocketFactory) not supported on JDK 9+"); + } + public static Jdk9Platform buildIfSupported() { // Find JDK 9 new methods try { diff --git a/pom.xml b/pom.xml index 52054e950364..4be0178ea073 100644 --- a/pom.xml +++ b/pom.xml @@ -304,7 +304,7 @@ jdk9 - 1.9 + 9 jdk9