TLS/SSL avec Tomcat

TLS/SSL permet de sécuriser les communications réseau grâce à un chiffrement basé sur un échange de clés.

Séquence TLS

Pour arriver à ce but avec Tomcat, il faut configurer un connecteur avec un certificat.

conf/server.xml
  <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true">
    <SSLHostConfig>
      <Certificate .../>
    </SSLHostConfig>
  </Connector>

Il y a plusieurs façon de faire avec Tomcat. Dans un premier temps, il faut choisir l’implémentation du coté du connecteur, entre JSSE et OpenSSL. Ensuite, on peut avoir le choix du format du certificat, entre JKS, PKCS#12 et PKCS#8/PEM. Enfin, il faut choisir l’outil pour générer ces certificats, essentiellement entre keytool et openssl.

Le contenu de cette page a été rédigé et testé avec Tomcat 11.0.

Implémentation TLS

Lorsqu’on configure le connecteur, on doit dans tous les cas activer l’attribut SSLEnabled="true", et on peut choisir l’implémentation TLS entre JSSE et OpenSSL.

JSSE

L’implémentation TLS par défaut dépend de la présence de la librairie native de Tomcat.

Sans librairie native, JSSE, Java Secure Socket Extension, est utilisée. Tout le traitement TLS est pris en charge par les classes du JDK, il n’y a pas de dépendance externe.

L’extrait de configuration ci-dessus est l’équivalent du suivant :

conf/server.xml
  <Connector
      port="8443" protocol="HTTP/1.1" SSLEnabled="true"
      sslImplementationName="org.apache.tomcat.util.net.jsse.JSSEImplementation">
    ...
  </Connector>

OpenSSL

Avec la librairie native, l’implémentation OpenSSL est utilisée. Le traitement TLS est délégué aux librairies natives de Tomcat et d’OpenSSL. Il faut donc qu’elles soient installées sur la machine. Cette configuration remplace le connecteur APR (org.apache.coyote.http11.Http11AprProtocol) qui a existé jusqu’à Tomcat 10.0.

L’extrait de configuration ci-dessus est équivalement à :

conf/server.xml
  <Connector
      port="8443" protocol="HTTP/1.1" SSLEnabled="true"
      sslImplementationName="org.apache.tomcat.util.net.openssl.OpenSSLImplementation">
    ...
  </Connector>

Lorsque la librairie native est présente, on peut forcer l’utilisation de l’implémentation JSSE. L’inverse n’est pas vrai puisque s’il n’y a pas de librairie native, on ne peut pas utiliser OpenSSL.

Installation de tcnative

Pour installer les librairies natives, on peut généralement installer certaines dépendances depuis les dépots, mais la librairie libtcnative doit être compilé pour bénéficier d’une version récente.

Par exemple pour Fedora, on peut utiliser le script suivant :

build-tcnative.sh
#!/bin/bash
# Script pour Fedora : installer et compiler Tomcat Native (APR + OpenSSL)
set -e

# Variables
TOMCAT_NATIVE_VERSION="2.0.9"
INSTALL_PREFIX="/usr/local/tomcat-native"
JAVA_HOME=$(dirname $(dirname $(readlink -f $(which java))))

# Installer les dépendances
sudo dnf install -y gcc make wget tar apr-devel openssl-devel

# Créer un dossier temporaire pour la compilation
TMPDIR=$(mktemp -d)
cd $TMPDIR

# Télécharger les sources Tomcat Native
wget https://downloads.apache.org/tomcat/tomcat-connectors/native/${TOMCAT_NATIVE_VERSION}/source/tomcat-native-${TOMCAT_NATIVE_VERSION}-src.tar.gz
tar xzf tomcat-native-${TOMCAT_NATIVE_VERSION}-src.tar.gz
cd tomcat-native-${TOMCAT_NATIVE_VERSION}-src/native

# Configurer la compilation
./configure --with-ssl=/usr/include/openssl
            --with-apr=/usr/bin/apr-1-config
            --with-java-home=$JAVA_HOME
            --prefix=$INSTALL_PREFIX

# Compiler et installer
make
sudo make install

# Ajouter la librairie à LD_LIBRARY_PATH
echo "export LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:$INSTALL_PREFIX/lib" | sudo tee /etc/profile.d/tomcat-native.sh
source /etc/profile.d/tomcat-native.sh

# Nettoyer le dossier temporaire
cd
rm -rf $TMPDIR

echo "Tomcat Native Library installée dans $INSTALL_PREFIX"

Pour Debian ou Ubuntu, le script est similaire excepté pour l’installation des dépendances.

sudo apt update
sudo apt install -y build-essential wget tar libapr1-dev libssl-dev pkg-config

Il faut aussi noter que le listener APR est nécessaire pour que la librairie native soit détectée et chargée.

conf/server.xml
  <Listener className="org.apache.catalina.core.AprLifecycleListener" />

Si l’installation de tcnative a bien fonctionné et que le listener est bien configuré, on devrait avoir les messages suivants au démarrage de Tomcat:

...
00:00:00.120 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent
        Loaded Apache Tomcat Native library [2.0.9] using APR version [1.7.6].
00:00:00.125 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL
        OpenSSL successfully initialized [OpenSSL 3.5.4 30 Sep 2025]
...

Format du certificat

Type du fichier de clés

Le connecteur peut utiliser deux types de keystores, JKS et PKCS#12. JKS signifie Java KeyStore et c’est un format interne au JDK. Depuis le JDK 11, le format standard PKCS#12 doit être privilégié.

Ces deux formats ont des similitudes. Ils se présentent sous forme de fichiers keystore, qui contiennent plusieurs entrées, chacune contenant une clé privée, une clé publique et un certificat.

conf/server.xml
  <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true">
    <SSLHostConfig>
      <Certificate certificateKeystoreFile="conf/sewa.p12"
                   certificateKeystorePassword="sewapwd" />
    </SSLHostConfig>
  </Connector>

Le chemin de certificateKeystoreFile est absolu ou relatif à la racine de Tomcat. Comme on n’a pas renseigné certificateKeyAlias, le connecteur utilise la première entrée du fichier.

On peut aussi configurer le connecteur avec des fichiers séparés pour la clé privée et le certificat / clé publique. Les fichiers sont alors au format PEM.

conf/server.xml
  <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true">
    <SSLHostConfig>
        <Certificate certificateFile="conf/sewa.cert"
                     certificateKeyFile="conf/sewa.key"
                     certificateKeyPassword="sewapwd" />
    </SSLHostConfig>
  </Connector>

Les mêmes formats de fichiers sont supportés par les implémentations JSSE et OpenSSL.

Type de clé

L’attribut type de l’élément <Cetificate> fait référence au type de clé. Il n’est généralement pas nécessaire de le renseigner car détecté à la lecture.

Les types les plus couramment utilisés sont RSA ou EC, pour elliptic curve.

Outils

On a à notre disposition essentiellement deux outils pour générer les clés et certificats, il s’agit de keytool qui fait partie du JDK et du classique openssl. Il y a d’autres outils, qui sont généralement basés sur l’un des deux précédents.

keytool

Le keystore est un fichier qui stocke un ensemble de couples de clés privée/publique, auxquels on attache des certificats. Pour générer un keystore au format JKS ou PKCS#12, on utilise keytool, qui s’installe avec le JDK.

~$ keytool -genkeypair                                                \
           -keystore sewa.jks -storepass sewapwd -storetype JKS       \
           -alias sewatech-fr -keypass sewapwd -keyalg RSA            \
           -dname "cn=www.sewatech.fr, o=Sewatech, c=FR"

Cette commande va générer une clé pour le site www.sewatech.fr. Si le fichier sewa.jks existe déjà, la nouvelle clé est ajoutée, sinon le fichier est créé pour cette première clé.

Sa variante pour PKCS#12 est très semblable, et comme c’est le format par défaut, on peut omettre le paramètre -storetype. Et comme le format ne supporte pas les mots de passe sur les entrées, on peut aussi omettre -keypass.

~$ keytool -genkeypair                                                \
           -keystore sewa.p12 -storepass sewapwd                      \
           -alias sewatech-fr -keyalg RSA                             \
           -dname "cn=www.sewatech.fr, o=Sewatech, c=FR"

Pour générer une clé elliptic curve, il faut juste changer la valeur de keyalg : -keyalg EC.

En l’état, la clé est auto-signée, c’est-à-dire qu’aucune autorité, autre que l’auteur lui-même, n’a certifié la validité de la clé. Les navigateurs refusent donc d’établir une connexion sécurisée avec le site qui produit la clé, sauf si on lui demande explicitement d’accepter, via une gestion des exceptions. La solution pour rassurer le navigateur, est de faire certifier la clé par une autorité tierce.

La demande de certificat est un fichier au format PKCS#10 généré à partir de la clé.

~$ keytool -certreq                                                  \
           -keystore sewa.p12 -storepass sewapwd                     \
           -alias sewatech-fr -file sewatech.csr

Le fichier csr doit ensuite être envoyé à l’autorité de certification (CA) qui retournera un certificat X.509 ou une chaîne de certificats. Un certificat est produit pour valider les informations du propriétaire de la clé ; ce certificat fait référence à un certificat parent qui valide les informations de l’autorité. Ces certificats peuvent être attachés les uns aux autres à plusieurs niveaux, formant une chaîne. Le certificat, ou la chaîne, sont au format PKCS#7 ou PEM, ces deux formats étant supportés par keytool. Si l’autorité retourne le certificat sous un autre format, il faut le transformer à l’aide d’un outil comme OpenSSL.

En possession d’un certificat au bon format, nous pouvons à présent l’importer et l’attacher à notre clé.

~$ keytool -importcert                                             \
           -keystore sewa.p12 -storepass sewapwd                   \
           -alias sewatech-fr -file sewatech.cer

Si le nom de domaine correspond bien au CN de la clé et si l’autorité qui a certifié notre clé a été déclarée dans sa configuration, le navigateur acceptera de naviguer par TLS.

openssl

OpenSSL est l’outil pour créer des clés et certificat PKCS#8, encodés en PEM. Comme pour les autres formats, on peut choisir le type, entre RSA et EC.

# Génération de la clé privée RSA, avec mot de passe
~$ openssl req -newkey rsa -keyout sewa.key -x509 -out sewa.cert   \
               -subj "/CN=sewatech.fr" -passout pass:sewapwd

ou

# Génération de la clé privée EC, avec mot de passe
~$ openssl req -newkey ec -keyout sewa.key -x509 -out sewa.cert    \
               -pkeyopt ec_paramgen_curve:prime256v1               \
               -subj "/CN=sewatech.fr" -passout pass:sewapwd

OpenSSL peut aussi créer des keystores au format PKCS#12, à partir des fichiers créés précédemment. Et l’outil ne peut créer que des keystores avec une seule entrée.

# Génération du keystore PKCS#12, avec mot de passe
~$ openssl pkcs12 -inkey sewa.key -in sewa.cert                    \
                  -export -out sewa.p12 -passin pass:sewapwd       \
                  -password pass:sewapwd

Synthèse

Depuis Tomcat 10.1, il n’y a plus cette distinction au niveau du protocole du connecteur. C’est au niveau de l’implémentation qu’on choisit entre JSSE ou OpenSSL.

Les deux implémentations supportent les formats JKS, PKCS#12 et PKCS#8/PEM.

L’outillage tourne autour de keytool pour JKS et PKCS#12, et d'`openssl` pour PKCS#12 et PKCS#8/PEM, en RSA ou EC.