Java – Unsupported record version SSLv2Hello using CloseableHttpClient

apache-httpcomponentsjavassl

I am trying to make an https call and getting the following error:
Unsupported record version SSLv2Hello

Can anyone please shed some light on what I'm doing wrong?
Thanks for your help.

Here is the StackTrace:

    debug:
    Unsupported record version SSLv2Hello
    javax.net.ssl.SSLException: Unsupported record version SSLv2Hello
    at sun.security.ssl.InputRecord.readV3Record(Unknown Source)
    at sun.security.ssl.InputRecord.read(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    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:123)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:318)
    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:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at httpcomponents.httpsTest.main(httpsTest.java:135)
    

Here is working example:

    import com.sun.net.ssl.internal.ssl.Provider;
    import java.io.IOException;
    import java.security.KeyManagementException;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    import java.security.Security;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    import java.text.MessageFormat;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Timer;
    import java.util.TimerTask;
    import java.util.concurrent.TimeUnit;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLException;
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.SSLSocket;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;
    import org.apache.http.Header;
    import org.apache.http.HttpHeaders;
    import org.apache.http.client.config.RequestConfig;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpHead;
    import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.conn.ssl.SSLContexts;
    import org.apache.http.conn.ssl.X509HostnameVerifier;
    import org.apache.http.entity.ContentType;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClientBuilder;
    import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
    import org.apache.http.protocol.BasicHttpContext;
    import org.apache.http.protocol.HttpContext;
String audioURL = "https://mydata.com/webreports/audio.jsp?callID=338786512&authentication=98695279578B04166629C0"; RequestConfig requestConfig = null; requestConfig = RequestConfig .custom() .setConnectTimeout(5000) .setConnectionRequestTimeout(5000) .setSocketTimeout(5000) .build(); PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = null; poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(); poolingHttpClientConnectionManager.setMaxTotal(5); CloseableHttpClient closeableHttpClient = null; HttpHead httpHead = new HttpHead(audioURL); try { Provider sslProvider = new Provider(); if (Security.getProvider(sslProvider.getName()) == null) { Security.addProvider(sslProvider); } TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException { } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException { } } }; SSLContext sslContext = SSLContexts .custom() .useSSL() .build(); sslContext.init(null, trustAllCerts, new SecureRandom()); LayeredConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext); X509HostnameVerifier x509HostnameVerifier = new X509HostnameVerifier() { @Override public void verify(String host, SSLSocket ssl) throws IOException { //do nothing } @Override public void verify(String host, X509Certificate cert) throws SSLException { //do nothing //do nothing } @Override public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException { //do nothing } @Override public boolean verify(String string, SSLSession ssls) { return true; } }; closeableHttpClient = HttpClientBuilder .create() .setDefaultRequestConfig(requestConfig) .setConnectionManager(poolingHttpClientConnectionManager) .setSslcontext(sslContext) .setHostnameVerifier(x509HostnameVerifier) .setSSLSocketFactory(sslConnectionSocketFactory) .build(); } catch (NoSuchAlgorithmException noSuchAlgorithmException) { System.out.println(noSuchAlgorithmException.getMessage()); } catch (KeyManagementException keyManagementException) { System.out.println(keyManagementException.getMessage()); } HttpContext httpContext = new BasicHttpContext(); CloseableHttpResponse closeableHttpResponse = null; try { if (closeableHttpClient != null) { closeableHttpResponse = closeableHttpClient.execute(httpHead, httpContext); if (closeableHttpResponse != null) { int statusCode = closeableHttpResponse.getStatusLine().getStatusCode(); System.out.println(String.valueOf(statusCode)); } } } catch (IOException iOException) { System.out.println(iOException.getMessage()); } finally { if (closeableHttpResponse != null) { try { closeableHttpResponse.close(); } catch (IOException iOException) { System.out.println(iOException.getMessage()); } } if (closeableHttpClient != null) { try { closeableHttpClient.close(); } catch (IOException iOException) { System.out.println(iOException.getMessage()); } } }

Best Answer

It seems the problem is that JDK8 clients cannot connect to SSL2 server with the default Provider (SSLv2 is deprecated for a long time). You have to force the server to use SSL3 (or another safer protocol) or you have to use another provider (BouncyCastle?). Currently we have a similar problem with SOAP webservice JDK8 client and JDK6 server.

http://en.wikipedia.org/wiki/Transport_Layer_Security#SSL_2.0

https://www.rfc-editor.org/rfc/rfc6176