Search code examples
javassltls1.2handshake

Enable a specific cipher suite for Java 11


We've been having trouble starting a Java application due to handshake failures. Upon inspection, we've discovered that the application can't connect to the server because the server expects a specific cipher suite (TLS_RSA_WITH_AES_256_CBC_SHA256), but the client doesn't have it in its hello message.

I would like to know if there's a way to enable the cipher suite for the client to use it in its hello. I'm not much of an expert in SSL/TLS, what would I need to understand to tackle this?

  • Java Version: 11.0.22
  • JRE Vendor: Red Hat, Inc.
  • JVM Version: 11.0.22+7-LTS

java -version:

openjdk version "11.0.22" 2024-01-16 LTS
OpenJDK Runtime Environment (Red_Hat-11.0.22.0.7-1) (build 11.0.22+7-LTS)
OpenJDK 64-Bit Server VM (Red_Hat-11.0.22.0.7-1) (build 11.0.22+7-LTS, mixed mode, sharing)

java.security jdk.tls.disabledAlgorithms entry:

jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, \
    DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \
    include jdk.disabled.namedCurves

java.security jdk.disabled.namedCurves entry:

jdk.disabled.namedCurves = secp112r1, secp112r2, secp128r1, secp128r2, \
    secp160k1, secp160r1, secp160r2, secp192k1, secp192r1, secp224k1, \
    secp224r1, secp256k1, sect113r1, sect113r2, sect131r1, sect131r2, \
    sect163k1, sect163r1, sect163r2, sect193r1, sect193r2, sect233k1, \
    sect233r1, sect239k1, sect283k1, sect283r1, sect409k1, sect409r1, \
    sect571k1, sect571r1, X9.62 c2tnb191v1, X9.62 c2tnb191v2, \
    X9.62 c2tnb191v3, X9.62 c2tnb239v1, X9.62 c2tnb239v2, X9.62 c2tnb239v3, \
    X9.62 c2tnb359v1, X9.62 c2tnb431r1, X9.62 prime192v2, X9.62 prime192v3, \
    X9.62 prime239v1, X9.62 prime239v2, X9.62 prime239v3, brainpoolP256r1, \
    brainpoolP320r1, brainpoolP384r1, brainpoolP512r1

java.security crypto.policy entry:

crypto.policy=unlimited

I've made a standalone Java class that prints all the supported ciphers and protocols (client-side):

try {
    SSLContext sslContext = SSLContext.getDefault();
    SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

    System.out.println("Supported Ciphers:");
    for (String cipher: sslSocketFactory.getSupportedCipherSuites()) {
        System.out.println(cipher);
    }

    System.out.println("\nSupported Protocols:");
    for (String protocol: sslContext.getSupportedSSLParameters().getProtocols()) {
        System.out.println(protocol);
    }
} catch (Exception e) {
    e.printStackTrace();
}

This is the output:

Supported cipher suites:
TLS_AES_256_GCM_SHA384
TLS_AES_128_GCM_SHA256
TLS_CHACHA20_POLY1305_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_EMPTY_RENEGOTIATION_INFO_SCSV
TLS_RSA_WITH_NULL_SHA256
TLS_ECDHE_ECDSA_WITH_NULL_SHA
TLS_ECDHE_RSA_WITH_NULL_SHA
SSL_RSA_WITH_NULL_SHA

Supported protocols:
TLSv1.3
TLSv1.2
TLSv1.1
TLSv1
SSLv3
SSLv2Hello

As you can see, there's no mention of "TLS_RSA_WITH_AES_256_CBC_SHA256". How could I enable that specific cipher suite? A few days ago, I don't know how, but the cipher suite appeared on the list, I really don't know what we did, so, I know its possible. Now it doesn't appear because we changed the Java installation (but anyways, both were Java 11).


Solution

  • So, I solved the issue, and yes, it had to do with the Java Distribution I was using.

    I was using Red Hat Inc.'s Java Distribution, installed via Red Hat's repositories with yum, but, apparently, RH's Java doesn't support the cipher suite I was looking for. @g00se's comment kinda helped me there when they mentioned 'licensing'. So, based on the comments I got on my question, I went and downloaded an .rpm for Java, but this time Oracle's.

    With that, I installed it on my RHEL server:

    rpm -ivh jdk-11.0.21_linux-x64_bin.rpm
    

    And then ran my class to check if any new cipher suites were added, and sure enough, there it was, 'TLS_RSA_WITH_AES_256_CBC_SHA256'.

    From there, I just specified in my service file (the one that runs the application that was having the handshake failure) to use the Oracle's Java, like this:

    ExecStart=/usr/lib/jvm/jdk-11-oracle-x64/bin/java ...other options... -jar "application.war"
    

    And everything worked fine, no more errors!

    Thanks for all your comments, they really helped me out :)