This Gist is about using Client Certificates in Java when making HTTPs calls with plain Java code (java(x).net
, no other frameworks) in a 2-way SSL context, that is: the Server trusts and uses a Client Public Key to establish the secure connection. The example is a Java runnable class for a Client that uses a Certificate to establish a Two Way SSL communication with a Server.
Disclaimer: this gist reflects my understanding, and is not necessarily 100% accurate. Feedback is appreciated.
For this to work, the Client certificate has to be issued by a CA (Certification Authority) trusted by the Server, the same way that the Client has to trust the CA of the Server. In Java, "trust a CA" means having that CA stored in an encrypted file called "trust store" accessible from our code by the use of a password and the appropriate security SDK provided by the JDK.
How to store that trust stores' passwords securely in our enviroments is another story.
In most of the cases where both systems belong to the same corporation, both Server and Client certificates are issued by the same CA, but it is better to think about two CA (one for each), regardless if it was the same.
In ths example, only the Client side is shown.
To run this example we need to pack the CA from Server in to a .jks
(Java Key Store) trust store for the client. That is done by running the following command:
keytool -import -keystore ./client-truststore.jks -file /route/to/server/ca/ca.crt -alias serverca
To run, make those resources available to the code by setting the following javax.net.*
properties in JVM arguments:
-Djavax.net.ssl.keyStoreType=pkcs12
-Djavax.net.ssl.trustStoreType=jks
-Djavax.net.ssl.keyStore=client_0.p12
-Djavax.net.ssl.trustStore=client-truststore.jks
-Djavax.net.debug=ssl
-Djavax.net.ssl.keyStorePassword=changeme
-Djavax.net.ssl.trustStorePassword=changeme
The property -Djavax.net.debug=ssl
makes the console output (System.out
) extremely verbose, so omit if it necessary.
- The
client_0.p12
is the Client Certificate issued by its CA, but only the Public Key would be sent to the Server. - The Server has to send the identificator of the CA that issued the Client Certificate to the Client. That is to say: in the initial handshakes, the Server sends the Client the set of CA's it trusts. If the Client cannot send a Public Key of a Certificate issued by any of those CA, the communication won't take place.
- The same way, the Client has to trust the CA of the Server certificate in order to accept the Server's Public Key. If the Client doesn't trust the Server CA, the communication cannot take place.
- The
ca.crt
of the example holds the CA of the Server, for this Client to trust the Server Certificate. The corresponding truststore of the Server (not shown in this gist) has to hold the CA from the client for it to send in the initial handshakes. - When the handshakes are made (basically, if the Server trusts the Client CA and the client trusted the Server CA), the communication is secure and both can encrypt / decrypt traffic as each party has access to the Public Key of each other. Remember that in asyncronous keys scenarios, we encrypt with the public key of the receiver, who decrypts the messages with is own private key.
- You can change the alias from
serverca
to whatever you need.