Skip to content

Commit

Permalink
Merge pull request #3091 from square/jwilson.0107.custom_cipher_siutes
Browse files Browse the repository at this point in the history
Example on customizing cipher suites.
  • Loading branch information
swankjesse committed Jan 8, 2017
2 parents 87a3ec9 + bb0f81e commit bdcd06f
Show file tree
Hide file tree
Showing 2 changed files with 171 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
public final class CheckHandshake {
/** Rejects otherwise-trusted certificates. */
private static final Interceptor CHECK_HANDSHAKE_INTERCEPTOR = new Interceptor() {
Set<String> blacklist = Collections.singleton("sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw=");
Set<String> blacklist = Collections.singleton(
"sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=");

@Override public Response intercept(Chain chain) throws IOException {
for (Certificate certificate : chain.connection().handshake().peerCertificates()) {
Expand Down
169 changes: 169 additions & 0 deletions samples/guide/src/main/java/okhttp3/recipes/CustomCipherSuites.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/*
* Copyright (C) 2017 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package okhttp3.recipes;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.security.GeneralSecurityException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import okhttp3.CipherSuite;
import okhttp3.ConnectionSpec;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public final class CustomCipherSuites {
private final OkHttpClient client;

public CustomCipherSuites() throws GeneralSecurityException {
// Configure cipher suites to demonstrate how to customize which cipher suites will be used for
// an OkHttp request. In order to be selected a cipher suite must be included in both OkHttp's
// connection spec and in the SSLSocket's enabled cipher suites array. Most applications should
// not customize the cipher suites list.
List<CipherSuite> customCipherSuites = Arrays.asList(
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384);
final ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.cipherSuites(customCipherSuites.toArray(new CipherSuite[0]))
.build();

X509TrustManager trustManager = defaultTrustManager();
SSLSocketFactory sslSocketFactory = defaultSslSocketFactory(trustManager);
SSLSocketFactory customSslSocketFactory = new DelegatingSSLSocketFactory(sslSocketFactory) {
@Override protected SSLSocket configureSocket(SSLSocket socket) throws IOException {
socket.setEnabledCipherSuites(javaNames(spec.cipherSuites()));
return socket;
}
};

client = new OkHttpClient.Builder()
.connectionSpecs(Collections.singletonList(spec))
.sslSocketFactory(customSslSocketFactory, trustManager)
.build();
}

/**
* Returns the VM's default SSL socket factory, using {@code trustManager} for trusted root
* certificates.
*/
private SSLSocketFactory defaultSslSocketFactory(X509TrustManager trustManager)
throws NoSuchAlgorithmException, KeyManagementException {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { trustManager }, null);

return sslContext.getSocketFactory();
}

/** Returns a trust manager that trusts the VM's default certificate authorities. */
private X509TrustManager defaultTrustManager() throws GeneralSecurityException {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers:"
+ Arrays.toString(trustManagers));
}
return (X509TrustManager) trustManagers[0];
}

private String[] javaNames(List<CipherSuite> cipherSuites) {
String[] result = new String[cipherSuites.size()];
for (int i = 0; i < result.length; i++) {
result[i] = cipherSuites.get(i).javaName();
}
return result;
}

/**
* An SSL socket factory that forwards all calls to a delegate. Override {@link #configureSocket}
* to customize a created socket before it is returned.
*/
static class DelegatingSSLSocketFactory extends SSLSocketFactory {
protected final SSLSocketFactory delegate;

public DelegatingSSLSocketFactory(SSLSocketFactory delegate) {
this.delegate = delegate;
}

@Override public String[] getDefaultCipherSuites() {
return delegate.getDefaultCipherSuites();
}

@Override public String[] getSupportedCipherSuites() {
return delegate.getSupportedCipherSuites();
}

@Override public Socket createSocket(
Socket socket, String host, int port, boolean autoClose) throws IOException {
return configureSocket((SSLSocket) delegate.createSocket(socket, host, port, autoClose));
}

@Override public Socket createSocket(String host, int port) throws IOException {
return configureSocket((SSLSocket) delegate.createSocket(host, port));
}

@Override public Socket createSocket(
String host, int port, InetAddress localHost, int localPort) throws IOException {
return configureSocket((SSLSocket) delegate.createSocket(host, port, localHost, localPort));
}

@Override public Socket createSocket(InetAddress host, int port) throws IOException {
return configureSocket((SSLSocket) delegate.createSocket(host, port));
}

@Override public Socket createSocket(
InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return configureSocket((SSLSocket) delegate.createSocket(
address, port, localAddress, localPort));
}

protected SSLSocket configureSocket(SSLSocket socket) throws IOException {
return socket;
}
}

public void run() throws Exception {
Request request = new Request.Builder()
.url("https://publicobject.com/helloworld.txt")
.build();

try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

System.out.println(response.handshake().cipherSuite());
System.out.println(response.body().string());
}
}

public static void main(String... args) throws Exception {
new CustomCipherSuites().run();
}
}

0 comments on commit bdcd06f

Please sign in to comment.