Skip to content

Instantly share code, notes, and snippets.

@swankjesse
Created March 11, 2017 21:00
Show Gist options
  • Save swankjesse/d094cb17d0562520cdbf64254542694a to your computer and use it in GitHub Desktop.
Save swankjesse/d094cb17d0562520cdbf64254542694a to your computer and use it in GitHub Desktop.
TlsOnIbm
package okhttp3.recipes;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.security.KeyStore;
import java.util.Arrays;
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.Handshake;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.TlsVersion;
public class TlsOnIbm {
public static void main(String[] args) throws Exception {
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));
}
X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] {trustManager}, null);
SSLSocketFactory sslSocketFactory
= new DelegatingSSLSocketFactory(sslContext.getSocketFactory()) {
@Override protected SSLSocket configureSocket(SSLSocket socket) throws IOException {
socket.setEnabledProtocols(new String[] {
TlsVersion.TLS_1_0.javaName(),
TlsVersion.TLS_1_1.javaName(),
TlsVersion.TLS_1_2.javaName()
});
return socket;
}
};
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustManager)
.retryOnConnectionFailure(false)
.build();
Request requestOkhttp = new Request.Builder()
.url("https://ps.pndsn.com")
.build();
Response response = client.newCall(requestOkhttp).execute();
Handshake handshake = response.handshake();
Headers headers = response.headers();
System.out.println("Cipher suite: " + handshake.cipherSuite());
System.out.println("TLS version: " + handshake.tlsVersion());
System.out.println();
System.out.println(response.code() + ": " + response.message());
for (int i = 0, size = headers.size(); i < size; i++) {
System.out.println(headers.name(i) + ": " + headers.value(i));
}
System.out.println();
System.out.println(response.body().string());
}
/**
* 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;
}
}
}
@swankjesse
Copy link
Author

I ran it like so:

docker run \
  -v /Users/jwilson/Square/okhttp:/okhttp \
  -v /Users/jwilson/.m2:/.m2 \
  ibmcom/ibmjava:8-sdk \
  java \
  -cp /.m2/repository/com/squareup/okio/okio/1.11.0/okio-1.11.0.jar:/okhttp/okhttp/target/classes:/okhttp/samples/guide/target/classes \
  okhttp3.recipes.TlsOnIbm

@bruceadams
Copy link

I believe these ten lines https://gist.github.com/swankjesse/d094cb17d0562520cdbf64254542694a#file-tlsonibm-java-L33:L44 can be replaced with:

    SSLContext sslContext = SSLContext.getInstance("TLS");
    if ( "IBM J9 VM".equals(System.getProperty("java.vm.name") ) {
        SSLContext sslContext = SSLContext.getInstance("SSL");
    }

The problem with IBM Java is what, exactly, does "TLS" mean in the call to SSLContext.getInstance, see:
https://www.ibm.com/support/knowledgecenter/SSYKE2_8.0.0/com.ibm.java.security.component.80.doc/security-component/jsse2Docs/protocols.html
IBM chose, a long time ago, for "TLS" in this context to mean only TLSv1.0. Over time, this diverged from Oracle's choices. For reference, here is Oracle's documentation for the meanings of names passed into SSLContext.getInstance:
http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext

@germanattanasio
Copy link

I'm doing the same as what @swankjesse is suggesting here, but I can't make it work.
https://gist.github.com/germanattanasio/3f0e7458328e817b4e63952ffaa93da2

@germanattanasio
Copy link

It seems like it won't work with okhttp 3.6.0 it will only work with the code in master

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment