Tomcat and SSL

# Tomcat SSL Configuration

Authors:
Henri Gomez | `<hgomez@slib.fr>`
Christopher Cain | `<ccain@apache.org>`
Eric Rescorla | `<ekr@rtfm.com>`

## Table of Contents

- Introduction to SSL
- Tomcat and SSL
- Certificates
- Building Tomcat with SSL support
- Tomcat with Apache and mod_jk
- SSL via Apache
- SSL Standalone
- General Tips on Running SSL
- Troubleshooting SSL Standalone
- Credits

## Introduction to SSL

SSL, or Secure Sockets Layer, is a technology which allows web browsers and web servers to communicate over a secured connection. This means that the data being sent is encrypted by one side, transmitted, then decrypted by the other side prior to any processing. This is a two-way process, meaning that both the server and the browser encrypt all traffic before sending out data.

Another important aspect of the SSL protocol is Authentication. This means that during your initial attempt to communicate with a web server over a secure connection, that server will present your web browser with a set of credentials, in the form of a Certificate, as proof that the site is who and what it claims to be. In certain cases, the server may also request a certificate from your web browser, asking for proof that you are who you claim to be. This is known as Client Authentication, although in practice it is used primarily for business-to-business (B2B) transactions rather than with typical site users. Most SSL-enabled web servers do not request Client Authentication.

## Tomcat and SSL

It is important to note that configuring Tomcat to take advantage of secure sockets is usually only necessary when running it as a standalone web server. When running Tomcat primarily as a Servlet/JSP container behind another web server, such as Apache or Microsoft IIS, it is usually necessary to configure the primary web server to handle the SSL connections from users. Typically, this server will negotiate all SSL-related functionality, then pass on any requests destined for the Tomcat container only after decrypting those requests. Likewise, Tomcat will return cleartext responses, which will then be encrypted by the primary server before being returned to the user's browser. In this environment, Tomcat knows that communications between the primary web server and the client are taking place over a secure connection (because your application needs to be able to ask about this), but it does not participate in the encryption or decryption itself.

Information on configuring Apache for SSL can be found at either the Apache-SSL pages, or the apache-mod_ssl project. For information on configuring Tomcat to communicate with an SSL-enabled Apache server, see the Tomcat with Apache and mod_jk section.
Note: SSL with Tomcat standalone requires JDK 1.2 or greater.

## Certificates

In order to implement SSL, a web server must have an associated certificate for each external interface (IP address) that accepts secure connections. The theory behind certificates is that a server should provide some kind of reasonable assurance that its owner is who you think it is, particularly before receiving any sensitive information. While a broader explanation of certificates is beyond the scope of this document, think of a certificate as a digital "driver's license" for an Internet address. It states what company a site is associated with, along with some basic contact information about the site's owner and/or administrator.

This "driver's license" is cryptographically signed by its issuer, and is therefore extremely difficult for anyone else to forge. For sites involved in e-commerce, or any other business transaction in which authentication of identity is important, a certificate is typically purchased from a well-known Certificate Authority (CA) such as VeriSign or Thawte. Such certificates can be electronically verified --- in effect, the CA will vouch for the authenticity of the certificates that it grants, so you can, ostensibly, trust that a given certificate is valid if you trust the CA who granted it.

In many cases, however, authentication is not really a concern. An administrator may simply want to ensure that the data being transmitted and received by the server is private and cannot be snooped by anyone who may be eavesdropping on the connection. In such cases one is often tempted to use a "self-signed certificate"--one which has been signed only by the owner. Such a certificate obviously doesn't provide any guarantee of who the certificate owner is; there's nothing stopping me from making myself a certificate claiming to be George W. Bush.

What's less obvious is that using such certificates weakens the secrecy of your data as well. The attack works like this: when the client attempts to connect to the server the attacker hijacks the connection. He sends the client his own self-signed certificate which has the same name as that in the server's self-signed certificate. The attacker then connects to the real server himself. When the client sends data to the server the attacker reads it and then sends it along to the real server. This is called a man-in-the-middle attack.

The take-home message is that if you're worried about attackers who can write data to the network (this is called an active attack) then self-signed certificates won't protect you. If you're worried about attackers who can only read data off the network (this is called a passive attack) then self-signed certificates work fine. In general, you should worry about active attack and so self-signed certificates aren't that good.

Nevertheless, self-signed certificates are fantastically useful for testing and they are easily created with Java's `keytool` program or using OpenSSL.

## Building Tomcat with SSL support

If you want to build Tomcat with support for SSL, be careful of your classpath. I usually clear the `CLASSPATH` environment variable in order to avoid possible conflicts in jars. A common case of conflict is for XML parsers (xerces & jaxp). Tomcat required a recent XML parser, such as Apache Group's Xerces or Sun's JAXP.

You now have two options for building Tomcat with SSL support: Sun's JSSE and Claymore Systems's PureTLS. The functionality that they offer is roughly equivalent. The primary relevant difference is in licensing: PureTLS is open source (BSD-style license) and JSSE is closed source. Therefore, if you want to redistribute compiled versions of Tomcat or just look at the source of your SSL/TLS implementation you must use PureTLS.

At build time (via Ant), Tomcat will automatically build as much SSL support as it can. If you have both PureTLS and JSSE in your `CLASSPATH`, Tomcat will automatically build with support for both. At run time, Tomcat will automatically select whatever library is present (if both are present, PureTLS will be selected). You can control which implementation is used via configuration file.

## Tomcat with Apache and mod_jk

If you use Apache with SSL (apache-ssl or apache-mod_ssl), the Apache connector mod_jk will be able to forward Tomcat SSL information if the JkExtractSSL directive is present in your httpd.conf.

Forwarded SSL Information is:

HTTPS | Apache Redirect to Tomcat from an SSL Area
SSL_SESSION_ID | SSL session ID
SSL_CIPHER | SSL CIPHER used
SSL_CLIENT_CERT | SSL Certificate of client

Since apache-ssl and apache-mod_ssl use different environment variables, you can adapt SSL variables via the following JK vars:

- JkExtractSSL
- JkHTTPSIndicator
- JkSESSIONIndicator
- JkCIPHERIndicator
- JkCERTSIndicator:

Here is an example of some directives to include in httpd.conf for use with mod_ssl:

# Should mod_jk send SSL information to Tomcat (default is On)
JkExtractSSL On
# What is the indicator for SSL (default is HTTPS)
JkHTTPSIndicator HTTPS
# What is the indicator for SSL session (default is SSL_SESSION_ID)
JkSESSIONIndicator SSL_SESSION_ID
# What is the indicator for client SSL cipher suit (default is SSL_CIPHER)
JkCIPHERIndicator SSL_CIPHER
# What is the indicator for the client SSL certificated (default is SSL_CLIENT_CERT)
JkCERTSIndicator SSL_CLIENT_CERT

When using mod_jk with Apache & mod_ssl, it is essential to specify "SSLOptions +StdEnvVars +ExportCertData" in the httpd.conf file.
Otherwise, mod_ssl will not produce the neccessary environment variables for mod_jk. (Tilo Christ <tilo.christ@med.siemens.de>).

Warning, even though mod_jk supports both ajp12 (an old version from ApacheJServ) and ajp13, only ajp13 can forward SSL information to Tomcat.

## SSL via Apache

mod_jk supports the VirtualHost directive of Apache. This is especially useful when using Apache mod_ssl with Tomcat.
The following configuration will easily secure your webapps via Apache SSL support (be careful when setting these jk variables outside VirtualHost directives):

JkWorkersFile /etc/httpd/conf/workers.properties
JkLogFile /var/log/httpd/mod_jk.log
JkLogLevel warn

The jk redirect stuff can be set in virtual hosts:

<VirtualHost _default_:443>
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXP56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL

# other SSL stuff

Alias /alesia "/var/tomcat/webapps/alesia"
<Directory "/var/tomcat/webapps/alesia">
Options Indexes FollowSymLinks
</Directory>

JkMount /alesia/servlet/* ajp13
JkMount /alesia/*.jsp ajp13
<Location "/alesia/WEB-INF/">
AllowOverride None
Deny from all
</Location>

</VirtualHost>

## SSL Standalone

In order to configure Tomcat standalone for SSL support, you need to create (or import) an SSL certificate. For more information about SSL and certificates, you might find the following resources helpful:

- OpenSSL (Open Source SSL implementation)
- ModSSL (SSL support for Apache)
- Cryptix (Open Source Java crypto library)

If you have either PureTLS or JSSE installed, you might as well use that for your SSL support. If you have neither installed, you will need to download and install one of them.

## SSL Support with JSSE

### Download and Install JSSE

### 1. Download and Install JSSE

Download the Java Secure Socket Extensions (JSSE) package, version 1.0.2 or later, from http://java.sun.com/products/jsse/ . If you are running JDK 1.4 (currently in beta), these classes have been integrated directly into the JDK, so you can skip this entire step.
After expanding the package, there are two ways to make it available to Tomcat (choose one or the other):

- You can make JSSE an installed extension by copying all three JAR files (`jcert.jar`, `jnet.jar`, and `jsse.jar`) into your `$JAVA_HOME/jre/lib/ext` directory.
- Alternatively, you can make these jars available via the classpath that is passed to Tomcat on startup. This will need to be done in the appropriate startup script for your environment ( `$TOMCAT_HOME/bin/tomcat.sh` in Unix, or `%TOMCAT_HOME%\bin\tomcat.bat` in Windows).

Note: The system classpath is effectively ignored by Tomcat, so including the JSSE jars there will not make them available for use by the Tomcat engine during runtime (although it will not conflict with the two methods described above if they do happen to be in the system classpath). Also, do not copy these jars into any of the internal Tomcat repositories (the `$TOMCAT_HOME/lib/*` directories, individual webapp directories, etc.). Doing so may cause Tomcat to fail, as these libraries should only be loaded by the system classloader.

### 2. Prepare the Certificate Keystore

Note: In order to execute the `keytool` command-line utility, the JSSE jars must be either in the classpath or an installed extension.
A "keystore" is essentially just a repository file for cryptographic objects, such as keys and certificates. Tomcat currently operates only on `JKS` format keystores. This is Java's standard "Java KeyStore" format, and is the format created by the `keytool` command-line utility. This tool is included in the JDK.
To create a new keystore from scratch, containing a single self-signed certificate, execute the following from a terminal command line:

> `%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA` (Windows)
> `$JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA` (Unix)

(The RSA algorithm should be preferred as a secure algorithm, and also to ensure general compatibility with other servers and components such as Netscape and IIS.)
This command will create a new file, in the home directory of the user under which you run it, named "`.keystore`". To specify a different location or filename, add the `-keystore` parameter, followed by the complete pathname to your keystore file, to the `keytool` command shown above. For example:

> `%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA \ -keystore /path/to/my/keystore` (Windows)
> `$JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA \ -keystore /path/to/my/keystore` (Unix)

After executing the `keytool` command, you will first be prompted for the keystore password. The default password used by Tomcat is "`changeit`" (all lower case), although you can specify a custom password if you like. Again, this will need to be reflected in the `server.xml` configuration file.
`[root@www.vercingetorix.org /root]# $JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA`
`Enter keystore password: changeit`
`What is your first and last name?`
`[Unknown]: www.vercingetorix.org`
`What is the name of your organizational unit?`
`[Unknown]: Chief`
`What is the name of your organization?`
`[Unknown]: Gaulois`
`What is the name of your City or Locality?`
`[Unknown]: Alesia`
`What is the name of your State or Province?`
`[Unknown]: 50`
`What is the two-letter country code for this unit?`
`[Unknown]: FR`
`Is <CN=www.vercingetorix.org, OU=Chief, O=Gaulois, L=Alesia, ST=50, C=FR> correct?`
`[no]: yes`
Finally, you will be prompted for the key password, which is the password specifically for this Certificate (as opposed to any other Certificates stored in the same keystore file). You MUST use the same password here as was used for the keystore password itself. (Currently, pressing the ENTER at this prompt will automatically do this.)
To import an existing certificate into a JKS keystore:
It is possible to import certificates generated with OpenSSL. Here are the steps needed to generate such certs with OpenSSL :

- To generate a new request and a new key

    openssl req -new -out REQ.pem -keyout KEY.pem

- To generate a self signed x509 certificate from a certificate request using a supplied key, and we want to see the text form of the output certificate (which we will put in the file selfSign.pem)

    openssl req -x509
    -in REQ.pem -key KEY.pem -out CERT.pem

- Verify that the signature is correct on a certificate request.

    openssl req -verify
    -in REQ.pem

- Verify that the signature was made using a specified public key

    openssl req -verify
    -in REQ.pem -key KEY.pem

- Print the contents of a certificate request

    openssl req -text
    -in REQ.pem

- To import the CERT in keystore, you just do next :

    keytool -import
    -v -trustcacerts -alias tomcat -file

    CERT.pem

For more information, please read the documentation (in your JDK documentation package) about `keytool`.

## SSL Support with PureTLS

### 1. Downloading and Installing PureTLS

The easiest way to download PureTLS is by simply downloading the prebuilt version from http://www.rtfm.com/puretls/prebuilt.html. This version contains all the jar files you will need in order to use PureTLS in one package. After expanding the package, there are two ways to make it available to Tomcat (choose one or the other):

- You can make PureTLS an installed extension by copying all three JAR files (`cryptix32.jar`, `puretls.jar`, and `cryptix-asn1.jar`) into your `$JAVA_HOME/jre/lib/ext` directory.
- Alternatively, you can make these jars available via the classpath that is passed to Tomcat on startup. This will need to be done in the appropriate startup script for your environment ( `$TOMCAT_HOME/bin/tomcat.sh` in Unix, or `%TOMCAT_HOME%\bin\tomcat.bat` in Windows).

Note: The system classpath is effectively ignored by Tomcat, so including the PureTLS jars there will not make them available for use by the Tomcat engine during runtime (although it will not conflict with the two methods described above if they do happen to be in the system classpath). Also, do not copy these jars into any of the internal Tomcat repositories (the `$TOMCAT_HOME/lib/*` directories, individual webapp directories, etc.). Doing so may cause Tomcat to fail, as these libraries should only be loaded by the system classloader.

Alternately, you can download the PureTLS source distribution from http://www.rtfm.com/puretls and build it yourself. You will also need to install Cryptix 3.2 from http://www.cryptix.org/. Once you've built Cryptix and PureTLS, install them as described above.

### 2. Obtaining Keys and Certificates

PureTLS uses OpenSSL-style keyfiles. If you have an OpenSSL key you can simply copy it somewhere and point Tomcat at it. Sometimes when people use OpenSSL they store their keys and certificates in separate files, such as `key.pem` and `cert.pem`. PureTLS expects a single file which you can create by just concatenating the two files. For instance: `cat key.pem cert.pem > keyfile.pem`.

PureTLS does not currently allow you to make self-signed certificates. However, a number of sample certificate files are included in the PureTLS distribution. For testing purposes you can use the file `rsa-server.pem which has the password `password.``

Finally, PureTLS allows you to create a certificate request using the `COM.claymoresystems.ptls.cert.CertRequest` class. With PureTLS in your classpath, execute `COM.claymoresystems.cert.CertRequest <keyfile-name> RSA`. Then type your keyfile password on the console (currently this is echoed which is rather a bug). PureTLS will think for a while and then generate a key in `keyfile-name`. The certificate request (in Netscape format) will be printed on the screen and can be cut and pasted into your CA's web page. When you get your certificate attach it to the end of your keyfile.

### 3. Trust Management for Client Authentication

If you intend to require your clients to authenticate with certificates you will need to decide what CAs you trust. PureTLS gets this information from a root file which is just the concatenation of the trusted root CA certificates. You specify that file to Tomcat using the `rootlist` attribute in the configuration file.

### 3. Edit the Tomcat configuration file

To configure a secure (SSL) HTTP connector for Tomcat, verify that it is activated in the `$TOMCAT_HOME/conf/server.xml` file (the standard version of this file, as shipped with Tomcat, contains a simple example which is commented-out by default).

> Syntax for Tomcat 3.2 :

> `<Connector className="org.apache.tomcat.service.PoolTcpConnector">`
> `<Parameter name="handler" value="org.apache.tomcat.service.http.HttpConnectionHandler"/>`
> `<Parameter name="port" value="8443"/>`
> `<Parameter name="socketFactory" value="org.apache.tomcat.net.SSLSocketFactory" />`
> `<Parameter name="keystore" value="/var/tomcat/conf/keystore" />`
> `<Parameter name="keypass" value="mynewpass"/>`
> `<Parameter name="clientAuth" value="false"/>`
> `</Connector>```

> Syntax for Tomcat 3.3 :

> `<Http10Connector`
> `port="8443"`
> `secure="true"`
> `keystore="/var/tomcat/conf/keystore"`
> `keypass="mynewpass"`
> `clientauth="false" />`

In the above examples, we indicate that the keystore is file located at `/var/tomcat/conf/keystore`, and the password if "mynewpass". Again, these attributes can be skipped if the Tomcat defaults were used. Also, we specified that we don't want to enforce client authentication. Also, note the case difference between Tomcat 3.2 and Tomcat 3.3 (i.e. "clientAuth" versus "clientauth").

By default, Tomcat chooses whatever SSL implementation is available, with preference given to PureTLS over JSSE if both are available. You can specify the exact implementation you want using the `SSLImplementation` parameter, like so:

`<Http10Connector`
`port="8443"`
`secure="true"`
`keystore="/var/tomcat/conf/keystore"`
`keypass="mynewpass"`
`clientauth="false"`
`SSLImplementation="org.apache.tomcat.util.net.PureTLSImplementation"` />

`SSLImplementation` can be the name of any class that implements `org.apache.tomcat.util.net.SSLImplementation`. The values built into Tomcat are `org.apache.tomcat.util.net.PureTLSImplementation` for PureTLS and `org.apache.tomcat.util.net.JSSEImplementation` for JSSE.

## General Tips on Running SSL

The first time a user attempts to access a secured page on your site, he or she is typically presented with a dialog containing the details of the certificate (such as the company and contact name), and asked if he or she wishes to accept the certificate as valid and continue with the transaction. Some browsers will provide an option for permanently accepting a given certificate as valid, in which case the user will not be bothered with a prompt each time they visit your site. Other browsers do not provide this option. Once approved by the user, a certificate will be considered valid for at least the entire browser session.

Also, while the SSL protocol was designed to be as efficient as securely possible, encryption/decryption is a computationally expensive process from a performance standpoint. It is not strictly necessary to run an entire web application over SSL, and indeed a developer can pick and choose which pages require a secure connection and which do not. For a reasonably busy site, it is customary to only run certain pages under SSL, namely those pages where sensitive information could possibly be exchanged. This would include things like login pages, personal information pages, and shopping cart checkouts, where credit card information could possibly be transmitted. Any page within an application can be requested over a secure socket by simply prefixing the address with `https:` instead of `http:`. Any pages which absolutely require a secure connection should check the protocol type associated with the page request and take the appropriate action if the `https` protocol is not specified.

## Troubleshooting SSL Standalone

Here is a list of common problems that you may encounter when setting up Tomcat standalone for SSL, and what to do about them.

- I am seeing "java.security.NoSuchAlgorithmException" errors.

  > The JVM cannot find the JSSE JAR files, or there was a problem in loading the JSSE Provider. Please ensure that the JSSE jars have been appropriately installed.

- When Tomcat starts up, I get an exception like "java.io.FileNotFoundException: {some-directory}/{some-file} not found".

  > A likely explanation is that Tomcat cannot find the keystore file where it is looking. By default, Tomcat expects the keystore file to be named `.keystore` in the user home directory under which Tomcat is running (which may or may not be the same as yours :-). If the keystore file is anywhere else, you will need to add the `keystore` parameter/attribute to the secure connector in the Tomcat configuration file (as outlined in the Standalone SSL section).

- When Tomcat starts up, I get an exception like "java.io.FileNotFoundException: Keystore was tampered with, or password was incorrect".

  > Assuming that someone has not actually tampered with your keystore file, the most likely cause is that Tomcat is using a different password than the one you specified when creating the keystore file. To fix this, you can either recreate the keystore file, or you can add/update the `keypass` parameter/attribute on the secure connector in the Tomcat configuration file (as outlined in the Standalone SSL section).

  > REMINDER - Passwords are case sensitive!

If you are still having problems, a good source of information is the TOMCAT-USER mailing list. You can find pointers to archives of previous messages on this list, as well as subscription and unsubscription information, at http://jakarta.apache.org/site/mail.html.

## Credits

This document was written by Henri Gomez, Christopher Cain and Eric Rescorla. Thanks to both Tilo Christ <tilo.christ@med.siemens.de> and hgopal@cmcltd.com for additional contributions.

Copyright ©1999-2001 The Apache Software Foundation Legal Stuff They Make Us Say Contact Information