Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unsupported record version SSLv2Hello using CloseableHttpClient

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());
        }
    }
}
like image 355
Mark Jones Avatar asked Oct 02 '14 17:10

Mark Jones


3 Answers

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

like image 155
dmatej Avatar answered Nov 10 '22 04:11

dmatej


Figured it out. The two places I tripped over my shoelaces were:

    Needed to register https with the PoolingHttpClientConnectionManager
    Set TLSv1 as the only supported protocol in the SSLConnectionSocketFactory
package httpcomponents;

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
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.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;

/**
 *
 * @author mark.jones
 */
public class HttpTest3 {

    public static void main(String[] args) {
        CloseableHttpClient closeableHttpClient = null;
        CloseableHttpResponse closeableHttpResponse = null;
        try {
            HttpHead httpHead = null;
            TrustStrategy trustStrategy = null;
            SSLContext sslContext = null;
            X509HostnameVerifier x509HostnameVerifier = null;
            LayeredConnectionSocketFactory sslConnectionSocketFactory = null;
            Registry<ConnectionSocketFactory> registry = null;
            PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = null;
            RequestConfig requestConfig = null;
            String audioURL = "https://ancientserver.com/webreports/audio.jsp?callID=338786512&authentication=98695279578B04166629C0AC0ABB49F0";

            httpHead = new HttpHead(audioURL);

            trustStrategy = new TrustStrategy() {
                @Override
                public boolean isTrusted(X509Certificate[] xcs, String authType) throws CertificateException {
                    return true;
                }
            };

            sslContext = SSLContexts
                    .custom()
                    .useSSL()
                    .loadTrustMaterial(null, trustStrategy)
                    .setSecureRandom(new SecureRandom())
                    .build();

            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;
                }
            };

            //either one works
            //LayeredConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, new String[]{"TLSv1"}, null, x509HostnameVerifier);

            registry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
                    .register("https", sslConnectionSocketFactory)
                    .build();

            poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(registry);

            requestConfig = RequestConfig
                    .custom()
                    .setConnectTimeout(5000)            //5 seconds
                    .setConnectionRequestTimeout(5000)
                    .setSocketTimeout(5000)
                    .build();

            closeableHttpClient = HttpClientBuilder
                    .create()
                    .setDefaultRequestConfig(requestConfig)
                    .setSslcontext(sslContext)
                    .setHostnameVerifier(x509HostnameVerifier)
                    .setSSLSocketFactory(sslConnectionSocketFactory)
                    .setConnectionManager(poolingHttpClientConnectionManager)
                    .build();

            if (closeableHttpClient != null) {
                closeableHttpResponse = closeableHttpClient.execute(httpHead);
                if (closeableHttpResponse != null) {
                    int statusCode = closeableHttpResponse.getStatusLine().getStatusCode();
                    System.out.println(String.valueOf(statusCode));
                    System.out.println(closeableHttpResponse.getFirstHeader("Content-Type"));
                }
            }
        } catch (NoSuchAlgorithmException noSuchAlgorithmException) {
            System.out.println(noSuchAlgorithmException.getMessage());
        } catch (KeyStoreException keyStoreException) {
            System.out.println(keyStoreException.getMessage());
        } catch (KeyManagementException keyManagementException) {
            System.out.println(keyManagementException.getMessage());
        } 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());
                }
            }
        }
    }
}
like image 42
Mark Jones Avatar answered Nov 10 '22 06:11

Mark Jones


It looks like you're connecting to a server that incredibly enough in this day and age still supports SSLv2.

Try removing SSlv2ClientHello from the list of enabled protocols, however you do that with Apache HTTPClient.

NB You haven't needed that stuff with the com.sun.net.ssl.internal.ssl.Provider since 2004, and you need to be aware that your TrustManager and HostnameVerifier are both radically insecure. Also TrustManager.getAcceptedIssuers() is not permitted to return null: see the Javadoc.

like image 1
user207421 Avatar answered Nov 10 '22 05:11

user207421