server side TLS support #339

merged 3 commits into from Oct 4, 2012


None yet

7 participants

bblfish commented May 28, 2012

This patch extends the very minimal TLS support in the master branch of Play with the following:

  • start https:// from the console (in dev mode)
  • settable properties from config file
  • patches the default server certificate to work for localhost (where it is most likely to be used)
  • fixes efficiency issue in TLS setup (it used to setup the whole connection on each tls request)

see also ticket 215: TLS-HTTPS support in Play 2.0 (I am not sure where one votes for pull requests. Here or at the tls ticket.)

TLS in server mode

It is useful to be able to run TLS in dev mode. This patch allows this to be done from the shell with

run -Dhttps.port=8443

The FakeKeyStore's certificate has been changed to one whose CN (Common Name) is localhost.
This is because browsers and other clients tend to look at the CN to see if they have reached the right server. It would be nice of course if one of the well known CA's signed an open localhost server, which could
then be used here usefully for test suites. (but that would be probably quite a lot of work to get them to do this)

Still CN=localhost is one less problem for clients. Apache's http client needs to be set up to ignore those errors in addition to ignoring certificates that might not be signed by well known CAs.

To see the certificate used by the server you can connect with your browser and click in the URL bar on the connection for such information, or you can use the following command line

openssl s_client -showcerts -connect localhost:443


With the latest patch one can now specify any keystore in the conf/application.conf file with the following properties

https.port8443.keystore { 
                          location : "conf/KEYSTORE.jks"
                          type : JKS
                          alias : selfsigned
                          password : secret
                          algorithm : SunX509
                          trust : noCA }

where alias is the alias of the server certificate placed in the keystore KEYSTORE.jks . Such a keystore can be built with java's keygen tool - for a hypothetical swiss company - as follows

$ keytool -genkey -alias selfsigned -keyalg RSA -dname ", OU=software, L=Zurich, ST=Switzerland, C=CH" -storepass secret -validity 2000 -keystore KEYSTORE.jks

By following the procedures listed by your favorite Certificate Autority, you can also place a certificate in the keystore that is signed by that CA and have the server use that. (Note that provides free signed certificates.) This will allow your users to connect to your server on https:// without an ugly warning box appearing. Hopefully greater support of IETF Dane by browsers will make it possible to use self signed certificates too.

See Also

Client side certificate support builds on this patch but was placed in a separate branch: pull request 340


Thank you so much!

bblfish commented Jun 3, 2012

with this patch, it should be possible to use curl to connect to localhost using the command line tool curl

curl -k -i  https://localhost:8443

For a bigger patch that builds on this, and that allows client side certificates, see pull request 340
enable requests to get client Certificates

I could also perhaps improve this patch to allow the user to specify his server certificate.

bblfish commented Jun 8, 2012

In the last patch ( e6af6dd ) I also made the TLS server more efficient. It only loads the keystore information once on startup, and not at every request as it was doing. It also allows you to set your server certificates, where previously you could only use a default one for localhost.

joscha commented Jun 10, 2012

nice work!

pk11 commented Jun 13, 2012

this looks very interesting. We will need to review this more carefully. Thanks

bblfish commented Jun 15, 2012

I just noticed that on my local test server that uses this patch the http port is set up as an HTTPs port. I had not been using the http port that much... Ie if I curl on port 9000 with an http:// url I get

[warn] play - Exception caught in Netty not an SSL/TLS record: 474554202f323031322f68656c6c6f2e6e3320485454502f312e310d0a557365722d4167656e743a206375726c2f372e32352e3020287838365f36342d6170706c652d64617277696e31312e332e3029206c69626375726c2f372e32352e30204f70656e53534c2f312e302e31207a6c69622f312e322e36206c696269646e2f312e32320d0a486f73743a206c6f63616c686f73743a393030300d0a4163636570743a206170706c69636174696f6e2f7264662b786d6c0d0a0d0a
    at org.jboss.netty.handler.ssl.SslHandler.decode( ~[netty-3.3.1.Final.jar:na]
    at org.jboss.netty.handler.codec.frame.FrameDecoder.callDecode( ~[netty-3.3.1.Final.jar:na]

Let me see what this could be due to...
Ok fixed with patch addcbc0

otwebti commented Jun 27, 2012

Very nice.
Seems very much in keeping with Play's philosophy of including all the standard pieces straight out of the box.

@jroper jroper was assigned Oct 3, 2012
jroper commented Oct 3, 2012

Hi Henry, I will be merging this pull request, but before I do, I want to make sure I have understood everything here. I wasn't involved in the initial implementation so I would like to check that I understand that too.


Before, Play was using a hard coded key store. Now if my understanding of SSL and Java key stores is correct, this is where the private key that is used to encrypt the SSL stream is stored, and is also where the certificate (in this case self signed) is stored. Basically this means that Play's current implementation of TLS is completely insecure, since anyone can obtain the private key from the Play source or binaries, and decrypt the symmetric key that the client has encrypted with the servers public key, and then decrypt all communications between the client and server.

Now, you can configure the key store, but it falls back to using the Fake key store if no key store is configured, with a warning message.

Is there any particular reason for providing the fallback? As far as I can see, this is a massive security vulnerability, making users think they are safe because they are using https, but with nothing but a small warning in the console that doesn't even properly inform them that the encryption is trivial for an eavesdropper to decrypt. I think the fallback should be removed, if they have not configured a keystore, it should fail to enable https.

If we do want to provide a fallback, for simple configuration, then we should generate the key store, with a key generated by SecureRandom, so that at least the encryption is somewhat secure.

HTTP port configuration

The HTTP port can now be configured in application.conf. Before, it could only be configured using system properties. application.conf config is overridden by system properties, therefore this change is backwards compatible.

Keystore configuration

The keystore configuration requires the port number to be in the key. Is there any particular reason for this? If we had the option to allow Play to listen on multiple different SSL ports, with different keystores, then this would make sense. In such a configuration I would imagine you'd have port forwarding from different IP addresses on port 443 (this allows the same Play instance to serve different domains with SSL). But it would be simpler to have Play bind to the same port (443) but on different IP addresses, in which case, you'd want to namespace the configuration by bind address, not port.

However, in such complex deployments, you're much more likely to have a load balancer/http router out the front, and therefore much more likely to handle all SSL at that stage, so I don't see why we should add this complexity in configuration here. In future, if we do allow binding to multiple SSL ports/addresses with different keystores, then in that configuration, if a list is supplied, we can check the namespaced config first, and if it doesn't exist, fallback to https.keystore. So for now to keep it simple, I'd say just have it as https.keystore.

I'm happy to make the necessary changes, I just want your feedback before I go ahead and do them.

bblfish commented Oct 3, 2012

Hi, thanks for working on this. Answers to your questions below

Fake Key Store

Yes, you are right: the keystore is where the private keys are stored, and that is indeed essential to the security of the server. I think having the hard coded key store is still a good default when running the server in localhost mode or in test mode.

For servers not in localhost or test mode mode generating a random certificate is indeed a better idea. Even better: you'd want to store it, so that the server can reuse the self signed certificate over time. (people are putting systems in place to help verify authenticity of servers by verifying stability of public keys: see SSL and the future of authenticity for some interesting ideas) Perhaps for play you'd offer a quick command line dialog and ask him a few of the questions openssl asks you. But that could be automated. I think you just need the domain name in the CN= part of the field to be the host name. You can see what current servers have with

$ openssl s_client -showcerts -connect

If the CN does not match the domain name, other connection errors appear. (That is why I patched the hard coded cert to have a CN=localhost - if I remember correctly.) Of course it would have to be self signed

Multiple SSL ports

Yes, I was probably trying to generalise too much there with multiple ports.


@jroper @bblfish Just a few points:

I think it's important to keep an easy to setup HTTPS way for development. I agree with James that it would be better if the fake key was random. But anyway keep in mind that no browser will accept the fake key without a big warning anyway. So I don't think there is a real risk of using a fake key in production.

Regarding the configuration, since the beginning of Play 2.0 I wanted to split the application configuration (in the application.conf file) and the server configuration (via system properties for netty, or in the future if we support more backend using the custom configuration mechanism of the backend).

It's way better this way because you can't really read the application configuration file while the application is not yet started. And it is the server that starts the application. So we have a cycle here. In Play 1.x before, the python scripts were reading the configuration file as well but it was leading to logic duplication and incoherence (like if you deploy in WAR mode, some configuration properties are not taken in account).

So I would say that both HTTP and KeyStore configuration shouldn't live in the application configuration file. They should be provided by system properties, or if it becomes too complicated to managed, in a dedicated netty configuration file.

jroper commented Oct 3, 2012


I completely agree that we need to have easy HTTPS setup for development. My biggest concern is that people will go to production using the fake key in server to server communication, where CA checking is easy to disable, self signed certs are often used anyway, and they are using SSL just so that the communication channel is encrypted. If we didn't go with a random key, then I'd like to see a big error message at error level saying that this configuration is insecure. But I don't think generating a random key and self signed certificate will be hard, the keystore APIs are easier to work with than the command line tool, and we can write it out to the conf directory the same way evolutions are generated and written there when required.

The interesting thing about configuring HTTPS via system properties, is that Java already provides quite a powerful way to configure the default keystore/truststore via system properties:

So, if we just let it all be done via system properties, then we don't have to do anything, and users get the full power of what Java provides out of the box. As for moving it to a configuration file, I think this is a good idea, the biggest problem though, if using Javas built in system properties, is how to load the system properties into the Java system properties as soon as possible, before Java does any lazy initialisation of its crypto APIs based on the system properties. I'll have a look at the OpenJDK source code to see how feasible it would, what race conditions might exist etc (I'm thinking, for example, if SBT goes out and makes an HTTPS connection to download an artifact, before any Play code was executed, would that prevent us from loading system properties to configure HTTPS).

jroper commented Oct 4, 2012

I've pulled this pull request into a new branch, and created a new pull request for final review before merging:


@jroper jroper merged commit addcbc0 into playframework:master Oct 4, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment