Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java - How can I disable a TLS cipher for only some protocols using JVM Config?

Tags:

java

java-8

I've seen lots of examples of disabling TLS ciphers in java using jdk.tls.disabledAlgorithms, for example:

 jdk.tls.disabledAlgorithms=MD2, RSA keySize < 1024, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256

But how can I disable a cipher for only certain protocols, using jdk.tls.disabledAlgorithms or a similar config?

For example, how can I disable TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 for TLSv1.1 only?

It doesn't seem to support the opensssl way of doing this, which is like so:

TLSv1.1:!TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256

It doesnt cause any errors, but the cipher is still allowed.

EDIT: Note that I'm only really interested in JVM config based answers, as I don't control the code that's on lots of these servers, just the JVM and JVM configurations. Some are even 3rd party servers, so more of an ops level thing than anything.

EDIT 2: Note that you can run a java app and supply arguments that change which protocols and ciphers are used, e.g. java -server -Djava.security.properties=./my/custom/java.security -jar myapp.jar will do it - but it wont let you filter ciphers by protocol, only ciphers, or protocols, from what I can see. The file would contain a property entry like jdk.tls.disabledAlgorithms

like image 446
Brad Parks Avatar asked Oct 12 '18 12:10

Brad Parks


People also ask

What is JDK TLS disabledAlgorithms?

The jdk. tls. disabledAlgorithms property. JSSE code uses this security property to disable TLS protocols, cipher suites, keys, and so on. The syntax is similar to the jdk.certpath.disabledAlgorithms security property.


2 Answers

Posting my comment as an answer because why not.

Other answers, and every doc I've found online, seems to agree that what you are asking for is not possible to do within Java, not yet at least. You can enable / disable protocols globally, and you can enable / disable cipher types globally, but you cannot do one based on the other.

However, since you are on the DevOps side, maybe a non-Java solution is possible. You could run separate instances of the app, each one having only TLSv1.1, only TLSv1.2 etc. enabled, and apply the desired cipher filter to each one; and then have nginx (or whatever you use) redirect traffic to the appropriate instance depending on the detected protocol.

So, one instance at NODE1 with:

jdk.tls.client.protocols=TLSv1.1
jdk.tls.disabledAlgorithms=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256

Another instance at NODE2 with:

jdk.tls.client.protocols=TLSv1.2
jdk.tls.disabledAlgorithms=...

And some nginx rules (use return or rewrite as you see fit):

server {
    [...]
    if ( $ssl_protocol = TLSv1.1 ) {
        return 302 $scheme://NODE1.yourhost.com$request_uri;
    }
    if ( $ssl_protocol = TLSv1.2 ) {
        rewrite ^ $scheme://NODE2.yourhost.com$request_uri;
    }

I'm just a Java dev, my experience with nginx is very limited so you might need to tweak the config a bit. Just trying to help.

like image 99
walen Avatar answered Oct 01 '22 07:10

walen


JSSE docs say that the https.protocols property can store comma separated list of supported protocols in a given SSL context, however this property is used by current JSSE implementation, but could be disregarded by other vendors or future versions, so YMMV.

Programatically you can achieve it like so:

SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket();
socket.setEnabledCipherSuites(new String[] {
    CipherSuite.TLS_RSA_WITH_RC4_128_MD5.javaName,
    CipherSuite.TLS_RSA_WITH_RC4_128_SHA.javaName,
});

//allow TLS1.2 only
socket.setEnabledProtocols(new String[] {
    TlsVersion.TLS_1_2.javaName,
});
like image 44
diginoise Avatar answered Oct 01 '22 05:10

diginoise