This is part of a series of posts about setting up Play WS as a TLS client for a "secure by default" setup.
Previous posts are:
- Fixing The Most Dangerous Code In The World (MITM, Protocols, Cipher Suites, Cert Stores)
- Fixing X.509 Certificates (General PKI, Weak Signature and Key Algorithms)
- Fixing Certificate Revocation (CRL, OCSP)
- Fixing Hostname Verification (HTTPS server identity checks)
- Testing Hostname Verification (DNS spoofing your client for educational purposes)
This post is where the rubber meets the road – an actual, demonstrable activator template that shows off the WS SSL, provides the scripts for certificate generation, and provides people with an out of the box TLS 1.2 using ECDSA certificates.
Want to download it? Go to https://github.com/typesafehub/activator-play-tls-example or clone it directly:
It's an activator template, so you can also install it from inside Typesafe Activator by searching for "TLS".
Be sure to read the README. This project is as lightweight as possible, but takes a little configuration to get started.
The biggest part of any demo application is setting up the scripts. I didn't find anything that was really hands free, so I wrote my own. They are exactly the same as the ones described Certificate Generation section of the manual.
There's various shortcuts that you can use for defining X.509 certificates, but I found it a lot more useful to go through the work of setting up the root CA certificate, defining the server certificate as having an EKU of "serverAuth" and so on.
The actual script to run Play with all the required JVM options is… large. Part of this is the documentation on every possible feature, but sadly, there are far too many lines which are "best practices" that are very rarely practiced.
Also, the note about
rh.secure is a reference to the RequestHeader class in Play itself. Ironically, even when we set HTTPS up on the server, Play itself can't tell the protocol it's running on without help.
I will admit to being gleefully happy at setting
disabledAlgorithms.properties on startup, so that at last AlgorithmConstraints is enabled on the server:
The CustomSSLEngineProvider is responsible for Play's HTTPS server. More details can be found in Configuring HTTPS.
Setting up an
SSLEngineProvider with client authentication is pretty easy, once you know the magic incantations needed to get the trust managers and the key managers set up. After that, it's a question of ensuring that the SSLEngine knows how trusting it should be.
Connecting to the server with Play WS
Setting up the Play client was pretty easy, but it's worth repeating that Play WS can be run outside of an application with the right setup:
The configuration on the ws.conf file was also intentionally strict. The NSA recommends some nice cipher suites Suite B Profile for TLS – the WS client will refuse to talk to the server with anything less than full on
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 and isn't going to look at any ECDSA signature less than
EC keySize < 384.
Client authentication on the client side was a little trickier than expected, but eventually I remembered that the client should be using a key store containing a trust anchor, and it worked itself out.
I think I'm done with JSSE for now. I was interested in exploits at one point, but the fixes amount to "Upgrade to JDK 1.8, use ECDSA certificates, and TLS 1.2" – all of which are demonstrated in this application.
I may at some point go back and look at HSTS or public key pinning in Play WS, but it really comes down to utility. Many of the use cases of pinning involve browsers or unknown clients. I've not heard of any demand for the feature, and it's unclear that anyone would find it all that useful.
With Play and with these blog posts, I'm very pleased to have written something that people find useful. Thanks.