Remote host closed connection during handshake java 8

Not an answer yet, but too much for a comment. This is clearly not a server cert problem; the symptoms of that are quite different. From your system's POV, the server appears to be closing during the handshake. There are two possibilities:

The server really is closing, which is a SSL/TLS protocol violation though a fairly minor one; there are quite a few reasons a server might fail to handshake with you but it should send a fatal alert first, which your JSSE or the weblogic equivalent should indicate. In this case there may well be some useful information in the server log, if you are able (and permitted) to communicate with knowledgeable server admin(s). Or you can try putting a network monitor on your client machine, or one close enough it sees all your traffic; personally I like www.wireshark.org. But this usually shows only that the close came immediately after the ClientHello, which doesn't narrow it down much. You don't say if you are supposed to and have configured a "client cert" (actually key&cert, in the form of a Java privateKeyEntry) for this server; if that is required by the server and not correct, some servers may perceive that as an attack and knowingly violate protocol by closing even though officially they should send an alert.

Or, some middlebox in the network, most often a firewall or purportedly-transparent proxy, is deciding it doesn't like your connection and forcing a close. The Proxy you use is an obvious suspect; when you say the "same code" works to other hosts, confirm if you mean through the same proxy (not just a proxy) and using HTTPS (not clear HTTP). If that isn't so, try testing to other hosts with HTTPS through the proxy (you needn't send a full SOAP request, just a GET / if enough). If you can, try connecting without the proxy, or possibly a different proxy, and connecting HTTP (not S) through the proxy to the host (if both support clear) and see if those work.

If you don't mind publishing the actual host (but definitely not any authentication credentials) others can try it. Or you can go to www.ssllabs.com and request they test the server (without publishing the results); this will try several common variations on SSL/TLS connection and report any errors it sees, as well as any security weaknesses.

SSLHandshakeException appear in logs when there is some error occur while validating the certificate installed in client machine with certificate on server machine. In this post, we will learn about fixing this if you are using Apache HttpClient library to create HttpClient to connect to SSL/TLS secured URLs.

The exception logs will look like this.

Caused by: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:980)
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1391)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1375)
	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:275)
	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:254)
	at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:117)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:314)
	at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363)
	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219)
	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195)
	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86)
	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:57)
	at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:88)
	at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:46)
	at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:49)
	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:509)
	... 61 more
Caused by: java.io.EOFException: SSL peer shut down incorrectly
	at sun.security.ssl.InputRecord.read(InputRecord.java:505)
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:961)
	... 80 more

I have already posted code fix to bypass SSL matching in earlier post.

Unfortunately, that fix works in TLS and TLS 1.1 protocols. It doesn’t work in TLS 1.2 protocol. So ultimately, you need to fix the certificate issue anyway. There is ‘no code only’ fix for this.

Now there are two ways, you can utilize the imported certificate from server. Either add certificate to the JDK cacerts store; or pass certificate information in JVM aruguments.

1) Import certificate to JDK cacert store

  1. Import the certificate from server.
  2. Use given command to add the certificate to JDK store. (Remove new line characters).
    keytool -import 
    	-noprompt 
    	-trustcacerts 
    	-alias MAVEN-ROOT 
    	-file C:/Users/Lokesh/keys/cert/maven.cer 
    	-keystore "C:/Program Files (x86)/Java/jdk8/jre/lib/security/cacerts" 
    	-storepass changeit
    

Now create HTTP client as given:

public HttpClient createTlsV2HttpClient() throws KeyManagementException, 
				UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {

      SSLContext sslContext = SSLContext.getInstance("TLSv1.2");

      SSLConnectionSocketFactory f = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1.2" }, null,
                   						SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

      Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                   		.register("http", PlainConnectionSocketFactory.getSocketFactory())
                   		.register("https", f)
                   		.build();

      PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);

      CloseableHttpClient client = HttpClients
      					.custom()
      					.setSSLSocketFactory(f)
                   		.setConnectionManager(cm)
                   		.build();
      return client;
}

Notice the code : SSLContext.getInstance("TLSv1.2"). This code picks up the certificates added to JDK cacert store. So make a note of it.

2) Pass certificate information in JVM aruguments

  1. Import the certicate from server.
  2. Add JVM arguments while starting the server. Change the parameter values as per your application.
    -Djavax.net.ssl.keyStore="C:/Users/Lokesh\keys\maven.jks" 
    -Djavax.net.ssl.keyStorePassword="test" 
    -Djavax.net.ssl.trustStore="C:/Users/Lokesh\keys\maven.jks" 
    -Djavax.net.ssl.trustStorePassword="test" 
    

Now create HTTP client as given:

public HttpClient createTlsV2HttpClient() throws KeyManagementException, 
				UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {

      SSLContext sslContext = SSLContexts.createSystemDefault();

      SSLConnectionSocketFactory f = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1.2" }, null,
                   						SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

      Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                   		.register("http", PlainConnectionSocketFactory.getSocketFactory())
                   		.register("https", f)
                   		.build();

      PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);

      CloseableHttpClient client = HttpClients
      					.custom()
      					.setSSLSocketFactory(f)
                   		.setConnectionManager(cm)
                   		.build();
      return client;
}

Notice the code : SSLContext.createSystemDefault(). This code picks up the certificates passed as JVM arguments. Again, make a note of it.

Summary

  1. Use SSLContext.getInstance("TLSv1.2") when certificate is added to JDK cacert store.
  2. Use SSLContext.createSystemDefault() when SSL info is passed as JVM argument.

Drop me your questions in comments section.

Happy Learning !!

What is remote host closed connection during handshake?

[SOLVED] TLS 1.2 – SSLHandshakeException: Remote host closed connection during handshake. SSLHandshakeException appear in logs when there is some error occur while validating the certificate installed in client machine with certificate on server machine.

How do I fix the SSL handshake exception in Java?

How to Fix SSL Handshake Failed.
Correct the time and date on the client device..
Try another browser..
Add website to allowlist..
Update browser to use the latest SSL protocol..
Check browser and server support for Cipher Suites..
Verify your SSL certificate is accurate and valid..

Why do we get SSL handshake exception?

The SSL Handshake Error occurs if the read access has not been granted to the OS, thus preventing the web server from completing authentication. It indicates that the browser's connection to the web server isn't secure.