BetterCloud / vault-java-driver

Zero-dependency Java client for HashiCorp's Vault
https://bettercloud.github.io/vault-java-driver/
336 stars 223 forks source link

DISABLED_SSL_CONTEXT does not send server name for SNI #71

Open stipx opened 7 years ago

stipx commented 7 years ago

Hi, The used SSL context does not send the SNIServerNames SSLProperty when SSL verification is disabled. So when Vault is running e.g. in OpenShift it does not work because it does not know where to route the requests.

Basically the SSLSocketFactory needs to set the right server name to the created SSLSocket. There is also the way to do this on our own by setting a custom SSLContext in the SSLConfig, but then the HostnameVerifier is not set to the one which just allows everything and it still fails.

I had to do a dirty hack to get it working and it will also only work for one vault connection in the whole JVM:

        final SSLContext sslContext = SSLContext.getInstance("TLS");
        SSLContextSpi spi = new SSLContextSpi() {

            @Override
            protected void engineInit(final KeyManager[] km, final TrustManager[] tm, final SecureRandom sr) throws KeyManagementException {
                sslContext.init(km, tm, sr);
            }

            @Override
            protected SSLSocketFactory engineGetSocketFactory() {
                SSLParameters params = new SSLParameters();
                params.setServerNames(Arrays.asList(new SNIHostName("my-vault-connector.foobar.com")));
                return new SSLSocketFactoryWrapper(sslContext.getSocketFactory(), params);
            }

            @Override
            protected SSLServerSocketFactory engineGetServerSocketFactory() {
                return sslContext.getServerSocketFactory();
            }

            @Override
            protected SSLSessionContext engineGetServerSessionContext() {
                return sslContext.getServerSessionContext();
            }

            @Override
            protected SSLSessionContext engineGetClientSessionContext() {
                return sslContext.getClientSessionContext();
            }

            @Override
            protected SSLEngine engineCreateSSLEngine(final String host, final int port) {
                return sslContext.createSSLEngine(host, port);
            }

            @Override
            protected SSLEngine engineCreateSSLEngine() {
                return sslContext.createSSLEngine();
            }
        };

        sslContext.init(null, new TrustManager[] { new X509TrustManager() {
            @Override
            public void checkClientTrusted(final X509Certificate[] x509Certificates, final String s)
                    throws CertificateException {
            }

            @Override
            public void checkServerTrusted(final X509Certificate[] x509Certificates, final String s)
                    throws CertificateException {
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        } }, new java.security.SecureRandom());

        class SSLContextWrapper extends SSLContext {
            public SSLContextWrapper(final SSLContextSpi spi, final java.security.Provider provider, final String protocol) {
                super(spi, provider, protocol);
            }
        }

        Field field = Rest.class.getDeclaredField("DISABLED_SSL_CONTEXT");
        field.setAccessible(true);
        field.set(null, new SSLContextWrapper(spi, sslContext.getProvider(), sslContext.getProtocol()));

        vault = new Vault(new VaultConfig()
                .address(address)
                .token(token)
                .sslConfig(new SslConfig().verify(false).build())
                .build());
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class SSLSocketFactoryWrapper extends SSLSocketFactory {

    private final SSLSocketFactory wrappedFactory;
    private final SSLParameters sslParameters;

    public SSLSocketFactoryWrapper(final SSLSocketFactory factory, final SSLParameters sslParameters) {
        this.wrappedFactory = factory;
        this.sslParameters = sslParameters;
    }

    @Override
    public Socket createSocket(final String host, final int port) throws IOException, UnknownHostException {
        SSLSocket socket = (SSLSocket) wrappedFactory.createSocket(host, port);
        socket.setSSLParameters(sslParameters);
        return socket;
    }

    @Override
    public Socket createSocket(final String host, final int port, final InetAddress localHost, final int localPort)
            throws IOException, UnknownHostException {
        SSLSocket socket = (SSLSocket) wrappedFactory.createSocket(host, port, localHost, localPort);
        socket.setSSLParameters(sslParameters);
        return socket;
    }

    @Override
    public Socket createSocket(final InetAddress host, final int port) throws IOException {
        SSLSocket socket = (SSLSocket) wrappedFactory.createSocket(host, port);
        socket.setSSLParameters(sslParameters);
        return socket;
    }

    @Override
    public Socket createSocket(final InetAddress address, final int port, final InetAddress localAddress,
            final int localPort) throws IOException {
        SSLSocket socket = (SSLSocket) wrappedFactory.createSocket(address, port, localAddress, localPort);
        socket.setSSLParameters(sslParameters);
        return socket;

    }

    @Override
    public Socket createSocket() throws IOException {
        SSLSocket socket = (SSLSocket) wrappedFactory.createSocket();
        socket.setSSLParameters(sslParameters);
        return socket;
    }

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

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

    @Override
    public Socket createSocket(final Socket s, final String host, final int port, final boolean autoClose)
            throws IOException {
        SSLSocket socket = (SSLSocket) wrappedFactory.createSocket(s, host, port, autoClose);
        socket.setSSLParameters(sslParameters);
        return socket;
    }

}