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 :
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.
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/
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.
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 :
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.
Une clé est un code binaire ressemblant au fichier suivant :
-----BEGIN PRIVATE KEY----- |
Un certificat est un code binaire ressemblant au fichier suivant :
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.
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
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 | ****** |
Editez ce script et modifier tous les champs pour les adapter à votre configuration :
// Le répertoire
d’installation du JDK 1.4.2 : |
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 : |
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=****** |
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% |
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 « 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 :
... |
Vous devez avoir généré les clés suivantes :
pkcs12.AC.pfx
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 »
Le script est découpé en trois parties distinctes :
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 :
keytool -genkey -v
-keystore jks.server.keystore -keyalg rsa -keysize 512 -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.
keytool -selfcert -alias
serveur -validity 1024 -keypass ****** |
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é.
keytool -export -keystore
jks.Server.keystore -keypass ****** -storepass ****** |
keytool -import -keystore
%DB_DIR%jks.client.truststore -keypass ****** -storepass ******
-alias serveur -file %DB_DIR%jks.AS.certificat |
java -cp %CLASSPATH_SSL%
com.penpen.portail.bigfert.swt.ssl.ExportPriv |
keytool -list -keystore jks.Server.keystore -storepass ****** |
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 ».
OpenSSL.exe x509 -out
"pem.AS.certificat" -outform pem -text |
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.
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 |
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.
OpenSSL.exe pkcs12
-export -in "pem.AC.certificat" -inkey
"pem.AC.key" |
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.
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).
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
La recherche d’un magasin de type TrustStore par JSSE se
fait de la façon suivante :
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 :
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 :
------------------------------------ |
Mais utilisons plutôt le serveur sécurisé :
------------------------------------ |
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 :
... |
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.
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"); |
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); |
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
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 :
... |
Attention à vote accès à Internet, ce navigateur HTTP Java ne supporte pas les connexions Web via un Proxy
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 |
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 |
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 |
La console de sortie du serveur nous indique que la page a bien été traitée :
... |
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.
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.
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 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); |
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é.
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 :
------------------------------------ |
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.
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 ?
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 |
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","******"); |
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 |
Le script « ServerHttps.bat » trace les informations suivantes:
SecureServer version 1.0 |
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.
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 :
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 |
On peut remarquer plusieurs choses dans ce fichier :
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.