-1

The problem

So, I have a server I need to connect to that is using an old, deprecated certificate. If I try to connect to it with Apache HttpClient, I get SSLException: Received fatal alert: close_notify. The client itself does not need to be reusable for other servers, but the builder code must be able to.

My less-than-ideal workaround

I have worked around this by setting a fallback TLS protocol, but it isn't ideal because it adds another request. There must be a more elegant way than this:

URL url = new URL("https://...");
SSLContextBuilder sslContextBuilder = SSLContexts.custom();
try {
    url.openConnection().connect();
} catch (SSLException e) {
    sslContextBuilder.useProtocol("TLSv1");
}

I have also tried

I have also tried creating a custom SSLConnectionSocketFactory, but apache ignores TLSv1 if TLSv1.2 is included as an option.

SSLConnectionSocketFactory sf = new SSLConnectionSocketFactory(
        SSLContext.getDefault(),
        new String[] { "TLSv1.2", "TLSv1" },
        null,
        SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

Reflection

In essence, I suppose that the base problem is that the remote server uses a deprecated cipher suite. I could pass in all the cipher suites I want to support into the SSLConnectionSocketFactory, but there are a lot, and Sun has hidden away the full listing behind private classes.

zalpha314
  • 1,444
  • 4
  • 19
  • 34
  • Can you list that server? e.g. https://ex.qq.com/ . And you can try it with ssllabs.com to see which SSL versions and cipher suites it supports. – auntyellow Jun 17 '16 at 16:22
  • Make up your mind. Is it a deprecated certificate or a deprecated cipher suite? – user207421 Jun 19 '16 at 10:10

1 Answers1

2

You can use a deprecated cipher suite (such as SSL_RSA_WITH_RC4_128_SHA) by removing jdk.tls.disabledAlgorithms in $JAVA_HOME/jre/lib/security/java.security.

e.g. the https://ex.qq.com/ accessed by a default HttpClient will return Received fatal alert: handshake_failure. But the following code can work:

public static void main(String[] args) throws Exception {
    HttpClientBuilder builder = HttpClientBuilder.create().
            setSSLSocketFactory(new SSLConnectionSocketFactory(SSLContext.getDefault(),
            new String[] {"TLSv1"}, new String[] {"SSL_RSA_WITH_RC4_128_SHA"}, new DefaultHostnameVerifier()));
    try (CloseableHttpClient client = builder.build()) {
        HttpGet get = new HttpGet("https://ex.qq.com/");
        System.out.println(client.execute(get).getStatusLine().getStatusCode());
    }
}

See this question for more detail: Received fatal alert: handshake_failure through SSLHandshakeException

Community
  • 1
  • 1
auntyellow
  • 2,423
  • 2
  • 20
  • 47
  • I'm afraid that modifying the JDK installation would not be a good solution for my case. This app runs on a containerized service, so modifying the JDK would be frowned upon, if not impossible. As for your other suggestion, wouldn't that only work with that single protocol and cipher? It doesn't look like it would properly handle other protocols. – zalpha314 Jun 17 '16 at 18:14