PKI, OpenSSL et répondeur OCSP

27/11/09

Bonjour tout le monde !

D’attaque pour continuer dans la lignée des certificats numériques ?

Dans le précédent post, je vous avais fait un peu peur en vous énumérant les responsabilités qui incombaient à la gestion d’une PKI.

Et bien aujourd’hui, je vais vous éplucher un outil qui va faire le sale boulot pour vous. Et oui, notre bon vieux OpenSSL, encore lui, vous propose sur un plateau d’argent une option en or : ocsp. Venons-en aux mains tout de suite.

OCSP, cet amas de lettre à l’adjonction barbare, signifie en réalité Online Certificate Status Protocol. Comme le nom l’indique, il s’agit d’un protocole stipulé par la RFC 2560, qui permet de contrôler le status d’un certificat numérique. OCSP s’impose comme une solution d’optimisation concernant le problème des CRL, les Certificate Revokation Lists.

Démonstration. Nous nous situons dans une architecture où il y a 2 authentifications pour une requête de, admettons, consultation de page web.

Le serveur s’authentifie auprès du client et le client doit également s’authentifier auprès du serveur. Prenons le problème en symétrie. Le client reçoit le certificat numérique du serveur, vérifie sa chaîne de certification et la signature correcte. Il doit également interroger la CRL pour vérifier si le certificat ne fait pas partie des certificats révoqués.

Ce fonctionnement implique tout d’abord la mise à disposition, l’accès et la mise à jour constante des CRL. Cela peut poser quelques cas de conscience au niveau fuite des données (les CRL constituent un peu des listes de vilains petits canards), donc au niveau sécurité. De même, si l’on considère que nous avons beaucoup de client, nous sommes confronté à une utilisation futile des ressources et du serveur mettant à disposition ces CRL, des clients qui doivent se taper chacun tout le travail, et du réseau en général.

Dans le cas où nous mettons en place un serveur OCSP, que l’on appellera communément répondeur OCSP, les clients doivent toujours vérifier la chaîne de certification des certificats qui leur sont présentés, en revanche, il leur suffira de requêter le répondeur OCSP pour avoir ou non la confirmation que ledit certificat est en règle et non révoqué.

OCSP sert donc à centraliser les tâches de vérification et nous permet de gagner en efficacité et en simplicité, tout en préservant notre architecture des concessions malencontreuses que nous aurions pu faire.

Il existe, pour notre serveur Linux frais et dispo, un projet OpenSource qui implémente OCSP et qui porte le doux nom de OpenCA OCSP Project.

Ce qu’on peut tout de suite remarquer, c’est que, à l’heure où j’écris ces lignes, le projet n’a pas subi d’update depuis Octobre 2006. Autre chose, si vous êtes comme moi, les seuls binaires disponibles concernent Fedora 3 et 4 et ne sont donc pas adaptés à votre système. Il faudra donc se résoudre à wgetter (downloader, pour ceux qui préfèrent) les sources et à les installer à la Barbue.

Une des bonnes pratiques est de wgetter les sources dans le répertoire /usr/local/src.

Il vous faut également gcc-4.2-base et gcc-4.2-multilib pour le compiler, notre bon vieux openssl et -très important- libssl-dev.

root@ocspd:~$ cd /usr/local/src

root@ocspd:~/usr/local# wget http://downloads.sourceforge.net/project/openca/OpenCA-OCSPD/1.5.1/openca-ocspd-1.5.1-rc1.tar.gz

Détarez l’archive et rendez-vous dans le répertoire crée.

root@ocspd:~/usr/local# tar -zxvf openca-ocspd-1.5.1-rc1.tar.gz

root@ocspd:~/usr/local# cd openca-ocspd-1.5.1-rc1/

Lancez le ./configure

Notez au passage qu’on apprend la maximal command line lenght.

Si le script de configuration bronche sur les librairies openldap qui ne sont pas présentes, et que vous comptez quand même vous en servir, mieux vaut se plier à ses exigences et installer les libldap2-dev, libldap-2.4-2-dbg et libldap-2.4-2.

Le coup d’oeil dans le Makefile crée nous indique que l’install se fera dans /usr/local/openca or ça ne me va pas. Si je veux que l’installation place tout son bazard ailleurs, il faut stipuler l’option –prefix=<chemin-ou-je-veux-que-tu-installe> juste après le ./configure. En pratique, je veux un joli /opt/openca avec tout ce qu’il faut dedans, je vais donc lui dire

root@ocspd:~/usr/local/openca-ocspd-1.5.1-rc1# ./configure --prefix=/opt/openca
root@ocspd:~/usr/local/openca-ocspd-1.5.1-rc1# make && make install
root@ocspd:~/usr/local/openca-ocspd-1.5.1-rc1# ls -lsa /opt/openca
total 20

4 drwxr-xr-x 5 root root 4096 2009-11-27 12:27 .
4 drwxr-xr-x 3 root root 4096 2009-11-27 12:27 ..
4 drwxr-xr-x 4 root root 4096 2009-11-27 12:27 etc
4 drwxr-xr-x 3 root root 4096 2009-11-27 12:27 man
4 drwxr-xr-x 2 root root 4096 2009-11-27 12:27 sbin

Ok ! Pour que tout se passe correctement dans le meilleur des monde, il faut un peu de retouche. Comme pour Apache, nous allons confier le process à un utilisateur spécifique que nous allons créer.

root@ocspd:~/opt/openca# groupadd ocspd
root@ocspd:~/opt/openca# useradd -d /opt/ocspd -g ocspd -s /bin/false ocspd
root@ocspd:~/opt/openca# chown -R ocspd:ocspd /opt/ocspd

Bien sûr, il faut notifier tout ça à OpenCA. Avant cela, nous allons reprendre notre certificat généré dans le billet précédent, server-cert.pem, sa clé privée et notre cacert.pem et copier le tout (ou lier, c’est vous qui voyez) dans le répertoire /opt/openca/etc/ocspd/certs/. En gardant notre arborescence, c’est mieux.

root@ocspd:~/opt/openca# cp -R /home/kbux/certs/* /opt/openca/etc/ocspd/certs/.

Vous devriez vous retrouver avec cette arborescence (après tri):

root@ocspd:~/opt/openca# ls -lsaR /opt/openca/etc/oscpd/certs
/opt/openca/etc/ocspd/certs :

total 32

4 drwxr-xr-x 4 ocspd ocspd 4096 2009-11-27 12:54 .
4 drwxr-xr-x 4 ocspd ocspd 4096 2009-11-27 12:27 ..
4 -rw-r--r-- 1 ocspd ocspd 1590 2009-11-27 12:53  cacert.pem
4 -rw-r--r-- 1 ocspd ocspd 698 2009-11-27 12:53  crl.pem
4 -rw-r--r-- 1 ocspd ocspd 203 2009-11-27 12:53  index.txt
4 drwxr-xr-x 2 ocspd ocspd 4096 2009-11-27 12:54  private
4 -rw-r--r-- 1 ocspd ocspd 3 2009-11-27 12:54  serial
4 drwxr-xr-x 2 ocspd ocspd 4096 2009-11-27 12:54  signedcerts

/opt/openca/etc/ocspd/certs/private:

total 12

4 drwxr-xr-x 2 ocspd ocspd 4096 2009-11-27 12:54  .
4 drwxr-xr-x 4 ocspd ocspd 4096 2009-11-27 12:54  ..
4 -rw-r--r-- 1 ocspd ocspd 1751 2009-11-27 12:54  server.key
4 -rw-r--r-- 1 ocspd ocspd 1751 2009-11-27 12:54  kbux.key

/opt/openca/etc/ocspd/certs/signedcerts:

total 16

4 drwxr-xr-x 2 ocspd ocspd 4096 2009-11-27 12:54  .
4 drwxr-xr-x 4 ocspd ocspd 4096 2009-11-27 12:54  ..
4 -rw-r--r-- 1 ocspd ocspd 1751 2009-11-27 12:54  server-cert.pem
4 -rw-r--r-- 1 ocspd ocspd 1751 2009-11-27 12:54  kbux.pem

Comme nous sommes des gens civilisés, nous allons générer et valider un certificat rien que pour notre répondeur OSCP. Nous placerons oscpd-cert.pem dans /opt/openca/etc/ocspd/certs/signedcerts et sa clé privée, ocspd-key.pem, dans /opt/openca/etc/ocspd/certs/private. Je vous renvoie au post précédent si vous avez quelques doutes quant à sa génération et validation.

ATTENTION !!! Il ne faut pas définir de passphrase pour ce certificat.

Si c’est trop tard, vous pouvez toujours la faire sauter avec la commande :

root@ocspd:~/opt/openca# openssl rsa -in /opt/openca/etc/ocspd/certs/private/ocspd-key.pem -out /opt/openca/etc/ocspd/certs/private/
ocspdkey.pem
root@ocspd:~/opt/openca# rm /opt/openca/etc/ocspd/certs/private/oscpd-key.pem
root@oscpd:~/opt/openca# mv /opt/openca/etc/ocspd/certs/private/ocspdkey.pem /opt/openca/etc/ocspd/certs/private/ocspd-key.pem

Editez le fichier de configuration /opt/openca/etc/ocspd/ocspd.conf et assaisonnez selon vos besoins (attention, le chemin dépend du prefix spécifié à la configuration). Le reste (les [...]) reste inchangé.

root@ocspd:~/opt/openca# vim /opt/openca/etc/ocspd/ocspd.conf

 # OCSPd example configuration file.
 # (c) 2001 by Massimiliano Pala - OpenCA Project.
 # All rights reserved
 [ ocspd ]
 default_ocspd   = OCSPD_default

 [ OCSPD_default ]
 dir              = /opt/openca/etc/ocspd
 db               = $dir/index.txt
 md               = sha1

 ca_certificate    = $dir/certs/cacert.pem
 ocspd_certificate = $dir/certs/ocspd-cert.pem
 ocspd_key         = $dir/certs/private/ocspd-key.pem
 pidfile           = $dir/ocspd.pid

 user                    = ocspd
 group                   = ocspd
 bind                    = *
 port                    = 2560
 max_childs_num          = 5
 max_req_size            = 8192

 threads_num             = 150
 max_timeout_secs        = 5

 crl_auto_reload = 3600
 crl_reload_expired = yes

 response         = ocsp_response

 #[...] 

 ####################################################################
 [ ocsp_response ]
 dir                     = /opt/openca/etc/ocspd
 ocsp_add_response_certs = $dir/certs/chain_certs.pem
 ocsp_add_response_keyid = yes
 next_update_days        = 0
 next_update_mins        = 5
 ####################################################################
 # [...]
 [ first_ca ]
 # Certificate Revokation List
 crl_url  = file:////opt/openca/etc/ocspd/certs/crl.pem
 ca_url  = file:////opt/openca/etc/ocspd/certs/cacert.pem
 #
 # [...]

Testons tout ça.

root@ocspd:~$ /opt/ocspd/sbin/ocspd -c /opt/ocspd/etc/ocspd/ocspd.conf -v &
cat /var/log/syslog | grep ocspd

Et voila ! Syslog nous informe qu’OpenCA tourne correctement avec une conclusion en «  INFO::OPENCA_SRV_INFO_TREAD::new thread created « .
Si, à l’avenir, vous devez relancer OpenCA, attention, vu qu’il est paramétré pour écouter sur toutes les interfaces, vous devez tuer le process.
La meilleure méthode est de le remettre en foreground (et oui, le ‘&‘ à la fin de la ligne le met en background). Pour cela, faîtes un fg et le job reviendra en premier plan. Ctrl+C et on n’en parle plus. Vous pourrez le relancer sans problème.

Bon, notre process tourne correctement, mais fait-il bien ce qu’on lui demande -à savoir vérifier la validité des certificats- ?

root@ocspd:~$ openssl ocsp -issuer /opt/openca/etc/ocspd/certs/cacert.pem -CAfile /opt/openca/etc/ocspd/certs/cacert.pem -cert
/opt/openca/etc/ocspd/certs/signedcerts/server-cert.pem -url http://localhost:2560 -text

[...]
/opt/openca/etc/ocspd/certs/signedcerts/server-cert.pem : good
[...]

OpenCA détecte bien le certificat comme valide.
Même chose pour le certificat kbux.pem, qui lui, avait fait précédemment l’objet d’une révocation (mais si, souvenez-vous !) :

root@ocspd:~$ openssl ocsp -issuer /opt/openca/etc/ocspd/certs/cacert.pem -CAfile /opt/openca/etc/ocspd/certs/cacert.pem -cert
/opt/openca/etc/ocspd/certs/signedcerts/kbux.pem -url http://localhost:2560 -text
[...]
/opt/openca/etc/ocspd/certs/signedcerts/kbux.pem : revoked
[...]

Et effectivement, kbux.pem apparaît bien comme révoqué.
Il ne nous reste plus qu’à faire en sorte que tous nos utilisateurs puissent dialoguer avec notre répondeur OCSP.

Il faut pour cela retoucher notre openssl.cnf et y inclure les données pour vérification OCSP. Malheureusement, cela nécessite une révocation massive de vos certificats et leur regénération.

Retournons dans notre openssl.cnf -qui était situé dans un emplacement bâtard, j’espère que vous l’avez remis dans /etc/openssl/, en tout cas, moi, je vais faire comme si-.
Donc un petit vim de /etc/ssl/openssl.cnf et on rajoute :

[OCSP]

basicConstraints        = CA:FALSE
keyUsage                = digitalSignature
extendedKeyUsage        = OCSPSigning
issuerAltName           = issuer:copy
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid:always,issuer:always
authorityInfoAccess     = OCSP;URI:http://ocspd.k-tux.com/

[OCSP_SERVER]
nsComment                       = "K-TUX Server certificate"
subjectKeyIdentifier            = hash
authorityKeyIdentifier          = keyid,issuer:always
issuerAltName                   = issuer:copy
basicConstraints                = critical,CA:FALSE
keyUsage                        = digitalSignature, nonRepudiation, keyEncipherment
nsCertType                      = server
extendedKeyUsage                = serverAuth
authorityInfoAccess             = OCSP;URI:http://ocspd.k-tux.com/

[OCSP_CLIENT]
nsComment                       = "Client Certificate"
subjectKeyIdentifier            = hash
authorityKeyIdentifier          = keyid,issuer:always
issuerAltName                   = issuer:copy
basicConstraints                = critical,CA:FALSE
keyUsage                        = digitalSignature, nonRepudiation
nsCertType                      = client
extendedKeyUsage                = clientAuth
authorityInfoAccess             = OCSP;URI:http://ocspd.k-tux.com/

Et de regénérer vos certificats avec l’extension OCSP_CLIENT.
Ensuite, sur le poste de votre utilisateur, pour les vérifier par Firefox par exemple, il vous faut aller dans les options avancées > chiffrement > et cocher « utiliser OCSP si le certificat spécifie un serveur ».

Il faut également savoir que s’il est peu mis en place actuellement, en revanche l’IETF est en train de nous concocter un protocole qui reprendrait les fonctionnalités d’OCSP et qui porte le doux nom de SCVP (oui, je sais, encore des acronymes barbares), Server-based Certificate Validation Protocol. Pour les curieux, vous pouvez essayer de digérer la RFC en question.

Voila. Ce n’est pas grand chose, mais c’est toujours bon à savoir.