Monday, April 13, 2015

Java 7 and TLSv1.2 - supported, but not enabled by default

Lately, I had to investigate how to make a Java 7 client connect to a server resource (in my case a JMS broker server) using sockets or http traffic over secure TLS v1.2 protocol (and only TLS v1.2... all other communication protocols should be refused). This would all have been a breeze if my client app was on Java 8...but being on Java 7, it was a completely different story.

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!

18 comments:

  1. Hi Fabien,

    The article was really helpful and I appreciate your efforts to present your research outcomes.

    Among the three solutions you provided, 3rd one (Upgrading to JAVA 8) is absolutely working fine. But my application cannot be upgraded to Java 8 now.

    Solution one is not working for me. My standalone.xml file does not have a HTTPS protocol connector. I added the properties you gave as JAVA VM arguments but still it is picking TLSv1. I am using JBOSS EAP 6 server, can you please give me more information, if I am missing anything.

    If you have any example code for Solution-2 please provide.

    Thanks,
    Kumar

    ReplyDelete
  2. Paypal has upgraded SSL certificates on their sandbox API endpoints to use "sha256" algorithm instead of sha1 (https://www.paypal-knowledge.com/infocenter/index?page=content&widgetview=true&id=FAQ1766&viewlocale=en_US&direct=en)

    The client certificate uses "sha256withrsa".I used this new certificates to connect to their sandbox endpoints and encountered handshake errors. Paypal also uses tlsv1.2

    Getting error "Unsupported SignatureAndHashAlgorithm in ServerKeyExchange Message"
    I tried the above things u mentioned but no success. Do you have any pointers on this?

    Thanks,
    Girish

    ReplyDelete
  3. Your stated https.cipherSuites VM argument very help me and solve my unsupported ciphers problem. Very thanks!

    ReplyDelete
  4. I am trying to hit my service from mule client with TLSv1.2 protocol.
    I tried system properties mentioned above to enable this protocol.

    But when I hit my service - getting below exception.




    soap:Server
    These policy alternatives can not be satisfied:
    {http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702}TransportBinding: TLS is not enabled
    {http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702}HttpsToken
    {http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702}TransportToken


    ReplyDelete
  5. This comment has been removed by the author.

    ReplyDelete
  6. For the option #2:

    try {
    SSLContext ctx = SSLContext.getInstance("TLSv1.2");
    ctx.init(null, null, null);
    SSLContext.setDefault(ctx);

    } catch (Exception e) {
    System.out.println(e.getMessage());
    }

    ReplyDelete
  7. yes you're correct that's option #2...I should indeed have posted the full code for that...thanks for the comment.

    ReplyDelete
  8. Thanks. Solution #2 greatly helped.

    ReplyDelete
  9. Thanks author Solution#2 helped me a lot

    ReplyDelete
  10. Thanks a lot was struggling for a solution ad finally point 2 worked out !!!

    ReplyDelete
  11. Solution #2 really works great!

    ReplyDelete
  12. Hi,
    I'm not getting what is application start up code. I'm also facing the same issue. Do I need to add those codes in my SQL server connection script.

    Please help me.

    ReplyDelete
    Replies
    1. Our web service is connecting to SQL server which upgraded with tls1.2. now we are facing issue with the connection.

      Could someone guide me on how to resolve this issue?

      We are running the application on java7. If I need to add the solution2 script. Please help me with the exact place to add it.

      Delete
  13. Thankful for Kirill Yunussov July 21, 2016 at 12:53 PM for the working solution....

    For the option #2:

    try {
    SSLContext ctx = SSLContext.getInstance("TLSv1.2");
    ctx.init(null, null, null);
    SSLContext.setDefault(ctx);

    } catch (Exception e) {
    System.out.println(e.getMessage());
    }

    ReplyDelete

  14. I was scrolling the internet like every day, there I found this article which is related to my interest. The way you covered the knowledge about the subject and the Bungalows in chunabhatti bhopal was worth to read, it undoubtedly cleared my vision and thoughts towards B Commercial Shops on ayodhya bypass road. Your writing skills and the way you portrayed the examples are very impressive. The knowledge about flats in chunabhatti bhopal is well covered. Thank you for putting this highly informative article on the internet which is clearing the vision about top builders in Bhopal and who are making an impact in the real estate sector by building such amazing townships.

    ReplyDelete
  15. Everyone wants to invest in the stock market buy they are confused which is the best trading platform in india, so here is a list of top 10 best trading platform that with there reviews and ratings

    ReplyDelete
  16. there are several mutual funds demat account schemes, you can select the best mutual fund demat account to invest for long term.

    ReplyDelete