How to configure JDK 1.6 to make ssl handshake to

2019-07-22 17:22发布

问题:

I'm seeing handshake_failure with client running on JDK 1.6. How can I configure the JDK 1.6 to allow the client to connect?

I suspect the problem is either with SSLv2 client hello or an unsupported cipher but not 100% sure which.

Client debug output:

Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
Client, setSoTimeout(61000) called
%% No cached client session
*** ClientHello, TLSv1
Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
***
Client, WRITE: TLSv1 Handshake, length = 75
Client, WRITE: SSLv2 client hello message, length = 101
Client, received EOFException: error
Client, handling exception: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
Client
, SEND TLSv1 ALERT:  
fatal, 
description = handshake_failure

I understand another approach (not ideal) is to allow SSLv2Hello pseudo protocol on the remote server. I'd hang my head in shame & ask the provider to allow SSLv2Hello but I'm not sure even that would allow the connection to succeed based on the available ciphers.

回答1:

SSLv2 and SSLv3 are deprecated protocols due to security issues (CVE-2014-3566 or Poodle, etc...) so is not a good idea force the server to accept it.

Nor is it necessary to upgrade the client's JVM up to 6 (as long as the server accepts TLSv1), you just have to disable the above protocols creating a custom socket factory (extending the default SSLSocketFactory), then remove it and set the enabled protocols when you create the socket

private Socket removeSSLv2v3(Socket socket) {

    if (!(socket instanceof SSLSocket)) {
        return socket;
    }

    SSLSocket sslSocket = (SSLSocket) socket;

    String[] protocols = sslSocket.getEnabledProtocols();
    Set<String> set = new HashSet<String>();
    for (String s : protocols) {
        if (s.equals("SSLv3") || s.equals("SSLv2Hello")) {
            continue;
        }
        set.add(s);
    }
    sslSocket.setEnabledProtocols(set.toArray(new String[0]));

    return sslSocket;
}

An example using Apache HttpComponents 4.4.1 (accepting Java 6 secure protocols only)

SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
sslContextBuilder.loadTrustMaterial(null, new TrustSelfSignedStrategy());

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContextBuilder.build(), new String[] { "TLSv1" }, null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());

CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

Or you can set the enabled protocols via properties in command line while executing your client (for Java 6, it accepts TLSv1 only)

java -Dhttps.protocols="TLSv1" <MyClient>

or

java -Dhttps.protocols=TLSv1 <MyClient>


标签: java ssl