Installing the APR-based Tomcat Native library and enabling SSL

Tomcat 6.x can be turbo-charged by using the Apache Portable Runtime (APR).

The Apache Portable Runtime is a highly portable library that is at the heart of Apache HTTP Server 2.x. APR has many uses, including access to advanced IO functionality (such as sendfile, epoll and OpenSSL), OS level functionality (random number generation, system status, etc), and native process handling (shared memory, NT pipes and Unix sockets). –Apache Tomcat User Guide

The Tomcat native library requires the following three components:

  • APR Library
  • JNI wrappers for APR used by Tomcat (libtcnative)
  • OpenSSL libraries
  1. Download and install the APR 1.4.x library and follow the README instructions. For Mac OS X, I used the following commands from this article.
    # Configure the make file from the download directory
    ./configure
    # Users of 64-bit Java 6 should use the following configure command:
    CFLAGS='-arch x86_64' ./configure
    # Make the library
    make
    # Test the build (Takes a while)
    make test
    # Install APR
    make install
  2. Compile and install the Tomcat native library in the bin directory. Detailed instructions here. For Mac OS X, I used the following commands from this article.
    # Build the make file for Java 5
    ./configure --with-apr=/usr/local/apr --with-ssl=/usr # With SSL
    ./configure --with-apr=/usr/local/apr --without-ssl # Without SSL
    
    # Some have reported having to use the --with-java-home option even with Java 5
    ./configure --with-apr=/usr/local/apr --with-ssl=/usr --with-java-home=/System/Library/Frameworks/JavaVM.framework/Versions/1.5 # With SSL
    ./configure --with-apr=/usr/local/apr --without-ssl --with-java-home=/System/Library/Frameworks/JavaVM.framework/Versions/1.5 # Without SSL
    
    # Users of 64-bit Java 6 should use the following configure command:
    CFLAGS='-arch x86_64' ./configure --with-apr=/usr/local/apr --with-ssl=/usr/ssl --with-java-home=/System/Library/Frameworks/JavaVM.framework/Versions/1.6
    
    # Make
    make
  3. Install the OpenSSL libraries (if necessary), more details here. It’s already installed on Mac OS X and distributions of Linux.

Okay, if you’re new to OpenSSL, here’s where the missing manual comes in. For testing or development, create self-signed certificates as follows:

openssl req -new -newkey rsa:1024 -nodes -out <tomcat home>conf/ssl/ca/localhost.csr -keyout <tomcat home>conf/ssl/ca/localhost.key

Then create a X.509 certificate:

openssl x509 -trustout -signkey <tomcat home>conf/ssl/ca/ca.key -days 365 -req -in <tomcat home>conf/ssl/ca/localhost.csr -out <tomcat home>conf/ssl/ca/localhost.pem

Edit the context.xml file in the conf directory (<tomcat home>conf). See Tomcat’s SSL documentation for more details.

<!-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
<Connector protocol="org.apache.coyote.http11.Http11AprProtocol"
 port="8443" maxThreads="200"
 scheme="https" secure="true" SSLEnabled="true"
 SSLCertificateFile="${catalina.base}/conf/ssl/ca/localhost.pem"
 SSLCertificateKeyFile="${catalina.base}/conf/ssl/ca/localhost.key"
 SSLProtocol="TLSv1"/>

Shutdown and start Tomcat and you should see the following line:
INFO - Loaded APR based Apache Tomcat Native library 1.1.16.

I hope helps you smoothly transition to the Tomcat native library.

Advertisements
Installing the APR-based Tomcat Native library and enabling SSL

Java SSL: How to accept a self-signed certificate

I’ve been working on a RESTful API for use on computers and mobile devices. I have a JUnit test case that connects to the URLs and reads the responses. Given the nature of the data being transferred back and forth, I enabled SSL on the web server using a self-signed certificate I generated using Java’s keytool.

keytool -genkey -alias <hostname> -keyalg RSA

This is where my problems began. My test case is using HTTP, so I needed to refactor it to use the HTTPS protocol. Unbeknownst to me, accepting SSL connections from self-signed certificates is non-trivial, especially if you want to do it right. There is copious advice on the inter-web about how to accept any certificate. I’m not keen on that approach; therefore, I set out to find the correct way.

Without a decent Java security reference handy, I surfed the internet for answers. I found partial code snippets on stackoverflow and Example Depot. In a nutshell, I found that you need an instance of a SSLSocketFactory to set in a HttpsURLConnection. Here’s how:

// Load the keystore in the user's home directory
File file = new File(System.getProperty("user.home") + File.separatorChar + ".keystore");
FileInputStream fis = null;
KeyStore keyStore = null;

fis = new FileInputStream(file);
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(fis, keystorePassword.toCharArray());

TrustManagerFactory tmf;

tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, tmf.getTrustManagers(), null);

//Get an instance of the socket factory
SSLSocketFactory sslFactory = ctx.getSocketFactory();

HttpsURLConnection connection = null;
url = new URL(newURLString);

connection = (HttpsURLConnection)url.openConnection();

//set the socket factory in the connection
connection.setSSLSocketFactory(sslFactory);

//...

Tip: Remember the alias created in the keytool must be the hostname of the server. Otherwise, an exception will be thrown on the client:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching <alias> found
Java SSL: How to accept a self-signed certificate