Java’s SSLContext protocol name is a footgun – Neil Madden
Java’s SSLContext protocol name is a footgun
This should be old news, but I keep seeing the same mistake crop up, so I thought I’d blog about it and spread awareness. In Java, if you want to configure TLS you generally start with an SSLContext. And you get an instance of this class by calling the static method SSLContext.getInstance("TLSv1.3"), specifying the version of the protocol you want to support. But typically a TLS connection supports other versions of the protocol, so what exactly does specifying “TLSv1.3” here mean? Probably not what you think it means…
The Java Security Standard Algorithm Names document doesn’t say much useful: “Supports […] TLS version 1.3; may support other SSL/TLS versions.” Well, which other versions? Later ones or earlier ones? That seems kind of important. It’s even vaguer if you don’t specify a version – the generic “TLS” identifier is specified as (my emphasis):
Supports some version of TLS; may support other SSL/TLS versions.
Useful.
OK, but what about the JSSE chapter in the Java Security Developer’s Guide. That seems at first glance to be more precise:
Like other JCA provider-based engine classes, SSLContext objects are created using the getInstance() factory methods of the SSLContext class. These static methods each return an instance that implements at least the requested secure socket protocol. The returned instance may implement other protocols, too. For example, getInstance("TLSv1") may return an instance that implements TLSv1, TLSv1.1, and TLSv1.2.
OK, that sounds promising! So, if I specify a version then that is taken as a minimum version and I may also get more recent versions? Great, sign me up!
Except, that is the exact fucking opposite of what the default SunJSSE provider does! When you specify “TLSv1.1” (for example), what the default provider does is treat that as a maximum TLS version . So the resulting SSLContext supports all versions of TLS up to (and including) 1.1, but nothing later. So if you have old code that requests version 1.1 and you try to connect to a modern server that only supports 1.2 and 1.3, then you’ll get a connection failure. And in modern Java, this will fail earlier because TLS 1.1 is disabled by default. If you specify “TLSv1.2” then you’ll just silently get a downgraded protocol for no good reason at all, when you probably thought you were being good and specifying a sensible minimum version.
It’s not just the default provider that does this, lots of others have followed the lead, including e.g., the Conscrypt/BoringSSL provider used by Android.
I suspect this behaviour exists because of a fear of breaking poorly-written software that baulks at unknown versions and doesn’t handle downgrades properly. But the problem is that many developers think it is best practice to specify a version when creating an SSLContext, and some security scanners even tell you to do so. In the best case, you then get code that is secure until the next major hole is discovered in TLS and v1.4 gets released. In the worst case you’ve silently implemented a self-inflicted protocol downgrade attack. I wonder how many Java apps were (and maybe still are) only supporting TLS 1.1/1.0 despite the underlying JDK supporting 1.2 or even 1.3?
Aside<br>I should stop here and mention a subtlety: this behaviour applies to client TLS connections only. Server-side SSL contexts completely ignore the protocol you specify here for the most part and go ahead and support everything.
So what should you do instead? Well there’s really no good answer here. Probably the best thing to do is to use the generic “TLS” identifier, which gets you an unspecified version of TLS, but which all providers I’ve looked at so far interpret as “sensible modern protocol versions”, i.e., TLS 1.3 and 1.2 (with 1.1 and earlier supported but disabled by default). There’s no guarantee at all of that behaviour, but there’s also no guarantee when you specify a version, so pick your poison.
(I’ve raised a bug for this, as it finally pissed me off enough, but my guess is they’ll either ignore it or fix the guide to be as vague as the standard names descriptions).
Share this:
Email a link to a friend (Opens in new window)<br>Email
Print (Opens in new window)<br>Print
Share on Facebook (Opens in new window)<br>Facebook
Share on Reddit (Opens in new window)<br>Reddit
Share on LinkedIn (Opens in new window)<br>LinkedIn
Like Loading…
Security
Java, JSSE, Security, tls
Published by
Neil Madden
Reblog
Subscribe
Subscribed
Neil Madden
Join 66 other subscribers
Sign me up
Already have a WordPress.com account? Log in now.
Neil Madden
Subscribe
Subscribed
Sign up
Log in
Copy shortlink
Report this content
View post in Reader
Manage subscriptions
Collapse this bar
%d