Tuesday, November 18, 2014

Netty (3.9.x) client-server connection with 2-way SSL authentication

Ok, so this is about how to (1) create a simple text based client-server protocol with Netty 3.9 that uses 2-way SSL authentication, i.e. an encrypted connection that also authenticates the client, and (2) how to generate the SSL certificates yourself. Code examples are in Scala.

Make sure you know how Netty works, how messages are sent and received, that is not covered here.

1) Client-server


Client

Code here.

A few notable things here:
  1. SslManager, we'll get back to that in a bit...
  2. Once the channel is connected (channelConnected()), we initiate the ssl handshake and listen to the result.
  3. In the ChannelFutureListener we wait for the success of the handshake. Note that communicating over this channel before won't work and will be insecure!!! 

Server

Code here.

Pretty similar to the client side:
  1. SslManager, just wait...
  2. In this example, we have a bunch of channels (ChannelGroup) that want to listen to the same stuff. Your scenario might be different.
  3. Once the channel is connected we do the same handshake thing on the server side.
  4. Only once the connection is secure (ChannelFutureListener) do we add the channel to the group.

SslManager

Code here, thanks to Veebs. This is used by both the client and the server.

2) Generate SSL certificates

What you need here is:
  1. One key store for the client with the client's private and public key
  2. One key store for the server with the server's private and public key
  3. One trust store for the client with the server's public key
  4. One trust store for the server with the client's public key
For this we can use the keytool program that comes with any JDK.

We generate a key store for the client with the following command, step 1):

keytool -genkey -alias fcr-freq-client -keysize 2048 -keyalg RSA -validity 3650 -keystore client.keystore -storetype JKS

Here you will be asked for a password to access the keystore. This is the password you have to give as argument to the ClientPipelineFactory.

Next we have to extract the client's public key from the keystore. This can be done with the following command (use the password defined above when prompted):

keytool -export -alias fcr-freq-client -keystore client.keystore -rfc -file public-client.cert

The public-client.cert file now contains the client's public key. Next, generate the server's truststore that will contain the client's public key:

keytool -import -alias fcr-freq-client -file public-client.cert -storetype JKS -keystore server.truststore

Here you'll have to give a password for the server truststore. Use a different one from the one you used for the client.

You should now have three files, client.keystore, server.truststore and public-client.cert. You can delete the last one as there is no more use for it.

Now do this again, but for the server, i.e. generate the server keystore (and use the server password), extract the server's public key (with the server password) and generate the client truststore (use the client password). With this, the client code only needs to know the client password and the server code only needs to know the server password.

Sources