How to implement 2-way SSL using Spring Boot

What is 2-way SSL(Mutual Authentication)?

In 2-way SSl both client and server have to present their certificates to each other to verify themselves with a trusted certificate.

In 2-way SSl there are 12 steps to digitally handshake. They send total 12 handshake messages to each other to set up a secure encrypted channel for further communication.

Fig.  2 way  SSL handshake messages

Process of 2-way SSL communication:

  1. Client sends ClientHello message proposing SSL options.
  2. Server responds with ServerHello message selecting the SSL options.
  3. Server sends Certificate message, which contains the server’s certificate.
  4. Server requests client’s certificate in CertificateRequest message, so that the connection can be mutually authenticated.
  5. Server concludes its part of the negotiation with ServerHelloDone message.
  6. Client responds with Certificate message, which contains the client’s certificate.
  7. Client sends session key information (encrypted with server’s public key) in ClientKeyExchange message.
  8. Client sends a CertificateVerify message to let the server know it owns the sent certificate.
  9. Client sends ChangeCipherSpec message to activate the negotiated options for all future messages it will send.
  10. Client sends Finished message to let the server check the newly activated options.
  11. Server sends ChangeCipherSpec message to activate the negotiated options for all future messages it will send.
  12. Server sends Finished message to let the client check the newly activated options.
Pre-Requisites:
  1. Java 1.8
  2. Spring Boot 2.4.4
  3. Keytool (bundled with jdk)

To implement 2-way SSL we will create 2 applications in spring boot: client application and server application.

Create self signed certificate for client:

We have different ways to do this but in this blog we will use “keytool” to generate a certificate:

Here we created a jks(java key store) file or certificate  for client.

Here SAN entry is very critical for self signed certificate as it may generate problem with chrome and safari browser if we skip it.

Create certificate for server application:

 

Create public certificate file from client app certi:

Now we will create public certi(.crt) from client jks file.

Create public certificate file from server app certi:

create public certi from server jks file.

We created public certificates and keystores for both client and server.

Now we will establish trust between them by importing client certificate into server’s keystore and vice versa.

Import server’s certificate into client keystore:

Import client’s certificate to server keystore:

Here we added public certificates into each other’s key store so they can verify the certificate and trust for further communication.

Next step is to configure our applications for encrypted SSL communication.

Configure Server for 2 way SSL communication:

  1. We have to copy java key store file to our resources folder(src/main/resources) in our server application
  2. Add following code to our application’s properties file(application.properties or application.yml).

Here we enabled SSL and made client-auth necessary to implement 2 way SSL and key-store-password is the password which you entered while creating the server jks file.

Create a controller class for incoming request:

Here we created a controller to serve incoming requests on the server application with an endpoint :  “/server-app/data”.

That’s all from server side now we need to configure client.

Configure Client for 2 way SSL :

  1. We have to copy java key store file to our resources folder(src/main/resources) in our client application
  2. Add following code to our application’s properties file(application.properties or application.yml).

Now we will add few dependencies of httpcomponent in pom.xml file of client app.

We have RestTemplate class in spring boot for https communication. We will use this RestTemplate class for our https communication from client application to server app. To set up 2 way SSL we need to configure our RestTemplate to use client’s trust store with server certificate to set up trust between them.

Configure controller in Client-app:

Now we will create 2 controllers in our client’s controller class:

Here we created 2 methods, one of them is communicating with the server controller using RestTemplate. We defined “msEndpoint” in our application.yml file.

Finally we configured both applications for 2 way SSL communication. Now we have to run these application as Spring Boot App in our IDE(I prefer STS). 

Now our client and server applications will start on ports respectively 9001 and 9002 that we defined in application.yml file.

Configure IDE to see all handshake protocol in IDE’s console:

To see complete debugging and all 12 digital handshake messages in our IDE’s console we have to follow these steps :

  1.  Right click on server-app and select run as from list.
  2.  Open “Run Configurations” and click on tab “arguments”.
  3. Add following arguments to “VM arguments” tab

 

That’s all and you can see complete debugging.

Import Certificate to Browser:

Now the problem is that we can’t browse these application’s url on the browser as our browser will complain about the certificate because here we configured the app for 2 way SSL  so we need to import our server’s certificate to our browser.

Unfortunately our browser can’t understand .jks file it understands only PKCS12 format file so we have to convert our jks file to PKCS12 format. To do this we can use “keytool”:

Here we converted the .jks file to .p12 format.

Now we will import this .p12 file on our browser so that our browser can present this cert to our client application for authentication purposes.

Steps to import .p12 file on chrome browser are:

 

  • Open settings tab of chrome browser and open security tab.

  • In the security tab go to bottom of the page and open “Manage Certificates” tab.

  • Now tap on “import” and select .p12 file and import it to browser.

That’s it now we are ready to test our application on browser using https://localhost:9001/{urlEndpoint} .

Now when we hit the url of our application the browser will give warning that “Your connection is not private”.

Just click on “advanced” and then tap on “proceed to localhost(unsafe).

Then select the certificate that you imported in the browser from the alert box and you are all set.

You can find complete source code on Bitbucket : https://bitbucket.org/nikhil_khicher/2-way-ssl-set-up/src/master/

 

Thank you

Comments