Search code examples
javasslhttpclientapache-httpclient-4.xapache-commons-httpclient

Ignore self-signed certificates in Apache HTTPClient 4.5


I am trying to accept all certificates, and/or accept self-signed certificates using Apache HTTPClient version 4.5 (tutorial link here)

I've been going through solutions to this problem from a bunch of posts on SO. So far none of them have worked.

I keep getting this error: Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

Apache Docs:

Related StackOverflow Questions - Here's some links of the solutions I've tried:

Note that in all these examples I am also passing a cookie store and a proxy credentials provider that I defined earlier. These are working, I'm just trying to add SSL support.

Try #1

Create my own ssl context with SSLContextBuilder and trust all self signed strategies with TrustSelfSignedStrategy.

SSLContextBuilder sshbuilder = new SSLContextBuilder();
sshbuilder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sshbuilder.build());

CloseableHttpClient httpclient = HttpClients.custom()
    .setDefaultCredentialsProvider(credsProvider)
    .setDefaultCookieStore(cookieStore)
    .setSSLSocketFactory(sslsf)
    .build();

RESULT: Didn't work. Got Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

Try #2

Same as above, but add a PoolingHttpClientConnectionManager

SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(),SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
        .register("http", new PlainConnectionSocketFactory())
        .register("https", sslsf)
        .build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
cm.setMaxTotal(2000);//max connection

CloseableHttpClient httpclient = HttpClients.custom()
    .setDefaultCredentialsProvider(credsProvider)
    .setDefaultCookieStore(cookieStore)
    .setSSLSocketFactory(sslsf)
    .setConnectionManager(cm)
    .build();

RESULT: Didn't work. Got Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

Try #3

Simply accept ALL certificates by overriding the TrustStrategy (this is not recommended)

SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustStrategy() {
    @Override
    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        return true;
    }
});
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(),
    SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

CloseableHttpClient httpclient = HttpClients.custom()
    .setDefaultCredentialsProvider(credsProvider)
    .setDefaultCookieStore(cookieStore)
    .setSSLSocketFactory(sslsf)
    .build();

RESULT: Didn't work. Got Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

Try #4

I found something useful from this answer:

As of version 4.5 HttpClient disables SSLv3 protocol version by default

Here's the solution he gave:

SSLContext sslcontext = SSLContexts.createSystemDefault();
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
        sslcontext, new String[] { "TLSv1", "SSLv3" }, null,
        SSLConnectionSocketFactory.getDefaultHostnameVerifier());

Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
        .register("http", PlainConnectionSocketFactory.INSTANCE)
        .register("https", sslConnectionSocketFactory)
        .build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);

httpclient = HttpClients.custom()
    .setDefaultCredentialsProvider(credsProvider)
    .setDefaultCookieStore(cookieStore)
    .setSSLSocketFactory(sslConnectionSocketFactory)
    .setConnectionManager(cm)
    .build();

RESULT: Didn't work. Got Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake


Solution

  • One of the above approaches should work in case of self-signed certificates, but the weird thing is you are getting same exception in all the approaches.

    I feel during SSL session establishment or handshaking protocol is not being accepted either by client or by server.

    The best solution here is to debug the application.

    In case of tomcat, add -Djavax.net.debug=all in setenv.sh or setenv.bat files and then restart the server.

    Or you can follow this tutorial.

    The OP just needed to change the port when connecting to SSL:

    //For HTTPS
    HttpHost httpstarget = new HttpHost("mysite.com", 443, "https");
    
    //For HTTP
    HttpHost httptarget = new HttpHost("mysite.com", 80, "http");