Crypter sur le Web

Le SSL est tous les jours dans notre vie

Le SSL prend une place de plus en plus importante dans l’ensemble des logiciels désirants accéder à un certain niveau de sécurité. Ces niveaux peuvent aller d’une simple authentifications applicative à de véritables VPN (Virtual Private Network) construit grâce à une double encapsulation SSL. Comment fonctionnent de telles architectures, quelle technique se cache derrière ces noms, comment les mettre en œuvre ? Ce sont des questions auxquelles nous allons essayer d’apporter des explications.

La sécurité regroupe 3 grands principes :

L’application exemple : Le Bureau Web

Le but de l’application BureauWeb est de permettre d’accéder à un ensemble de fonctionnalités du système d’exploitation à partir d’un client Web : Navigateur ou Client Java lourd.

Schéma d’architecture générale de cette application

Cette application va reprendre les 4 grands axes de la sécurité : L’identification est assurée par l’identification applicative du serveur d’application Apache. L’authentification est assurée par un double cryptage SSL : Le premier authentifie le serveur, le second authentifie le client (la partie suivante explique comment un cryptage peut authentifier un tier). L’intégrité est apportée par le cryptage SSL.

La version courante de SSL est 3.0. Il a été standardisé par l’IETF (Internet Engineering Task Force) comme TLS (Transport Layer Security) version 1.0. Il y a peu de changement entre TLS 1.0 et SSL 3.0, mais il c’est une bonne idée de continuer à utiliser SSL 3.0 même vieux, car TLS n’est pas toujours supporté par les navigateurs.

Les pré-requis

Pour mettre en œuvre le tutoriel, vous devez avoir installé les logiciels suivants :

Editeur Logiciel
Sun JDK V1.4.2
(Incluant JSSE V1.02)
Jakarta Apache V2.0.48
OpenSSL OpenSSL V0.9.7.d
Jakarta Tomcat V4.1.27

http://www.javasoft.com/products/jsse/

http://httpd.apache.org/

http://www.openssl.org/

http://jakarta.apache.org/

La version courante de JSSE est V1.02, disponible gratuitement sur le site de SUN. Cette version n’est à télécharger que si vous uiliser un JDK inférieure au V1.4 de SUN.

Attention, OpenSSL n’est pas disponible déjà compilé pour Windows. Il existe cependant des sites permettant de downloader une version compilée de Apache et OpenSSL.

Il vous faut enfin télécharger le tutoriel ici.

Une fois téléchargé, décompactez-le dans voter répertoire de travail habituel.

Le SSL : Cryptage, mais aussi authentification d’un tiers

Imaginons un serveur et un client, ça c’est facile. Le client veut être sûr que c’est bien le serveur qu’il connaît qui est en train de lui parler. Comment faire ? La réponse est simple, c’est SSL.

Son fonctionnement est le suivant : Imaginer un algorithme capable de générer une clef capable de chiffrer un message et un autre clef capable de le déchiffrer. Nous obtenons une clé publique, capable de chiffrer et une clef privée, capable de déchiffrer.

Utilisons maintenant ces clés de la façon suivante :

Fonctionnement de SSL

Détail :

  1. Le serveur envoie un message crypté ( le coffre ) avec sa clé publique.
  2. Le client reçoit ce coffre et ajoute la clef publique à la liste des personnes de confiance. Il peut alors ouvrir la fente pour y glisser son message. Il ne peut que crypter, et pas décrypter : il peut donc créer ou ajouter un message, mais pas les lires. Le client n’a plus qu’à renvoyer le coffre au serveur.
  3. Le serveur reçoit le coffre et peut l’ouvrir pour prendre le message : le décrypter avec la clé privée.

Comment le client est sûr que c’est bien le serveur qui lui a envoyé sa clé publique ? C’est le rôle d’un organisme de confiance, externe aux deux partenaires qui s’en charge. Des sociétés comme "Verify", ou autres, vendent des jeux de clé avec des durées de validités.

Le client est ainsi certain que le serveur récupérant sont message sera le seul à pouvoir le décoder, puisqu’il est le seul à avoir la clé privée. La confidentialité de cette clé privée est donc très importante.

Ce fonctionnement est le plus répandu sur le Web, il porte le nom d’authentification serveur. Il permet uniquement au client de s’assurer qu’il dialogue bien avec le serveur qu’il pense. Il est également possible de créer une authentification cliente, qui fonctionne exactement sur le même principe. Le serveur est alors sûr que c’est bien ce client avec qui il dialogue. L’utilisation d’une authentification serveur et cliente en simultanée permettent de créer ce qu’on appel un VPN applicatif.

Pour comprendre les documents techniques, voici le lien entre la vulgarisation ci-dessus et les termes techniques :

Certificat : Clé publique ou Public Key, plus des Infos (Nom client, organisme de certification, etc)

La clé privée est aussi appelée Private Key.

Les clés publique sont stockées dans un magasin dit de confiance ou un TrustStore. Les clés privée sont stockées dans un magasin de clés ou KeyStore. Ces magasins sont souvent protégés par des mots de passe.

La gestion des clés dans des magasins ( Store )

Pourquoi des magasins ?

Une clé est un code binaire ressemblant au fichier suivant :

-----BEGIN PRIVATE KEY-----
MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAx07VYA53aD5uP40KM6Ck066LWe/1
utv01pkqLAbncZbvGuklIrfkFsbdDbfkHhrpcGOiVr/s2z4BDC7oDSRGsQIDAQABAkBn4r91ghTb
US9GEM3wextu+tvH1TvQWjYUZWGF8VNR8N7CWyJPkOQPOC/ZSIZiDjN8mnxtC4qFco6rOJyowfPB
AiEA58c6q9sc2QMlLETH0wwfRwSqbf3mfMxQCGsqXBxFzacCIQDcIuzo88RiP2zwUwHQuJ5OSRXx
vhxJ67LySmQNjKND5wIhAMKZEzmXDfFmIp+4X81iMCCAWldfBVVidQ+cakRLuI+hAiAoAVjYhORd
jnU3v34G9mYeh/2q7wepD2J30bkZFUPeZQIgV/K2+suCrLfxwJXY5i48mBHtoBPonYQWfTJebFLk
NoM=-----END PRIVATE KEY-----

Un certificat est un code binaire ressemblant au fichier suivant :

Certificate:
Data:
        Version: 1 (0x0)
Serial Number: 1096999113 (0x4162e0c9)
Signature Algorithm: md5WithRSAEncryption
Issuer: C=FR, ST=IDF, L=Paris, O=PenPen, OU=Bureau Web, CN=travail
Validity
Not Before: Oct 5 17:58:33 2004 GMT
Not After : Jul 26 17:58:33 2007 GMT

Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (512 bit)
Modulus (512 bit):
00:c7:4e:d5:60:0e:77:68:3e:6e:3f:8d:0a:33:a0:
a4:d3:ae:8b:59:ef:f5:ba:db:f4:d6:99:2a:2c:06:
e7:71:96:ef:1a:e9:25:22:b7:e4:16:c6:dd:0d:b7:
e4:1e:1a:e9:70:63:a2:56:bf:ec:db:3e:01:0c:2e:
e8:0d:24:46:b1
Exponent: 65537 (0x10001)
Signature Algorithm:md5WithRSAEncryption
73:22:4c:30:90:bd:70:ec:61:ad:88:86:46:17:3b:cd:19:d7:
77:60:6c:e2:10:ba:62:06:46:7c:5b:80:e3:e8:d6:b8:09:31:
09:87:aa:48:4f:ed:51:61:0d:aa:34:23:17:11:e5:53:35:1a:
85:92:bf:94:84:e2:5d:6f:a5:75
-----BEGIN CERTIFICATE-----
MIIBszCCAV0CBEFi4MkwDQYJKoZIhvcNAQEEBQAwYzELMAkGA1UEBhMCRlIxDDAK
BgNVBAgTA0lERjEOMAwGA1UEBxMFUGFyaXMxDzANBgNVBAoTBlBlblBlbjETMBEG
A1UECxMKQnVyZWF1IFdlYjEQMA4GA1UEAxMHdHJhdmFpbDAeFw0wNDEwMDUxNzU4
MzNaFw0wNzA3MjYxNzU4MzNaMGMxCzAJBgNVBAYTAkZSMQwwCgYDVQQIEwNJREYx
DjAMBgNVBAcTBVBhcmlzMQ8wDQYDVQQKEwZQZW5QZW4xEzARBgNVBAsTCkJ1cmVh
dSBXZWIxEDAOBgNVBAMTB3RyYXZhaWwwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA
x07VYA53aD5uP40KM6Ck066LWe/1utv01pkqLAbncZbvGuklIrfkFsbdDbfkHhrp
cGOiVr/s2z4BDC7oDSRGsQIDAQABMA0GCSqGSIb3DQEBBAUAA0EAcyJMMJC9cOxh
rYiGRhc7zRnXd2Bs4hC6YgZGfFuA4+jWuAkxCYeqSE/tUWENqjQjFxHlUzUahZK/
lITiXW+ldQ==
-----END CERTIFICATE-----

Il est clair qu’il n’est pas facile de manipuler ce type de fichier. Chaque éditeur a donc proposé une solution de stockage de ces clés : des magasins ou des stores. Pour notre application exemple, nous allons utiliser trois types d’implémentations de magasins.

Les besoins de transformation

Notre serveur et nos deux formats de clients utilisant des magasin avec des formats différents, il est indispensable d’expliquer comment générer un couple clé privée et certificat unique pour tous ces formats.

Le seul moyen de conversion que j’ai trouvé est le suivant :

Ordre de génération de chaque format

  1. Création d’un couple certificat et clef privée dans un KeyStore au format JKS
  2. Les certificats sont Self certifiés
  3. Extraction du certificat
  4. Extraction de la clef privée avec un code Java
  5. Encodage du certificat JKS en PEM via le format pivot DER
  6. Encodage du certificat PEM en PKCS12 via le format pivot DER

La génération des clés :

Plan de nommage :

Pour JAVA

Serveur Client
KeyStore JKS jks.server.keystore jks.client.keystore
Password Keystore ****** ******
Alias JKS serveur client
Certificat JKS jks.server.certificat jks.client.certificat
Clef privée jks.AS.key jks.AC.key
Pwd Clef privée ****** ******

Pour OpenSSL

Serveur Client
Certificat PEM pem.AS.certificat pem.AC.certificat
Clef privée PEM pem.AS.key
Pour le navigateur
KeyStore PKCS12 pkcs12.AC.p12
Password ******

Pour le navigateur

Serveur Client
KeyStore PKCS12 pkcs12.AC.p12
Password ******

Schéma général de la génération des clés

Le script d’initialisation de l’environnement : « SetEnvSSL.bat »

Editez ce script et modifier tous les champs pour les adapter à votre configuration :

// Le répertoire d’installation du JDK 1.4.2 :
set JAVA_HOME=C:\java\j2sdk1.4.2\jre
// Le répertoire où seront générées les clés :
set DB_DIR=G:\ssl\Tutoriel\ssl\
// Le répertoire d’installation d’OpenSSL :
set OPENSSL_DIR=c:\java\Apache2\bin\

Il est au moins indispensable de bien préciser le répertoire JAV-HOME, la partie OPENSSL peut ne pas être installée, mais vous ne ferez pas tout le tutoriel.

// Le hostname du serveur :
set HOST_NAME_SERVER="travail"
// Le hostname du client :
set HOST_NAME_CLIENT="travail"

Il est très important de préciser le hostname du serveur et du client, car pour JAVA, le certificat n'est valable que pour un nom de machine qui doit correspondre.

set SERVER_STORE_PWD=******
set SERVER_KEY_PWD=%SERVER_STORE_PWD%
set CLIENT_STORE_PWD=******
set CLIENT_KEY_PWD=%CLIENT_STORE_PWD%

Vous devez modifier ces valeurs pour préciser les mots de passe de chacun de vos magasins. Pour commencer, mettez le même partout.

Enfin, les derniers paramètres permettent d’activer le « debug » :

rem set OPTION_DEBUG_SSL=-Djava.security.debug=all %OPTION_DEBUG_SSL%
rem set OPTION_DEBUG_SSL=-Djavax.net.debug=all %OPTION_DEBUG_SSL%

Ces mode débug sont très verbeux et plutôt présents à titre d’information de ce qui se passe. Le débug sur « security » n’est axé que la sécurité java, qui n’est pas utilisée ici, le « net » est plus intéressant, mais il est difficile de voir su un des caractères de la clé ou du décryptage est bon ou pas …

Le script de création du jeu de clé de base dans les différents formats

Le script « CreateBase.bat » permet de générer les clés pour la configuration suivante :

Exécuter le script « CreateBase.bat » et tapez les réponses suivantes :

...
Trust this certificate? [no]:yes
...
Trust this certificate? [no]:yes
...
Quand il n’y a plus d’activite, appuyer sur une touche space
...
Enter Export Password:client
Verifying - Enter Export Password:client
...

Vous devez avoir généré les clés suivantes :

Le script d’ajout d’un jeu de clé pour un nouveau client dans les différents formats

Pour ajouter un jeu de clé pour un nouveau client, il est possible d’utiliser les scriptes « CreateNewKey.bat ». Bien sûr, il est indispensable de d’ajouter un jeu de clés, une fois le jeu de clés de base déjà créé. Pour enchaîner toutes les créations de jeu de clés, vous pouvez utiliser le script « CreateAll.bat ». Ce script vous créera alors la configuration de clé suivante :

Configuration créée par le script « CreateAll.bat »

Explications sur le script « CreateBase.bat »

Le script est découpé en trois parties distinctes :

  1. La création des clés au format JKS
  2. Le passage par le format pivot DER pour traduire ces clés au format PEM
  3. Le passage par le format pivot DER pour traduire ces clés au format PKCS12

Pour Java

La manipulation des clés au format JKS se fait grâce à l’outil keytool.exe situé dans JAVA_HOME/jre/bin/keytool.exe. La première partie du script suit les étapes suivantes :

Génération d’un couple Clef Privée et son certificat dans JKS

keytool -genkey -v -keystore jks.server.keystore -keyalg rsa -keysize 512
        -alias serveur -storepass ****** -keypass ******
        -dname "CN=travail, OU=Bureau Web, O=PenPen, L=Paris, S=IDF, C=FR"
keytool -genkey -v -keystore jks.client.keystore -keyalg rsa -keysize 512

        -alias client   -storepass ****** -keypass ******

        -dname "CN=travail, OU=Bureau Web, O=PenPen, L=Paris, S=IDF, C=FR"

La taille de la clé est ici de 512 bits. Remarquez l’attribut « CN=travail » portant absolument le nom de la machine qui acceptera le certificat. Nous créons deux jeux de clé : une pour l’authentification du serveur et l’autre pour l’authentification du client.

Auto-certification d’un couple Clef Privée / Certificat dans JKS

keytool -selfcert -alias serveur  -validity 1024 -keypass ******
        -keystore jks.Server.keystore -storepass ****** -v
keytool -selfcert -alias client   -validity 1024 -keypass ******
        -keystore jks.client.keystore -storepass ****** -v

Dans notre exemple, nous n’allons pas signer nos certificat par un tiers de confiance. L’outil « keytool.exe » permet de s’auto-certifier un jeu de clé.

Exportation du Certificat hors de JKS

keytool -export -keystore jks.Server.keystore -keypass ****** -storepass ******
        -alias serveur  -file jks.AS.certificat
keytool -export -keystore jks.client.keystore -keypass ****** -storepass ******
        -alias client   -file jks.AC.certificat

Importation dans le TrustStore du tiers

keytool -import -keystore %DB_DIR%jks.client.truststore -keypass ****** -storepass ****** -alias serveur  -file %DB_DIR%jks.AS.certificat
keytool -import -keystore %DB_DIR%jks.server.truststore -keypass ****** -storepass ****** -alias client   -file %DB_DIR%jks.AC.certificat

Exportation des clés privées hors de JKS en binaire

java -cp %CLASSPATH_SSL% com.penpen.portail.bigfert.swt.ssl.ExportPriv
         jks.Server.keystore serveur  ****** ****** > jks.AS.key

java -cp %CLASSPATH_SSL% com.penpen.portail.bigfert.swt.ssl.ExportPriv
         jks.client.keystore client   ****** ****** > jks.AC.key

Lister un JKS
keytool -list -keystore jks.Server.keystore   -storepass ******

Pour Apache

La manipulation des couple de clés avec OpenSSL se fait via l’outil « OpenSSL.exe » situé dans le répertoire « ROOT_APACHE2/bin/OpenSSL.exe ».

Importation des certificats JKS au format DER (Binaire) :

OpenSSL.exe x509 -out "pem.AS.certificat" -outform pem -text
                 -in jks.AS.certificat -inform der

Création de la clé privée au format PEM
copy "jks.AS.key" "pem.AS.key"

Il faut en effet savoir que le format de la clé privée en JKS est binaire et est le même qu’en PEM. Une simple copie du fichier extrait de la clé privée suffit.

Concaténation de certificat sur le serveur

Dans le cas d’ajout d’un nouveau couple de clé, le script « CreateNewKey.bat » exécute les même commande que le script de base avec en plus cette commande :

java -cp %CLASSPATH_SSL% com.penpen.portail.bigfert.swt.ssl.ConcatFile
                        "pem.%CLIENT_NAME%.certificat" "pem.AC.certificat"

Il est utile de savoir que pour que le serveur Apache accepte plusieurs certificat pour différentes authentification cliente, il suffit de concaténer tous les certificats, les un derrière les autres, pour qu’il les accepte tous.

Pour le navigateur

Copy de la clef privée et du certificat au format Binaire (DER) vers le format PKCS12 :

OpenSSL.exe pkcs12 -export -in "pem.AC.certificat" -inkey "pem.AC.key"
                   -name "Certificat de client" -certfile "pem.AC.certificat"
                   -out "pkcs12.AC.pfx"

Première étape, le plus simple

Les API Java sont adaptées au développement d’applications réseaux ou distribuées. Le package java.net permet à un novice de développer des applications clients/serveurs basées sur les sockets.

Pour avancer étape par étape, nous allons commencer par faire dialoguer un serveur JAVA et un navigateur Web avec une simple authentification Serveur.

Le serveur étant Java, il faut s’assurer dans un premier temps que la sécurité JSSE dans Java est correctement installée.

Qu’est-ce que JSSE ?

Nous n’arrêtons pas de parler de SSL, mais comment est-il possible d’utiliser SSL dans notre serveur Java ? La réponse est apportée par SUN avec une API complète SSL/TLS : JSSE (Java Secure Socket Extension).

Vérification de l’installation de JSSE

Le fonctionnement de JSSE se base sur 3 fichiers JAR : jsse.jar, jcert.jar, et jnet.jar. Ces fichiers jar doivent être présent dans votre classpass. Pour vérifier la bonne installation de JSSE, vous pouvez exécuter les scripts « InfoJavaHome.bat » et « InfoJSSEInstall.bat ». Ces scripts utilisent les classes com.penpen.portail.bigfert.swt.ssl.InfoJavaHome et com.penpen.portail.bigfert.swt.ssl.InfoJSSEInstall

Sélection d’un magasin

La recherche d’un magasin de type TrustStore par JSSE se fait de la façon suivante :

  1. Si la propriété système javax.net.ssl.trustStore est définie, alors la valeur de cette propriété est utilisée pour localiser le magasin TrusStore.
  2. Si le fichier JAVA_HOME/lib/security/jssecacerts file est défini, alors ce fichier « jssecacerts » est utilisé comme TruStstore.
  3. Si le fichier JAVA_HOME/lib/security/cacerts est défini, alors ce fichier « cacerts » est utilisé comme TrustStorefile.

Vous pouvez trouver la valeur de ce TrustStore en exécutant le script « InfoTrustStore.bat ». Ce script utilise la classe com.penpen.portail.bigfert.swt.ssl.InfoTrsustStore.

Pour cette partie, nous allons utiliser les fichiers générés précédemment  :

Le serveur Java

Maintenant que nous avons notre couple de clé pour l’authentification serveur, nous avons allons utiliser un petit serveur HTTPS fournit et écrit en Java pour tester le bon fonctionnement de JSSE.
Ce serveur se base sur la classe com.penpen.portail.ssl.ServeurHTTPSSL.java, qui dérive d’un serveur HTTP de base le ServeurHTTP.java.
Le démarrage du serveur sans SSL, se ferait avec le script « ServeurHttp.bat ». nous obtiendrions la fenêtre suivante :

------------------------------------
Creation du Serveur Travail
Les parametres :
  - PORT :80
------------------------------------
Travail est en cours d ecoute sur le port 80 ...
------------------------------------

Mais utilisons plutôt le serveur sécurisé :

------------------------------------
Creation du Serveur SecureServer
Les parametres :
  - PORT :443
  - Keystore Name     :jks.server.keystore
  - Keystore Password :******
  - Key Password :******
               Alias : serveur Type : X.509
  - ACTIVE_AUTH :false
------------------------------------
SecureServer est en cours d ecoute sur le port 443 ...
------------------------------------

Maintenant, nous pouvons appeler la page « https://travail/index.htm » depuis votre navigateur préféré. Le navigateur s’ouvre et affiche alors la fenêtre suivante :

Si vous cliquez sur « Afficher le certificat », la fenêtre suivante apparaît :

La fenêtre ci-dessus explique pourquoi IE a bloqué ce certificat. Si vous cliquez sur l’onglet « Détail », vous pouvez voir les détails des informations de ce certificat. Maintenant, si vous cliquez sur « Chemin d’accès de certificat », vous comprenez que ce certificat n’a pas été validé par un tiers de confiance !

Après avoir cliqué sur le bouton « OK » et accepté de certificat, la fenêtre IE suivante s’affiche :

Le serveur dans la console vous retourne les lignes suivantes :

...
------------------------------------
SecureServer est en cours d ecoute sur le port 443 ...
------------------------------------
Connexion accepte de travail (192.168.0.1) sur le port 1433.
Reception de la requete suivante:
Requete complete. Fermeture de connexion.
-----------------------------------------
Connexion accepte de travail (192.168.0.1) sur le port 1434.
Reception de la requete suivante:
GET /index.html HTTP/1.1
Accept: */*
Accept-Language: fr
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
Host: travail

Connection: Keep-Alive
Fichier envoye : G:\ssl\Tutoriel\index.html
Nombre de bytes: 310
Requete complete. Fermeture de connexion.
-----------------------------------------

A cette étape, la première partie est maintenant terminée. Vous pouvez soit creuser le fonctionnement du serveur sécurisé, soit passer directement à la seconde étape de ce tutoriel en créant cette fois un client Java à la place du navigateur Web.

Comment ce serveur sécurisé fonctionne-t-il ?

Passons en revue les lignes du serveur sécurisé « ServeurHTTPSSL.java ». La première chose à remarquer c’est les imports réalisés pour son bon fonctionnement :

import javax.net.*;

import javax.net.ssl.*;

import com.sun.net.ssl.*;

Ce sont les packages de base de JSSE. Le package javax.net contient les classes SocketFactory et ServerSocketFactory, qui remplacent les socket TCP par des sockets SSL. Le package javax.net.ssl contient des classes et des interfaces pour établir et gérer une session SSL. Enfin, le package com.sun.net.ssl contient les classes et interfaces sous - jacentes de gestion des clés.

Le serveur définit ensuite les attributs suivants :

String KEYSTORE = System.getProperty("javax.net.ssl.keyStore");
String KEYSTOREPW = System.getProperty("javax.net.ssl.keyStorePassword");
String KEYPW = System.getProperty("javax.net.ssl.keyPassword");

boolean ACTIVE_AUTH = Boolean.valueOf(System.getProperty("javax.net.ssl.ActivateAuthentication")).booleanValue();

On retrouve les valeurs de nos magasins ainsi que leurs password. On peut également remarquer l’attribut d’activation de l’authentification cliente. Dans cette partie, il est laissé à false.
Ensuite, la méthode main() crée simplement une instance de ServeurHTTPSSL et appel sa méthode run().

La méthode getServerSocket() est la méthode où toute l’action du SSL prend sa place. Elle surcharge la méthode getServerSocket() du serveurHTTP de base pour y substituer une SSLServerSocket au TCP ServerSocket ordinaire. La méthode getServerSocket() commence par enregistrer JSSE comme étant le fournisseur du service de cryptage :
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());

Le serveur accède alors au KeyStore passé en paramètre. Le format utilisé est JKS, et on peut loader le magasins grâce au password :

KeyStore keystore = KeyStore.getInstance("JKS");

keystore.load(new FileInputStream(KEYSTORE), KEYSTOREPW);

Une KeyManagerFactory est alors utilisée pour créer un gestionnaire de clé au format X.509 pour le magasins. Cette KeyManagerFactory est bien sûr définie dans com.sun.net.ssl.

KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");

kmf.init(keystore, KEYPW);

Nous avons réglé le problème de la gestion des clés, mais maintenant nous avons besoin d’établir un SSLContext. Ce SSLContext est un environnement pour implémenter JSSE. Il sera utilisé pour créer une ServerSocketFactory, qui sera utilisée pour créer une SSLServerSocket.
SSLContext sslc = SSLContext.getInstance("SSLv3");

Le SSLContext est configuré pou utiliser SSL V3.0 à la place de TLS 1.0. Il est plus sûr d’utiliser SSL V3.0 car il est plus répandu sur les navigateurs. On initialise ensuite noter SSLContext pour travailler avec notre manager de clé :
sslc.init(kmf.getKeyManagers(), null, null);

Ensuite, nous créons une ServerSocketFactory depuis le SSLContext :
ServerSocketFactory ssf = sslc.getServerSocketFactory();

Maintenant, nous pouvons créer la Socket SSL :

SSLServerSocket serverSocket = (SSLServerSocket) ssf.createServerSocket(serverPort);

Il ne reste plus qu’à préciser si nous utilisons une authentification du cleint 
serverSocket.setNeedClientAuth(requireClientAuthentication);

Seconde étape, Comment marche le client

Cette seconde étape va permettre d’expliquer comment la partie cliente d’un Socket SSL fonctionne en Java. Pour ce faire, nous allons remplacer le navigateur Web par une client HTTP écrit en Java. Ca va se compliquer, mais tenez bon ! Voici le schéma de cette seconde étape :

Avec un client Java

Le Client HTTP et HTTPS

Dans le package livré, vous trouvez deux classe Java permettant de simuler un client HTTP. Ce sont les classes « ClientHTTP.java » et sa dérivée « ClientHTTPSSL.java ».

Vous pouvez tester le client HTTP SSL sur un site déjà sécurisé tel que celui de SUN. Exécuter le script « ClientJavaSSLSun.bat » et vous vous connecterez sur le site de SUN en SSL. Voici le résultat de cet appel :

...
  - URL :https://www.sun.com
  - Keystore Name     :null

  - Keystore Password :null
  - Key Password :null
  - Truststore Name     :null
  - Truststore Password :null
-------------------------------------------
Parametres :
  - URL ori : https://www.sun.com
  - URL auto : https://www.sun.com
  - URL : https://www.sun.com:-1/
-------------------------------------------
THE HEADERS
-------------------------------------------
KEY: Server
VALUE: SunONE WebServer 6.0
KEY: Date
VALUE: Wed, 06 Oct 2004 17:42:39 GMT
KEY: P3p
VALUE: policyref="http://www.sun.com/p3p/Sun_P3P_Policy.xml", CP="CAO DSP COR CU
R ADMa DEVa TAIa PSAa PSDa CONi TELi OUR  SAMi PUBi IND PHY ONL PUR COM NAV INT
DEM CNT STA POL PRE GOV"

KEY: Set-Cookie
VALUE: SUN_ID=82.66.40.189:226021097084559; EXPIRES=Wednesday, 31-Dec-2025 23:59
:59 GMT; DOMAIN=.sun.com; PATH=/

KEY: Content-Type
VALUE: text/html;ISO-8859-1
KEY: Set-Cookie
VALUE: JSESSIONID=7011E43BFDDCEE27DEBF0F891195C2A4.tomcat2;Path=/;Secure
KEY: Connection
VALUE: close
-------------------------------------------
THE CONTENT
-------------------------------------------
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
...
</table>
<!-- ### ADD ANY HIDDEN ELEMENTS HERE === NOT AT THE TOP ### -->
            <script language="JavaScript" src="/share/omniture/s_code_remote.js">
</script>

</body>
</html>
-------------------------------------------
G:\ssl\Tutoriel>pause
Appuyez sur une touche pour continuer...

Attention à vote accès à Internet, ce navigateur HTTP Java ne supporte pas les connexions Web via un Proxy

Testez-le sur votre serveur !

Vous devez maintenant avoir hâte de tester ce client HTTPS sur votre serveur HTTPS. He bien allons-y ! Démarrer votre serveur « ServeurHttps.bat » et démarrer votre client avec « ClientHttpSSL.bat ».

Voici la console du client HTTPS :

G:\ssl\Tutoriel>echo off
  - URL :https://travail/index.html
  - Keystore Name     :jks.client.keystore
  - Keystore Password :******
  - Key Password :null
               Alias : client Type : X.509

  - Truststore Name     :jks.client.truststore
  - Truststore Password :******
               Alias : serveur Type : X.509
-------------------------------------------
Parametres :
  - URL ori : https://travail/index.html
  - URL auto : https://travail/index.html
  - URL : https://travail:-1//index.html
-------------------------------------------
THE HEADERS
-------------------------------------------
KEY: Content-Length
VALUE: 310
KEY: Content-Type
VALUE: text/html
-------------------------------------------
THE CONTENT
-------------------------------------------
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  <title>Vous utiliser la sÚcuritÚ Java avec JSSE</title>

</head>
<body>
<h1>Vous utiliser la sÚcuritÚ Java avec JSSE</h1>
<p>Cette page a ÚtÚ sÚcurisÚe en utilisant SSL version 3.0.</p>
</body>
</html>
-------------------------------------------

Ce test n’a pu fonctionner que si le magasin du certificat a bien été initialisé. C’est bien le cas puisque dans le TrustStore du client « jks.client.truststore » nous avons ajouté le certificat du serveur. Rappelez-vous, nous avons tapé « Oui » ou « yes » à la question :

Trust this certificate? [no]: y
Certificate was added to keystore

De plus il a fallu retrouver ce magasin. C’est le cas, puisque la classe d’affichage du paramétrage « TraceInfoManager.java » a affiché « TrsuStire Name = jks.client.truststore ». Cette valeur a été initialisée dans le fichier « SetEnvSSL.bat » avec la ligne :

set OPTION_CLIENT_SSL=-Djavax.net.ssl.trustStore=jks.client.truststore
                      -Djavax.net.ssl.trustStorePassword=******

La console de sortie du serveur nous indique que la page a bien été traitée :

...
SecureServer est en cours d ecoute sur le port 443 ...
------------------------------------
Connexion accepte de travail (82.66.40.189) sur le port 1041.
Reception de la requete suivante:

GET /index.html HTTP/1.1
User-Agent: Java/1.4.2_04
Host: travail
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
Fichier envoye : G:\ssl\Tutoriel\index.html
Nombre de bytes: 310
Requete complete. Fermeture de connexion.
-----------------------------------------

Vous avez réussi à faire communiquer un serveur Java et un client Java avec une authentification du serveur. C’est déjà pas mal, mais on va faire beaucoup mieux dans la partie suivante : Nous allons croiser les connexions SSL ! Si vous voulez des complémentes d’informations sur le fonctionnement du client Java, poursuivez cette section, sinon sautez à la section suivante.

Comment fonctionne ce client HTTPS ?

La petite astuce pour implémenter SSL sur le client HTTP, c’est d’abord d’enregistrer le provider SSL comme étant le provider de sécurité et ensuite de positionner la propriété système « java.protocol.handler.pkgs system »avec le protocole SSL. Ainsi, JSSE est automatiquement utilisé pour gérer les URLs HTTPS :

Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());

System.setProperty("java.protocol.handler.pkgs",

                   "com.sun.net.ssl.internal.www.protocol");

Cette explication est très courte, mais ce point d’insertion est terriblement efficasse.

Troisième étape : l’authentification du client

Maintenant que la mise en place d’un flux SSL pour l’authentification du serveur, nous allons attaquer les choses sérieuses avec un second cryptage sur le premier : l’authentification du client :

Le but bien sur est d’être sûr que le client qui se connecte est bien celui qu’il prétend être. Nous aurons ainsi créé un vrai VPN sur Internet. Voici le schéma de ce que nous allons mettre en place dans cette partie :

L’authentification du client

La configuration du serveur Java

La configuration du serveur est très simple puisqu’il suffit de passer en paramètre au démarrage du serveur le choix d’activation ou non de l’authentification du client. Ceci est fait dans le script de démarrage « ServeurHttpsWithAC.bat » avec l’argument « -Djavax.net.ssl.ActivateAuthentication=true ».

L’activation de ce paramètre amène à positionner setNeedClientAuth()du serveur de sockets à true. Voici le code de la classe « ServeurHTTPSSL.java » :

// Authenticate the client?

serverSocket.setNeedClientAuth(ACTIVE_AUTH);

L’ajout du jeu de clé au navigateur Web

Du coté du navigateur Web, il faut ajouter le fichier PKCS#12 comme clé privée pour le client. Voici comment procéder :

Sélectionner dans le menu « Outils/Options Internet/Contenu/Certificats … », la fenêtre suivante apparaît :

Cliquez sur « Importer » pour ajouter un certificat. Suivez alors les instructions du wizard :

La fenêtre des certificats vous indique maintenant qu’un certificat est installé.

Maintenant démarrer tout !

Commencer par démarrer le serveur HTPPS Java avec l’authentification du client. Pour cela utiliser le script « ServeurHttpsWithAC.bat ».

La fenêtre de commande doit vous afficher les traces suivantes :

------------------------------------
Creation du Serveur SecureServer
Les parametres :
  - PORT :443
  - Keystore Name     :jks.server.keystore
  - Keystore Password :******
  - Key Password :******
               Alias : serveur Type : X.509
  - ACTIVE_AUTH :true
  - Truststore Name     :jks.server.truststore
  - Truststore Password :******
               Alias : client Type : X.509
------------------------------------
SecureServer est en cours d ecoute sur le port 443 ...
------------------------------------

Vous pouvez remarquer que l’authentification est bien activée « ACTIVE_AUTH true ».

Vous pouvez maintenant exécuter le script « ClientHttpSSL.bat ». Un navigateur Web s’ouvre et vous demande de sélectionner le certificat à utiliser pour l’authentification cliente. Sélectionnez le certificat importé, comme sur la fenêtre suivante :

Cliquez sur « Ok », la fenêtre du navigateur s’ouvre normalement :

Vous avez réalisé une authentification serveur et cliente, soit un canal entièrement sécurisé. Il reste à remplacer le navigateur Web par un client HTTPS Java. C’est ce que nous allons faire dans à la quatrième étape.

Quatrième étape : tout en Java

La quatrième étape consiste maintenant à remplacer le navigateur web par un client Java. Cette configuration est intéressante dans le cas d’applications Client/Serveur fonctionnant sur Internet

Voici le schéma de ce que nous allons mettre en place :

Un VPN en Java ?

La configuration du client

Nous allons maintenant utiliser le couple de clés jks.client.keystore et jks.server.truststore pour mettre en place l’authentification cliente. Dans mon cas, le client et le serveur sont les mêmes machines. Ces stores ont été initialisés avec une clé privée dans le KeyStore et son certificat dans le TrustStore. Rappelez-vous, nous avons tapé « Oui » ou « yes » à la question :

Trust this certificate? [no]: y
Certificate was added to keystore

Il faut donc que le Serveur http SSL et le Client http SSL utilisent maintenant ces deux nouveaux stores. Nous allons le faire en ajoutant les paramètres système « javax.ssl.truststore » et « javax.ssl.keystore » comme indiqué dans le script « SetEnvSSL.bat » :

...

set OPTION_SERVER_SSL=-Djavax.net.ssl.trustStore=jks.server.truststore

                      -Djavax.net.ssl.trustStorePassword=****** %OPTION_SERVER_SSL%

...

set OPTION_CLIENT_SSL=-Djavax.net.ssl.keyStore=jks.client.keystore

                      -Djavax.net.ssl.keyStorePassword=******

...

La configuration pourait bien sûr être faite avec le code suivant :

System.setProperty("javax.net.ssl.keyStore","c:\\windows\\.keystore");

System.setProperty("javax.net.ssl.keyStorePassword","******");

On test l’ensemble

Tout ce qui reste, c'est de redémarrer le serveur sécurisé et y accéder avec le client sécurisé. Prenez soin de laisser une ou deux minutes au serveur pour démarrer. Démarrez alors le brother sécurisé sur voter machine.

Le script « ClientJavaSSL.bat » trace les informations suivantes :

THE HEADERS
-----------
KEY: Content-Length
VALUE: 487
KEY: Content-Type
VALUE: text/html
THE CONTENT
-----------
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  <title>Welcome to Java Security using JSSE</title>
</head>
<body>
<h1>Welcome to Java Security using JSSE</h1>
<p>This page was securely sent using SSL version 3.0.</p>
</body>
</html>

Le script « ServerHttps.bat » trace les informations suivantes:

SecureServer version 1.0
SecureServer is listening on port 443.
Accepted connection to LIBRETTO70CT (192.168.1.70) on port 1098.
Received the following request:

GET / HTTP/1.1
User-Agent: Java1.3.0_01
Host: travail
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
File sent: C:\WINDOWS\Desktop\JSSE\index.htm
Number of bytes: 487
Request completed. Closing connection.

Maintenant, vous commencer à bien maîtriser le SSL pour Java et les navigateurs Web. Il reste encore la configuration sur un vrai serveur Web. C’est ce que nous allons faire dans la section suivante.

Cinquième étape : Et sur un vrai serveur Web ?

Pour finir l’ensemble des possibilités que nous offre SSL, il nous reste la mise en place des authentifications serveur et cliente sur un serveur Web. Nous avons choisi Apache avec le module SSL offert par OpenSSL.

Ci-dessous, le schéma des deux tests que nous allons réaliser :

Configuration du serveur Apache

Vous devez commencer par vérifier que le fichier de configuration d'Apache est configuré pour SSL :

LoadModule ssl_module modules/mod_ssl.so
<IfModule mod_ssl.c>
  Include conf/ssl.conf
</IfModule>

Voici ensuite la configuration du fichier « ssl.conf » de OpenSSL :

Listen 443
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl    .crl
SSLPassPhraseDialog  exec:C:/java/Apache2/conf/passphrase.bat
SSLSessionCache         dbm:logs/ssl_scache
SSLSessionCacheTimeout  300
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
DocumentRoot "C:/java/Apache2/htdocsssl"
ServerName penpen.hd.free.fr:443
ServerAdmin administrator@penpen.hd.free.fr
ErrorLog logs/SSLError.log
TransferLog logs/SSLAccess.log
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile C:/java/Apache2/ssl/pem.AS.certificat

SSLCertificateKeyFile C:/java/Apache2/ssl/pem.AS.key
SSLCACertificatePath C:/java/Apache2/ssl
SSLCACertificateFile C:/java/Apache2/ssl/pem.AC.certificat
SSLVerifyClient require
SSLVerifyDepth  10

On peut remarquer plusieurs choses dans ce fichier :

Testons l’ensemble

Il ne vous restes plus qu'à tester l'ensemble, en démarrant d'abord votre serveur Apache ( En service ou en ligne de commande), puis de démarrer en même temps votre navigateur Web et votre brother Java sécurisé.

Voici la log SSLAccess.log du serveur Apache :

Vous avez enfin réussi à faire communiquer l'ensemble de ces produits au travers de connexions SSL. Il ne vous reste plus qu'à implémenter votre application au travers d'Internet.