Configuring SSL/TLS Connection Made Easy
Configuring SSL/TLS Connection Made Easy
In this article, we discuss how to easily configure an SSL/TLS connection in Java to better secure your application.
Join the DZone community and get the full member experience.Join For Free
Setting up encryption for your application, how hard can it be? I thought it should be easy, as all communication with modern web applications should be encrypted, right? Well, my expectations were wrong... While setting it up, I encountered a couple of hidden difficulties. For example, the configuration is vague, verbose, not straight-forward to set it up, hard to debug, and not unit-test friendly.
For this article, I'll assume you already have a basic understanding of certificates, keystores, encryption protocols, and ssl-handshake. If not, I would recommend going through this article: How to Easily Set Up Mutual TLS.
It will go through the following topics:
- No security.
- One-way authentication.
- Two-way authentication.
- Two-way authentication with trusting the Certificate Authority.
It will also explain how to create KeyStores, Certificates, Certificate Signing Requests, and how to implement it.
Let's continue to the next part. I want to provide a couple of examples to explain the hidden difficulties when setting up a secure connection with https and certificates in vanilla Java. For this example, I will use Apache HttpClient. If we want to use a client without encryption, the following setup will get the job done:
Apache HttpClient requires a configured
SSLContext instance to enable a secure https connection. The most minimal setup would look like the example below:
The above setup looks easy, but it brings a lot of additional logic in your codebase. It can be time-consuming to understand the following for someone who is not familiar with java security library:
- What is the best way to create a keystore?
- What is a default keystore type and what other options can I choose from?
- Why do I need a TrustManagerFactory? Can't I just put my keystore instance with trusted certificates directly into the
- What is the default algorithm of a TrustManagerFactory?
- Is the default algorithm good enough, or do I need another one and what other options can I choose from?
- Which encryption protocol should I choose to create an
- Why can I provide null as a parameter value when initializing an
SSLContext, and what will the resulting
SSLContextdo for me?
Well, these are a lot of questions to be answered for just a basic setup. I won't be providing the answers to the above questions, as these are already answered by our community. As a developer, you probably want to provide the best configuration for your projects and with the least amount of effort, which also should be maintainable.
The above configuration will get even harder if you also need to configure your client to communicate with mutual TLS, also known as mutual authentication. It is also hard to unit test an
SSLContext object because you can't get any information from it that will tell if the
trustmanager is really initialised well and if it contains all the trusted certificates. The only way to really validate your code is by writing an integration test, where the client actually sends a request to a real server with HTTPS enabled.
I faced the same challenges as my colleagues. They also didn't enjoy setting it up. It was just a configuration that needed to be set up once well enough to do the job, and after that, we feared to touch it again.
Some other HTTP clients even require a different setup (e.g., Netty HttpClient, AsyncHttpClient, and Dispatch Reboot). These clients only accept an
SSLContext from Netty's library instead of the one from the JDK.
I wanted to help myself out from this difficult task and make my life easier. I thought why shouldn't we have something similar to Lord Of The Rings — one ring to rule them all. So, in that way, sslcontext-kickstart was born. One library to configure and rule them all! It should be painless to use, easy to test and debug, and fun to set-it-up. The project is available at Github - SSLContext-Kickstart
- No need for low-level
- No knowledge needed about
KeyManagerFactory, and how to create it.
- The above classes will all be created with just providing an identity and a
- Create an
sslcontextwith multiple identities and
- Load multiple identities/trustStores/keyManagers/trustManagers
The vanilla java example of earlier could be replaced with the following code snippet:
Other configurations are also possible:
One way authentication with the default JDK
One-way authentication while trusting all certificates without validation, not recommended to use at production!
One-way authentication with a specific encryption protocol version and option to validate the hostname within the request against the SAN field of a certificate. If you are using Java 11 or newer, then you are also able to use TLSv1.3 as encryption protocol. Just provide "TLSv1.3" as a protocol argument, and it will work out-of-the-box.
Two-way authentication with custom
trustStore, hostname verified, and encryption protocol version:
Support for using multiple identities and
Support for using X509KeyManager and X509TrustManager:
Let's also have a quick look at the unit test:
Or, see SSLFactoryShould for all other possible unit tests cases.
Below is a list of clients which have already been tested with examples, see in the ClientConfig class and the service directory for detailed configuration. Visit the following page for the most recent version of the list: Example SSL / TLS Configuration for Http Clients
- Apache HttpClient -> Client configuration | Example request
- JDK HttpClient -> Client Configuration | Example request
- Old JDK HttpClient -> Client Configuration & Example request
- Netty Reactor -> Client Configuration | Example request
- Jetty Reactive HttpClient -> Client Configuration | Example request
- Spring RestTemplate -> Client Configuration | Example request
- Spring WebFlux WebClient Netty -> Client Configuration | Example request
- Spring WebFlux WebClient Jetty -> Client Configuration | Example request
- OkHttp -> Client Configuration | Example request
- Jersey Client -> Client Configuration | Example request
- Old Jersey Client -> Client Configuration | Example request
- Google HttpClient -> Client Configuration | Example request
- Unirest -> Client Configuration | Example request
- Retrofit -> Client Configuration | Example request
- Async Http Client -> Client Configuration | Example request
- Twitter Finagle -> Client Configuration | Example request
- Twitter Finagle Featherbed -> Client Configuration & Example request
- Akka Http Client -> Client Configuration | Example request
- Dispatch Reboot -> Client Configuration & Example request
- ScalaJ / Simplified Http Client -> Client Configuration & Example request
- Sttp -> Client Configuration & Example request
- Requests-Scala -> Client Configuration & Example request
- Http4s Blaze Client -> Client Configuration | Example request
- Http4s Java Net Client -> Client Configuration | Example request
The source code is available here at Github: SSLContext-Kickstart.
Get the latest version from Maven Central or copy and paste the following snippet into your pom:
Or for Gradle:
Or for Scala SBT:
libraryDependencies += "io.github.hakky54" % "sslcontext-kickstart" % "3.0.9"
Or for Apache Ivy:
<dependency org="io.github.hakky54" name="sslcontext-kickstart" rev="3.0.9" />
Good luck and enjoy enabling encryption on your project!
Opinions expressed by DZone contributors are their own.