Wednesday, August 12, 2009

Two way SSL on Tomcat & JBoss

Continued from the previous post where I had put in steps to setup one way SSL. In this post i shall provide steps to enable client certificate authorization. Hence here we will see a situation where the client verifies the server cert and server verifies the client cert for validity and trust before a successful SSL handshake. The initial steps shall be the same as mentioned in my previous post and with an assumption that your one way SSL is already working. Now to enable the client authorization, we need to modify the server.xml as below:
<Connector 
  port="8443" minSpareThreads="5" maxSpareThreads="75" enableLookups="true"
  disableUploadTimeout="true" acceptCount="100" maxThreads="200" scheme="https" 
  secure="true" SSLEnabled="true" keystoreFile="c:/certs/test_store" keystorePass="password" 
  clientAuth="true" truststoreFile="c:/certs/test_store" 
  truststorePass="password" sslProtocol="TLS"/>
Export a certificate from the client keystore (client_store in this example) and import it into the server's truststore (test_store in this example). In real world you probably would not import each client cert but a CA root cert and then sign each client cert with that one. The above mentioned way is only for testing purposes and get the feel of the process. Launch the server. No modifications are needed in the code on the client side. You can launch the client using:
c:\>java -Djavax.net.ssl.trustStore=c:/certs/client_store -Djavax.net.ssl.trustStorePassword=password -Djavax.net.ssl.keyStore=c:/certs/client_store -Djavax.net.ssl.keyStorePassword=password HelloWorld
Additional Tips: 1)In order to get detailed debug statements for the SSL handshake between the server and the client you can use the vm argument -Djavax.net.debug=ssl,handshake on either side. 2)If you want to be able to access the site using your browser then you will have to have the client certificate in the Internet Options > Content > Certificates > Personal section. For this you will have to be using a PKCS12 keystore instead of a standard JKS keystore. Hence instead use the following steps to generate the keystore on the client side:
keytool -genkey -v -alias clientKey -keyalg RSA -storetype PKCS12 -keystore client.p12
The keypass and storepass needs to be the same. Like in the steps for client using JKS, even here you can use a similar command to export the cert
keytool -export -alias clientKey -keystore client.p12 -storetype PKCS12 -rfc -file client.cer
Rest instructions like importing this cert into server's keystore continue to be same. One important point to note is that since the server's cert cannot be imported into PKCS12 keystore on client side, you have to import it into a JKS truststore and the commandline to launch the program needs to be modified as:
c:\>java -Djavax.net.debug=ssl,handshake -Djavax.net.ssl.keyStoreType=PKCS12
-Djavax.net.ssl.keyStore=c:/certs/client.p12 -Djavax.net.ssl.keyStorePassword=password
-Djavax.net.ssl.trustStore=c:/certs/cacerts -Djavax.net.ssl.trustStorePassword=password HelloWorld
In this case, the server's certificate has been imported into the cacerts truststore of type JKS. The PKCS12 keystore can be imported into the internet explorer at the above mentioned path. Now if you hit the URL using https, you shall be displayed a dialog box to select the cert you want to use for client authorization. Once you select it, the handshake process continues. Through out the example we have been making hits to a servlet (https://personal-PC:8443/SampleWebApp/HelloWorld). We can get the details of the client cert used to access this URL from an attribute in the request object.
X509Certificate certs[] = (X509Certificate[])request.getAttribute("javax.servlet.request.X509Certificate");
for (X509Certificate cert : certs) {
out.println(cert.getIssuerDN());
}

1 comment: