At first, I thought it'd be easy since my JMS broker server (Terracotta Universal Messaging in this case) already supports TLS v1.2, lets you enforce it through system property (-DSSLProtocols), and also lets you pick which cipher(s) to use. So I thought all I needed was to set that system property on the server side and disable in the UI (called Enterprise Manager) all ciphers for this communication interface BUT the TLS v1.2 ciphers I wanted to use (the "SHA256" cipher suites in this case -- check full list of available ciphers for TLS v1.2 at https://www.openssl.org/docs/apps/ciphers.html)...as shown below in screenshot:
And everything would work fine, right? The client would start the secure handshake with the server, figure out that TLSv1.2 is the only protocol that can be used, and use the right secure protocol version and ciphers as defined by the server.
Well, this theoretical scenario is partially true: Everything is setup properly on the server side, as it rightly says "I only accept TLSv1.2 sessions with the following ciphers". But unfortunately, the Java 7 client does not seem to be able to start a TLSv1.2 secure connection by default (if you're on Java 8, stop reading right now -- unless you're curious of course -- as it would all work fine out of the box)
And yes, after quick research, Java 7 introduced support for TLS v1.2 (refer to http://docs.oracle.com/javase/7/docs/technotes/guides/security/enhancements-7.html) BUT does not enable it by default. In other words, your client app must explicitly specify "TLS v1.2" at SSLContext creation, or otherwise will just not be able to use it.
This is a pretty important nuance that you can test yourself very easily with the following 2 test cases:
1) Output for Gist - Java 7 + SSLContext context = SSLContext.getDefault()
Supported Protocols: 5 SSLv2Hello SSLv3 TLSv1 TLSv1.1 TLSv1.2 Enabled Protocols: 1 TLSv1 Enabled Ciphers: 80 ... list of available ciphers omitted here ...
2) Output for Gist - Java 7 + SSLContext context = SSLContext.getInstance("TLSv1.2")
Supported Protocols: 5 SSLv2Hello SSLv3 TLSv1 TLSv1.1 TLSv1.2 Enabled Protocols: 3 TLSv1 TLSv1.1 TLSv1.2 Enabled Ciphers: 80 ... list of available ciphers omitted here ...
So this is great! All you and I need is to update the client app's code to specify TLSv1.2 at SSL Context creation!
But wait...what if I'm using a client library to perform all that low level SSLContext connection etc...in that case, it's going to be tricky to update the code, unless specifying the SSL protocol versions and ciphers are exposed to client app in some way (eg. system properties).
If you reach this situation, here are 3 solutions I found (well, I found 1 and 3...solution 2 is credited to a smarter developer :) )
1) If all you want is to create a HTTPS connection (over TLSv1.2) from your client app to the server, you're in luck: all you need is add the following 2 system properties to your client app and the SSL context will be created properly as specified:
- https.protocols ==> -Dhttps.protocols=TLSv1.2 (comma-separated list of you want to use several protocols)
- https.cipherSuites ==> -Dhttps.cipherSuites=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (comma-separated list of you want to use several ciphers)
2) If you want to use the secure socket protocol (as opposed to HTTPs traffic), the above properties won't work unfortunately...but you could create a "TLSv1.2" SSLContext at application startup and use the "SSLContext.setDefault(ctx)" call to register that new context as the default one.
3) Upgrade your client to JAVA 8, which enables TLSv1.2 protocol by default (at this time, JAVA 8 should be already used anyway, or on most project roadmaps hopefully)
That's it! Another fun investigative work day at the office!
3) Upgrade your client to JAVA 8, which enables TLSv1.2 protocol by default (at this time, JAVA 8 should be already used anyway, or on most project roadmaps hopefully)
That's it! Another fun investigative work day at the office!