Speed Up Netty SSL

Knowing Where You Are

First you can do a few simple test to see how good (or bad) your current SSL configuration of your Netty server is. Note: These tools also work with any other web server.

  • Perform the wormly SSL Web server test on your server to get an idea how well your server is configured.
  • For a more comprehensive test, consider to use the tool sslyze, which will test your server SSL configuration.

Just download their executable from https://github.com/nabla-c0d3/sslyze/releases, unpack the repository and run

sslyze.exe –regular yourserver.com

The test might run for a while but will generate a very informative report.

Improving Netty Performance

Depending on your results in the first step, you might consider the following ways to improve the performance of your Netty server:

  • Assure to keep HTTP connections ALIVE.

This requires to send a ‘Content-Length’ header to the browser and not to close the channel after a response has been written to the channel.

References

Stackoverflow – Slow Java SSL in a netty application

5 easy tips to accelerate SSL

Setting Up SSL with Netty

SSL is unquestionably a very useful and powerful technology to make systems more secure. Java in general and Netty in specific provide strong out-of-box support for supporting SSL encryption and authentication. However, since SSL is a complex technology it can often be cumbersome and difficult to set it up correctly.

The following steps describe how an SSL certificate can be obtained and configured to be used in Netty.

Step 1: Create a Keystore

Create a keystore using Java’s keytool (it’s in the [path to java]/bin directory if it’s not on your classpath):

keytool -keysize 2048 -genkey -alias tomcat -keyalg RSA -keystore tomcat.keystore

Step 2: Create a Certificate Signing Request (CSR)

You need to generate this request to submit it to whichever party you would like to issue your SSL certificate (e.g GoDaddy or StartSSL). Again, use Java’s keytool:

keytool -certreq -keyalg RSA -alias tomcat -file yourdomain.csr -keystore tomcat.keystore

Step 3: Upload Certificate Singing Request to Issuer

Go to your issuer’s website and upload the CSR where possible. For GoDaddy, the necessary form looks as follows:

Just copy and paste the contents from the yourdomain.csr file.

Step 4: Download Certificate from your Provider

Download the certificate from your provided/issuer. For instance, for godaddy.com, select the certificate for Tomcat.

Step 5: Installing the Certificates into your Keystore

You will need to install both the certificate for your server as well as some certificates from your issuer (see intermediary certificates).

Below we will install the certificates provided from GoDaddy. First, install the root certificates from GoDaddy into your keystore (the names for the crt files are different for different providers).

keytool -import -alias root -keystore tomcat.keystore -trustcacerts –file gd_bundle.crt

Then, install the intermediary certificates:

keytool -import -alias intermed -keystore tomcat.keystore -trustcacerts –file gd_intermediate.crt

The tool might prompt you that the “Certificate already exists in keystore under alias <root>”. Type “yes” to add it in any case.

Lastly, install the certificate for your server:

keytool -import -alias tomcat -keystore tomcat.keystore -trustcacerts –file yourdomain.com

This time, the tool should report “Certificate reply was installed in keystore”.

The result of this procedure should be that the tomcat.keystore file should have grown in size to about 8 kb (from 3 kb after step 2).

Optional: Also download the ‘Go Daddy Class 2 Certification Authority Root Certificate‘ from the godaddy website and add it to your store. Add it with the alias ‘root2’.

Step 6: Double-Check you have Installed all Certificates

Use to keytool to verify that you have all certificates installed correctly.

keytool –list –keystore tomcat.keystore

This should show you that your keystore contains three entries: ‘root’, ‘intermed’ and ‘tomcat’. (And ‘root2’ if you have added the Go Daddy Class2 certificate).

Step 7: Prepare Keystore for Netty

There are many ways to provide the keystore we have just create to Netty. The following is just one option (but one I find particularly handy):

1. Convert your keystore into a String using Base64Coder and the OneUtils.

final File original = new File(pathtoyourkeystore);

System.out.println(Base64Coder.encode(

OneUtilsJre.toByteArray(new FileInputStream(original))));

2. Copy the String and place it into a static variable, for instance:

class MyKeystore {

public static data = "[generated base 64 data]";

}

3. Create an SSLContext from the data of your keystore.

SSLContext serverContext = SSLContext.getInstance("TLS");

final KeyStore ks = KeyStore.getInstance("JKS");

ks.load(new ByteArrayInputStream(Base64Coder

.decode(MyKeystore.data)),

"yourkeystorepassword".toCharArray());

final KeyManagerFactory kmf = KeyManagerFactory

.getInstance(algorithm);

kmf.init(ks, "yourkeystorepassword".toCharArray());

serverContext.init(kmf.getKeyManagers(), null, null);

4. Create a Netty SSLHandler from the created context:

final SslHandler sslHandler = new SslHandler(serverContext);

5. Add the SSL handler to your Netty pipe (remember this must be the first handler):

pipeline.addLast("ssl", sslHandler);

Now deploy to server and enjoy the SSL security.

References

Generating a CSR and Installing an SSL Certificate in Tomcat 4.x/5.x/6.x

Tomcat 5 SSL – Install GoDaddy Wildcard Certificate JKS / PKCS12 ? What?

Eclipse Wiki – Generating a Private Key and a Keystore

Why Netty cannot serve multiple SSL domains from one IP

Background

Due to some issues with a transparent proxy apparently employed by Vodafone New Zealand, a signed SSL certificate had to be added to the REST server in the Appjangle cloud in order to serve resources ‘protected’ from Vodafone’s caching efforts.

One REST server in the Appjangle cloud can serve more than one domain … but this appears to be troublesome to achieve using SSL.

Problem

You would like to serve content through HTTPS from two domains from one IP address using Netty. For example:

https://mydomain1.com

and https://mydomain2.com

both should be served from a Netty server running on the IP 184.2.23.1.

Analysis

It is relatively easy to host multiple HTTP hosts on one IP address. One can implement a SimpleChannelUpstreamHandler arranged in a pipeline after a HttpRequestDecoder. The SimpleChannelUpstramHandler can then separate requests based on the HOST value of the incoming HttpRequests.

For SSL, this is not possible, since the SslHandler is usually defined at the very beginning of a Netty pipeline. This is an inherent requirement of the SSL protocol, which protects communication with an IP address and not with a domain.

It is therefore not possible to ‘unwrap’ the incoming encoded message and retrieve its HOST value, since this can only be done AFTER the SSL connection is established.

Note: This is not an inherent problem of Netty but caused by the JDK’s SSL implementation.

Solution

One possible solution would be to use Server Name Indication – an extension to the SSL protocol to allow for ‘virtual hosts’ over SSL. However, this is extension not necessarily supported by all available HTTP clients. Moreover, it does not appear that Netty/Java currently support Server Name Indication.

Therefore, the best option at present appears to use one dedicated IP address for every HTTPS host you want to use.

Also note that JDK 7 adds support for Server Name Indication, so if you are running on this platform, you could explore if you can configure Netty to support it.