package com.stripe.net; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.HashSet; import java.util.Set; /** * Wraps a SSLSocketFactory and enables more TLS versions */ public class StripeSSLSocketFactory extends SSLSocketFactory { private final SSLSocketFactory under; private final boolean tlsv11Supported, tlsv12Supported; private static final String TLSv11Proto = "TLSv1.1", TLSv12Proto = "TLSv1.2"; public StripeSSLSocketFactory() { this.under = HttpsURLConnection.getDefaultSSLSocketFactory(); // For sufficiently old Java, TLSv1.1 and TLSv1.2 might not be supported, so do some detection boolean tlsv11Supported = false, tlsv12Supported = false; String[] supportedProtos = new String[0]; try { supportedProtos = SSLContext.getDefault().getSupportedSSLParameters().getProtocols(); } catch (NoSuchAlgorithmException e) { } for (String proto : supportedProtos) { if (proto.equals(TLSv11Proto)) { tlsv11Supported = true; } else if (proto.equals(TLSv12Proto)) { tlsv12Supported = true; } } this.tlsv11Supported = tlsv11Supported; this.tlsv12Supported = tlsv12Supported; } private Socket fixupSocket(Socket sock) { if (!(sock instanceof SSLSocket)) { return sock; } SSLSocket sslSock = (SSLSocket) sock; Set<String> protos = new HashSet<String>(Arrays.asList(sslSock.getEnabledProtocols())); if (tlsv11Supported) { protos.add(TLSv11Proto); } if (tlsv12Supported) { protos.add(TLSv12Proto); } sslSock.setEnabledProtocols(protos.toArray(new String[0])); return sslSock; } @Override public String[] getDefaultCipherSuites() { return this.under.getDefaultCipherSuites(); } @Override public String[] getSupportedCipherSuites() { return this.under.getSupportedCipherSuites(); } @Override public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { return fixupSocket(this.under.createSocket(s, host, port, autoClose)); } @Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException { return fixupSocket(this.under.createSocket(host, port)); } @Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { return fixupSocket(this.under.createSocket(host, port, localHost, localPort)); } @Override public Socket createSocket(InetAddress host, int port) throws IOException { return fixupSocket(this.under.createSocket(host, port)); } @Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { return fixupSocket(this.under.createSocket(address, port, localAddress, localPort)); } }