Johan
Johan

Reputation: 40500

Ignoring bad certificate on HTTPS connection when using Apache Async HttpClient 4.0.x

I'm using the Async Apache HttpClient (CloseableHttpAsyncClient) to connect to a server but I run into the following exception:

javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at org.apache.http.concurrent.BasicFuture.failed(BasicFuture.java:130)
    at org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.failed(DefaultClientExchangeHandlerImpl.java:258)
    at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.exception(HttpAsyncRequestExecutor.java:123)
    at org.apache.http.impl.nio.client.InternalIODispatch.onException(InternalIODispatch.java:68)
    at org.apache.http.impl.nio.client.InternalIODispatch.onException(InternalIODispatch.java:37)
    at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:124)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:159)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:338)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:316)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:277)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:105)
    at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:584)
    at java.lang.Thread.run(Thread.java:695)
Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at com.sun.net.ssl.internal.ssl.Handshaker.checkThrown(Handshaker.java:1015)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.checkTaskThrown(SSLEngineImpl.java:485)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.writeAppRecord(SSLEngineImpl.java:1108)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.wrap(SSLEngineImpl.java:1080)
    at javax.net.ssl.SSLEngine.wrap(SSLEngine.java:452)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.doWrap(SSLIOSession.java:220)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:254)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.isAppInputReady(SSLIOSession.java:391)
    at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:119)
    ... 7 more
Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1508)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:243)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1209)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:135)
    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
    at com.sun.net.ssl.internal.ssl.Handshaker$1.run(Handshaker.java:533)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.net.ssl.internal.ssl.Handshaker$DelegatedTask.run(Handshaker.java:952)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.doRunTask(SSLIOSession.java:238)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:276)
    ... 9 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:323)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:217)
    at sun.security.validator.Validator.validate(Validator.java:218)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:249)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1188)
    ... 16 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:318)
    ... 22 more

Since this is a test server I just want CloseableHttpAsyncClient to ignore all SSL errors. I know how to do this using the non-async version of HttpClient (this has been answered here for example) but I cannot get this to work using the async version.

I've tried the following:

TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
    public boolean isTrusted(X509Certificate[] certificate, String authType) {
        return true;
    }
};

SSLContext sslContext = null;
try {
    sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
} catch (Exception e) {
    // Handle error
}

CloseableHttpAsyncClient client = HttpAsyncClients.custom()
        .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
        .setSSLContext(sslContext).build();

but it doesn't work. Does anyone know how to solve this?

Upvotes: 1

Views: 6266

Answers (2)

Johan
Johan

Reputation: 40500

Actually the code that I provided in my question worked. The problem was that I was using Unirest (which uses Apache HttpClient under the hood) and had configured it like this:

Unirest.setAsyncHttpClient(createHttpAsyncClient(CONNECTION_TIMEOUT, SOCKET_TIMEOUT));
Unirest.setTimeouts(CONNECTION_TIMEOUT, SOCKET_TIMEOUT);

The problem was that "setTimeouts" overrode the configuration I made in createHttpAsyncClient without any indication. Changing to

Unirest.setTimeouts(CONNECTION_TIMEOUT, SOCKET_TIMEOUT);
Unirest.setAsyncHttpClient(createHttpAsyncClient(CONNECTION_TIMEOUT, SOCKET_TIMEOUT));

made everything work.

So if someone else has the same problem with plain Async Apache HTTPClient then the code to make it trust all certificates is the following:

TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
    public boolean isTrusted(X509Certificate[] certificate, String authType) {
        return true;
    }
};

SSLContext sslContext = null;
try {
    sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
} catch (Exception e) {
    // Handle error
}

CloseableHttpAsyncClient client = HttpAsyncClients.custom()
        .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
        .setSSLContext(sslContext).build();

Upvotes: 5

ok2c
ok2c

Reputation: 27528

I suspect this problem has nothing to do with hostname verification. SSL handshake likely fails much earlier, before an SSL session could be negotiated. There can be various reasons for such failure, SSL protocol version mismatch being most likely. You should run your application with SSL debug log activated (using -Djavax.net.debug=all system property) and analyze the log output

Upvotes: 0

Related Questions