Fournir, puis demander à un utilisateur un certificat pour l'authentifier sur notre site internet.

rsaPlp.png

::TOC::

Pourquoi faire ça?

A moins de s'appeler le trésor public[1], cette sécurité peut paraître exagérée.

Ça va me servir dans quelques semaines à sécuriser une appli web du travail pour laquelle seuls une dizaine d'utilisateurs auront accès depuis l'extérieur (via un reverse proxy apache) .

Présentation des techniques employées:

La configuration se fait au niveau d'apache et du module SSL. Ce n'est pas compliqué, Mais c'est chiant à expliquer de façon claire. J'en suis à la troisième re-rédaction de ce billet pour tenter d'éclaircir les explications.

Ce billet contient tout un mémo de création d'une chaine de certification avec openSSL et un peu de config Apache.

Sur le serveur (mon Raspberry pi), je vais créer trois sites virtuels (VHOST) dans la configuration d'apache:

  • home.tinad.fr (en http)
  • home.tinad.fr (en https)
  • prive.tinad.fr (en https, avec obligation pour l'utilisateur de posséder un certificat personnel signé par l'autorité de certification qu'on va créer):

Créer son autorité de certification et des certificats pour les deux sites en https

l'autorité de certification

Malheureusement, il n'est pas possible d'obtenir un certificat ayant le rôle "autorité de certification" reconnu par tous les navigateurs. On devra faire en sorte que les utilisateurs ajoutent notre certificat dans leur navigateur. Je ne détaillerai pas ici comment faire, mais il voici trois pistes:

  • Créer une page web intermédiaire fournissant le certificat, et expliquant comment et pourquoi l'installer
  • Si les utilisateurs sont dans un réseau sur lequel on est l'administrateur réseau : Via une GPO.
  • Offrir une boite de kinder chocolat à l'administrateur réseau pour qu'il fasse une GPO.
  • L'installer manuellement sur tous les postes.

Configuration

#On créé l'architecture de dossiers et fichiers nécessaires à une gestion des
#clés et certificats dans le repertoire /srv/ssl
mkdir /srv/ssl
cd /srv/ssl
mkdir certs crl newcerts private
echo 01 > serial
touch index.txt
echo 01 > crlnumber
cp /usr/lib/ssl/openssl.cnf .

Editer le fichier /srv/ssl/openssl.conf et modifiez les parametres suivants:

Dans le bloc CA_default :

  • dir=/srv/ssl

Dans le bloc [req_distinguished_name] : .

countryName_default             = FR
stateOrProvinceName_default     = France

Clé privée certificat et signature

#Créer une clé privée
openssl genrsa -des3 -out private/cakey.pem 4096
#certif signé
openssl req -config openssl.cnf -new -x509 -nodes -sha1 -days 1825 -key private/cakey.pem -out cacert.pem

Adaptez les réponses en fonction,s de votre site, mais ne mettez pas le FDQN dans le common name. Il s'agit du certificat autorité, pas celui de votre site web. Voici mon retour écran:

root@raspberrypi:/srv/ssl# openssl req -config openssl.cnf -new -x509 -nodes -sha1 -days 1825 -key private/cakey.pem -out cacert.pem
Enter pass phrase for private/cakey.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [FR]:
State or Province Name (full name) [France]:
Locality Name (eg, city) []:Rouen
Organization Name (eg, company) [Internet Widgits Pty Ltd]:tinad
Organizational Unit Name (eg, section) []:Gnieark   
Common Name (e.g. server FQDN or YOUR name) []:tinad.fr
Email Address []:gnieark@free.fr

Publier le certificat de l'autorité de certification

cp /srv/ssl/cacert.pem /var/www/cacert.crt

(Lors de la copie, on change l'extension .pem en .crt, car .crt est un type mime connu dans la configuration standard d'apache)

Enregistrez le certificat dans le magasin de confiance de votre ordinateur local

Ouvrez tout simplement votre navigateur à l'URL http://VotreServeur/cacert.crt et cochez toutes les cases:

firefoxCacertTinad.png

Créer un certificat pour le serveur Web home.tinad.fr

changez "home.tinad.fr" par le FDQN de votre serveur pour la suite des tests.

cd /srv/ssl
#Création de la clé privée pour home.tinad.fr
openssl genrsa -des3 -out home.tinad.fr.key.pem 4096
#demande de certificat:
openssl req -config openssl.cnf -new -key home.tinad.fr.key.pem -out home.tinad.fr.csr.pem

Voici mon retour écran:

root@raspberrypi:/srv/ssl# openssl req -config openssl.cnf -new -key home.tinad.fr.key.pem -out home.tinad.fr.csr.pem
Enter pass phrase for home.tinad.fr.key.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [FR]:
State or Province Name (full name) [France]:
Locality Name (eg, city) []:Rouen
Organization Name (eg, company) [Internet Widgits Pty Ltd]:tinad
Organizational Unit Name (eg, section) []:home
Common Name (e.g. server FQDN or YOUR name) []:home.tinad.fr
Email Address []:gnieark@free.fr

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Signature de la demande:

openssl ca -config openssl.cnf -policy policy_anything -out home.tinad.fr.cert.pem -infiles home.tinad.fr.csr.pem

La valeur la plus importante est le common name. Elle corrspond au FDQN pour les autres champs, essayez simplement d'etre logique avec l'autorité de certification Voici mon retour écran:

root@raspberrypi:/srv/ssl# openssl ca -config openssl.cnf -policy policy_anything -out home.tinad.fr.cert.pem -infiles home.tinad.fr.csr.pem 
Using configuration from openssl.cnf
Enter pass phrase for /srv/ssl/private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 1 (0x1)
        Validity
            Not Before: May  3 19:25:04 2013 GMT
            Not After : May  3 19:25:04 2014 GMT
        Subject:
            countryName               = FR
            stateOrProvinceName       = France
            localityName              = Rouen
            organizationName          = tinad
            organizationalUnitName    = home
            commonName                = home.tinad.fr
            emailAddress              = gnieark@free.fr
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            Netscape Comment: 
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier: 
                81:4B:C7:3E:9B:C6:EA:60:78:26:B3:8F:77:B4:43:07:07:DE:A8:02
            X509v3 Authority Key Identifier: 
                keyid:BE:1D:5D:B9:F1:53:D6:BD:11:90:8E:5C:0F:D2:BC:99:22:BE:F1:48

Certificate is to be certified until May  3 19:25:04 2014 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

Voila, on a notre certificat signé: /srv/ssl/home.tinad.fr.cert.pem et sa clé privée: /srv/ssl/home.tinad.fr.key.pem (chiffrée par un mot de passe là)

On remarque au passage openssl a incrémenté la valeur dans le fichier /srv/ssl/serial .

Créer une clé non protégée par un mot de passe (ça servira à Apache)

cd /srv/ssl
openssl rsa -in home.tinad.fr.key.pem -out home.tinad.fr-EnClair.key.pem

Créer un certificat pour le serveur Web prive.tinad.fr

Idem qu'au châpitre précedent, du coup je ne détaille pas:

cd /srv/ssl
#Création de la clé privée pour prive.tinad.fr
openssl genrsa -des3 -out prive.tinad.fr.key.pem 4096
#demande de certificat:
openssl req -config openssl.cnf -new -key prive.tinad.fr.key.pem -out prive.tinad.fr.csr.pem
#signature de la demande:
openssl ca -config openssl.cnf -policy policy_anything -out prive.tinad.fr.cert.pem -infiles prive.tinad.fr.csr.pem
#créer une clé non protégée:
openssl rsa -in prive.tinad.fr.key.pem -out prive.tinad.fr-EnClair.key.pem

Configuration du serveur web

cd /var/www
#on va créer 5 dossier pour des vhosts:
mkdir home.tinad.fr
mkdir home.tinad.fr-https
mkdir prive.tinad.fr-https
#Il me semble que le VHOST par défault d'apache est le premier par ordre alphabétique;
#d'où le "0" au début du nom
mkdir 0-default
mkdir 0-default-https
#Supprimer les fichiers de vhosts créés à l’installation d'apache
cd /etc/apache2/sites-enabled
rm *

configuration des vhost

Comme vous le verrez, je reste sur une configuration méga basique des VHOST, préférant les valeurs par défaut d’apache aux paramètres non ou mal compris. De plus je n'utilise pas de script CGI, donc autant ne pas les activer.

vi /etc/apache2/sites-available/home.tinad.fr

<VirtualHost *:80>                                                                                                                                                               
ServerName home.tinad.fr                                                                                                                                               
DocumentRoot /var/www/home.tinad.fr                                                                                                                                    
</VirtualHost>

vi /etc/apache2/sites-available/home.tinad.fr-https

Ce VHOST est chiffré en HTTPS, cependant, aucune restriction d'accès n'est effectuée. Pour le test, j'ai mis le certificat de notre propre autorité de certification. Mais en production, autant mettre un vrai certificat (comptez maxi 30€/an). Pour cette maquette, j'y publie le certificat de l'autorité de certification, j'explique comment l'insérer, et je mets un formulaire qui permettra aux utilisateurs de demander leurs propres certificats. (dans le projet final ce sera l'administrateur qui aura accès au formulaire pour générer les certificats)

<VirtualHost *:443>
        ServerName home.tinad.fr
        DocumentRoot /var/www/home.tinad.fr-https
        SSLEngine On                                                                                                                                                                                           
        SSLCertificateFile /srv/ssl/home.tinad.fr.cert.pem                                                                                                                                                     
        SSLCertificateKeyFile /srv/ssl/home.tinad.fr-EnClair.key.pem                                                                                                                                           
        SSLProtocol all -SSLv2                                                                                                                                                                                                                                                                                                                                                              
</Virtualhost>

vi /etc/apache2/sites-available/prive.tinad.fr-https

<VirtualHost *:443>
	ServerName prive.tinad.fr
	DocumentRoot /var/www/prive.tinad.fr-https
	SSLEngine On
	SSLCertificateFile /srv/ssl/prive.tinad.fr.cert.pem 
	SSLCertificateKeyFile /srv/ssl/prive.tinad.fr-EnClair.key.pem
	SSLProtocol all -SSLv2
	SSLCACertificateFile /srv/ssl/cacert.pem
        SSLCARevocationFile  /srv/ssl/crl.pem
	SSLVerifyClient require
	SSLVerifyDepth 1
	SSLOptions +StdEnvVars
</Virtualhost>

Ce VHOST étant le plus intéressant, expliquons les directives

  • SSLEngine On : active le SSL
  • SSLCertificateFile le fichier contenant le certificat TLS pour prive.tinad.fr
  • SSLCertificateKeyFile le fichier contenant la clé qui servira à chiffrer les connexions (à garder bien cachée ;) )
  • SSLProtocol all -SSLv2 On accepte tous les protocoles ssl supportés sauf le SSLV2 qui présente une faiblesse)
  • SSLCACertificateFile Le fichier certificat de l'autorité qui signe les certificats clients (apache vérifie les signatures)
  • SSLCARevocationFile Le fichier qui contient la liste des certificats révoqués (nécessaire si on veut gérer les utilisateurs)
  • SSLVerifyClient require Seuls les clients ayant un certificat valide sont admis
  • SSLVerifyDepth 1 On limite à une autorité de certification intermédiaire
  • SSLOptions +StdEnvVars Cette directive permet d'ajouter les informations concernant le certificat client aux variables d'environnement. On pourra ainsi adapter le code PHP en fonction du certificat de l'utilisateur.

Activation des vhost:

a2ensite home.tinad.fr
a2ensite home.tinad.fr-https
a2ensite prive.tinad.fr-https
/etc/init.d/apache2 reload

Créer un couple certificat-clé client (fichier PKCS#12):

cd /srv/ssl
mkdir home.tinad.fr-Clefs-clients
cd home.tinad.fr-Clefs-clients

creer clé

openssl genrsa -des3 -out gnieark.home.tinad.fr.key.pem

Créer le certificat:

openssl req -config ../openssl.cnf -new -key gnieark.home.tinad.fr.key.pem -out gnieark.home.tinad.fr.csr.pem

Retour écran de la dernière commande:

Enter pass phrase for gnieark.home.tinad.fr.key.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [FR]:
State or Province Name (full name) [France]:
Locality Name (eg, city) []:Rouen
Organization Name (eg, company) [Internet Widgits Pty Ltd]:tinad
Organizational Unit Name (eg, section) []:home
Common Name (e.g. server FQDN or YOUR name) []:gnieark
Email Address []:gnieark@free.fr

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Signer le certificat:

openssl ca -config ../openssl.cnf -policy policy_anything -out gnieark.home.tinad.fr.cert.pem -infiles gnieark.home.tinad.fr.csr.pem

Retour écran de la commande:

root@raspberrypi:/srv/ssl/home.tinad.fr-Clefs-clients# openssl ca -config ../openssl.cnf -policy policy_anything -out gnieark.home.tinad.fr.cert.pem -infiles gnieark.home.tinad.fr.csr.pem 
Using configuration from ../openssl.cnf
Enter pass phrase for /srv/ssl/private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 2 (0x2)
        Validity
            Not Before: May 12 17:18:18 2013 GMT
            Not After : May 12 17:18:18 2014 GMT
        Subject:
            countryName               = FR
            stateOrProvinceName       = France
            localityName              = Rouen
            organizationName          = tinad
            organizationalUnitName    = home
            commonName                = gnieark
            emailAddress              = gnieark@free.fr
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            Netscape Comment: 
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier: 
                47:E4:92:85:3A:43:6A:BC:43:C7:5B:41:F4:67:66:E2:36:CA:D7:69
            X509v3 Authority Key Identifier: 
                keyid:BE:1D:5D:B9:F1:53:D6:BD:11:90:8E:5C:0F:D2:BC:99:22:BE:F1:48

Certificate is to be certified until May 12 17:18:18 2014 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

Concatener et convertir au forlat PKCS#12 (.p12)

openssl pkcs12 -export -inkey gnieark.home.tinad.fr.key.pem -in gnieark.home.tinad.fr.cert.pem -out gnieark.home.tinad.fr.cert.p12 -name "Gnieark"

Ça y est, j'ai une clé à) fournir à l'utilisateur Gnieark, il pourra l'intégrer à Firefox ou Internet Explorer (lol) et ainsi accéder au site que j'ai protégé précédent.

Révoquer un certificat:

En imaginant que je révoque un Zigazou

cd /srv/ssl
openssl ca -config openssl.cnf -revoke prive.tinad.fr/zigazou.prive.tinad.fr.cert.pem
#générer la liste de révocation:
openssl ca -config openssl.cnf -gencrl -out crl.pem
#la visualiser:
openssl crl -in crl.pem -text

Note

[1] Pour déclarer nos impôts il n'y a plus besoin de certificat personnel, mais les interlocuteurs (fonctionnaires de collectivités) ont leurs propres clés PKCS pour communiquer avec cette administration

Page top