Using Let's Encrypt Certificates with OSGi HTTP Service
Rather than one of my usual polemics, this is a quickly-written practical post. I hope the information here is useful to somebody.
Currently I am setting up effectiveosgi.com, the website for my upcoming book “Effective OSGi”. The site is a web app that will allow users to download preview PDFs, order print copies, and so on. Naturally I am developing it in Java and OSGi (in fact, many of the code samples in the book are based on the application that will be used to sell and deliver it).
Of course I want to follow best practices and use TLS (HTTPS), and this is much easier nowadays thanks to Let’s Encrypt. However, it wasn’t exactly obvious how to import the certicate provided by Let’s Encrypt into a Java/OSGi application, so I’m documenting the steps that worked for me.
Step One: Get the Certificate
This part I’m not going document in detail because it’s more than adequately documented on the Let’s Encrypt - Getting Started page. I used the “standalone” method. The subsequent steps assume that you have successfully obtained your certificate files, which will be saved under the path
/etc/letsencrypt/live/[yourdomain]. The files you will find there are
Step Two: Build Java Keystore
Note that this step is relevant for all Java developers, not just OSGi users.
Java applications cannot directly read PEM files; we need to generate a Java keystore file using the
keytool program included with the JDK. Unfortunately
keytool also can’t read PEM files directly, so we first have to use
openssl to convert them to PKCS12 format:
openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem \ -out cert_and_key.pkcs12 -name MyDomain \ -CAfile chain.pem -caname root
You will be prompted to enter an export password. This will only be used in the next step, so it’s fine to use just
password. Now we have a file called
cert_and_key.pkcs12 which combines both the full certificate chain with the private signing key. Import this into a new keystore file as follows:
keytool -importkeystore \ -srckeystore cert_and_key.pkcs12 -srcstoretype PKCS12 -srcstorepass password \ -destkeystore letsencrypt.jks -deststorepass XXXXXX -destkeypass XXXXXXX
You now have a keystore file named
letsencrypt.jks. Keep the store and key passwords safe and secret!
Step Three: Configure HTTP Service
This step is relevant to OSGi developers. I’ll assume you are using the Apache Felix HTTP Service.
The HTTP Service is configured with the standard OSGi Configuration Admin. You need to create a configuration record with a PID of
org.apache.felix.http with the following settings:
org.apache.felix.https.enable true org.osgi.service.http.port.secure: 8443 org.apache.felix.https.keystore: path/to/letsencrypt.jks org.apache.felix.https.keystore.password: XXXXXX org.apache.felix.https.keystore.key.password: XXXXXXX
This should be all you need to do get a green lock icon in your browser. Congratulations, you are now running a properly configured HTTPS server!
However… it’s not very secure yet. Once your site is running, I strongly recommend testing your TLS implementation using SSL Labs from Qualys. If you do this now, you will get at best a B grade.
Step Four: Getting the A Grade
One of the security warnings reported by SSL Labs is due to weak Diffie-Hellman groups. I don’t pretend to understand everything on the linked page, but fortunately the fix is easy: you just need to make sure your Java VM uses 2048-bit Diffie-Hellman keys by setting a system property. This can be specified on the command line as follows:
java -Djdk.tls.ephemeralDHKeySize=2048 ...
To achieve forward secrecy you also need to restrict the cipher suites to use only elliptic-curve algorithms. It’s also a good idea to limit the server to 256-bit rather than 128-bit algos. This is done in the configuration admin record for the HTTP Service; just add the following:
org.apache.felix.https.jetty.ciphersuites.included: \ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, \ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, \ TLS_RSA_WITH_AES_256_CBC_SHA256, \ TLS_RSA_WITH_AES_256_CBC_SHA
With these settings you should now be a grade A student:
Finally: you might be wondering how to get an elusive A+ grade on SSL Labs. Alas it doesn’t currently seem to be possible in a Java-based server (though I may be wrong – please let me know in the comments). The feature needed to unlock A+ is called TLS_FALLBACK_SCSV, and it requires an API change. Hopefully it will be implemented in Java 9.