1

I'm running into a bit of a pickle with a call to a third-party API from a java application. The external API requires at least one of the following ciphers:

TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256

I followed the instructions here: https://confluence.atlassian.com/stashkb/list-ciphers-used-by-jvm-679609085.html to try to upgrade the available ciphers on my application server. After the upgrade however I still don't see any of the compatible ciphers listed.

I suspect the problem is that my server is running jdk 1.7 . This is a legacy application so unfortunately I'm not able to upgrade to a newer jdk. Is there any way to add those ciphers to my existing java installation?

Update: I figured out how to add additional ciphers but it doesn't seem to have helped. In my socket factory I added some code like this:

private Socket acceptOnlyTLS12(Socket socket) {
        if (!(socket instanceof SSLSocket))
            return socket;
        SSLSocket sslSocket = (SSLSocket) socket;
        sslSocket.setEnabledProtocols(new String[] { "TLSv1.2" });
        List<String> ciphers = new ArrayList<String>(Arrays.asList(sslSocket.getEnabledCipherSuites()));
        ciphers.add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256");
        sslSocket.setEnabledCipherSuites(ciphers.toArray(new String[] {}));
        return sslSocket;
    }

Is there another step I'm missing somewhere? Is some way to obtain additional information about why the ssl handshake is failing?

5
  • Migrating from Java 7 to 8 wasn't a big deal as far as I remember. Have you tried to make it run on Java 8? Beside that you can still use the external proxy termination method, use a modern web server like nginx on the same machine that terminates the TLS connection and forwards the now unencrypted connection to the actual Java server.
    – Robert
    Oct 28, 2021 at 19:37
  • @Robert Unfortunately I have. The application is running on Jboss4 which doesn't play nicely with newer versions of the jdk.
    – pbuchheit
    Oct 28, 2021 at 19:40
  • Then you have to take the external TLS termination server option.
    – Robert
    Oct 28, 2021 at 21:01
  • @Robert can you elaborate a bit on that? What is an external TLS termination server?
    – pbuchheit
    Oct 29, 2021 at 13:22

2 Answers 2

1

(1) That webpage is dated 2014; unlimited policy is no longer used at all for Oracle Java versions after 2017, and before that (which e.g. 7u80 was) it only mattered for symmetric encryption over 128 bits which here would affect only the AES256 suites not the AES128 ones. (It was never applicable to OpenJDK, although OpenJDK below 8 was/is mostly available only on major Linux distros like RedHat and Debian that could allocate staff for building and packaging; you don't say which you are using.)

(2) Java (1.)7 does support the CBC ciphersuites you show (not the GCM ones, and for Oracle versions below 7u171 the AES256 ones do require unlimited policy) but ONLY when TLS1.2 is used (these ciphersuites did not exist in lower version protocols) and by default j7 disables TLS1.2 (and 1.1) clientside.

If you are explicitly doing the connection to this API with HttpsURLConnection (e.g. new URL("https://something").openConnection()) you can tweak the socketfactory to use SSLContext.getInstance("TLSv1.2") and/or explicitly setEnabledProtocols on the socket. If you are using other middleware e.g. Apache HttpComponents there are usually similar methods but they vary in detail; you would need to show us the code, and that would probably belong on StackOverflow not here. If you are calling a library that does the connection internally, it may have options, or not. For all or many calling methods, you can alter defaults like SSLContext.setDefault() or HttpsURLConnection.setDefaultSSLSocketFacfory() if these defaults are not overridden in the relevant code and making a global change like that doesn't cause trouble for anything else running in your same JVM.

Alternatively (and more on topic!) if you have a sufficiently recent j7 update, I'm pretty sure they backported the system property jdk.tls.client.protocols which you could set to e.g. TLSv1,TLSv1.1,TLSv1.2 to change the default with no code change (but again only if not overridden and not harming anything else). I don't recall exactly when this was but definitely after 7u80, so you would have it only with paid Oracle support or OpenJDK supported by somebody else with or without pay. That's easy to try and may work.

1
  • @ dave_thompson_085 I was able to install a newer version of jdk7 and added the unlimited strength JCE jars. Some of the required ciphers are at least available now, but they are not enabled. Any idea how to configure which ciphers are enabled by the jdk?
    – pbuchheit
    Oct 29, 2021 at 15:15
0

I finally found a workaround, if a bit ugly. I created a groovy script that makes a cURL request to the external API. Since cURL can use the latest certificates, I can get around the limitations imposed by being stuck with an old JDK. It's kludgy but it works.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .