Devenir sa propre autorité de certification
Ces derniers temps et de plus en plus souvent, le protocole TLS (anciennement SSL) et surtout son implémentation dans le protocole HTTP (ce qui donne le HTTPS) est au cœur de nombreux et vifs débats quant à la sécurité toute relative que représente la méthode d'authentification la plus répandue : l'authentification du client TLS par certificat numérique.
L'authentification du client TLS par certificat numérique, qu'es aquò ?
C'est quand le client (vous, par l'intermédiaire de notre navigateur Web) authentifie le serveur TLS sur lequel il se connecte (le site de votre banque, votre boîte e‑mail sur un portail Web, etc.). Cette authentification est réalisée via l'utilisation d'un certificat numérique (sorte de carte d'identité virtuelle approuvée par un tiers de confiance) X.509 (norme cryptographique des télécoms) délivré par une autorité de certification (CA). Votre navigateur Web embarque tout un tas de certificats dits racines, c'est à dire issus directement des autorités de certification (commerciales pour leur très grande majorité) et auto-signés. Ces certificats font office d'autorités connues et permettent d'en signer d'autres (moyennant finance) : votre banque, par exemple, achète auprès d'une autorité de certification racine, disons VISA, une certification (et donc un certificat d'autorité intermédiaire) afin de pouvoir créer ses propres certificats signés par celui (racine) de VISA. Ainsi, votre navigateur Web embarquant le certificat racine de VISA, il pourra établir une connexion sécurisée au site de votre banque de manière totalement transparente pour vous : le certificat de la banque étant signé par VISA et le certificat de VISA étant reconnu comme de confiance, le navigateur fera automatiquement confiance au certificat de la banque. Vous suivez ?
Et alors ? Il est où le problème ?
Eh bien, il réside principalement dans le fait que ces autorités de certification sont — je l'ai déjà dit — des entreprises commerciales (dont le but est donc de faire des profits) voire des fournisseurs d'accès ou même des gouvernements, qui prennent des intermédiaires, délèguent à des intermédiaires qui font de même, ne sont pas à l'abri d'une malveillance ou d'un piratage et qu'aussi, on peut tout à fait légitimement ne pas vouloir leur faire confiance (perso, un certificat du gouvernement birman, je me méfierais…)
- les intermédiaires : Paul est le plus grand sage du village, tout le monde lui fait absolument confiance. Paul signe un papier à Nathalie indiquant qu'il accorde à Nathalie toute sa confiance. Nathalie fait de même avec Jacques, Clara et Maxime, qui font ensuite de même avec… Car oui : toute autorité de certification racine peut délivrer un certificat intermédiaire à qui bon lui semble. Ça vous parle ?
- malveillance ou piratage : le système des certificats repose sur une infrastructure à clefs publiques, c'est-à-dire qu'une clef publique est disponible à quiconque la veut et que cette clef permet de déchiffrer ce qui a été chiffré avec la clef privée correspondante. Par exemple, une autorité de certification utilise sa clef privée pour créer un certificat, puis tout le monde peut vérifier que le certificat est authentique en utilisant la clef publique associée. Un système très efficace… tant que la clef privée ne se retrouve pas dans la nature, comme c'est arrivé récemment à l'autorité de certification racine Comodo : une clef privée d'un de leurs intermédiaires ayant été compromise, plusieurs certificats frauduleux ont vu le jour, impactant des sites tels que ceux de Live, GMail ou Mozilla. Comme les certificats frauduleux avaient été créés avec la clef privée de l'intermédiaire lui-même agrée par Comodo dont les certificats racines sont intégrés d'office dans les navigateurs Web, vous imaginez bien que lesdits navigateurs n'y ont vu que du feu.
- accorder sa confiance : dans un pays comme la Chine, le gouvernement possède ses propres certificats racines qui sont évidemment installés dans tous les navigateurs. Cela signifie qu'au regard du gouvernement chinois, que vous vous connectiez en HTTP ou HTTPS ne fait aucune différence. La Chine c'est loin, me direz-vous, mais vu le nombre d'intermédiaires plus ou moins douteux, ça pourrait très bien arriver n'importe où (et d'ailleurs, c'est le cas, même si ce n'est pas forcément mis en place par un gouvernement ou à l'échelle d'une nation).
Je ne peux que vous inviter à lire les articles de SebSauvage à ce sujet ici et là et si vous ne le connaissez pas encore, prenez le temps de parcourir son site et de lire ses coups de gueule, ça vaut le coup.
C'est bien joli tout ça. Et donc… ?
Et donc, je n'ai toujours pas trouvé la solution idéale (et gagné des milliards avec (≧∇≦)アハハ八八ノヽノヽノヽノ \ / \), du genre chaîne de confiance véritable un peu dans le principe du WOT mais décentralisé + authentification DNS avec des DNS eux aussi décentralisés mais je me suis décidé à franchir un cap : créer ma propre autorité de certification racine. Ce qui nous amène directement au sujet principal de ce billet.
Be Your Own CA : comment devenir sa propre autorité de certification racine.
Ce qui suit est une adaptation de l'excellent tutoriel de David Pashley auquel vous pouvez vous reporter pour plus de détails.
Avant toute chose, il faut installer OpenSSL :
# apt-get install openssl
Puis l'on crée les répertoires qui vont accueillir notre certificat racine :
# mkdir -p /etc/own_ca/{conf,private,public} && chmod 400 /etc/own_ca/private
Cela va créer /etc/own_ca qui contiendra les répertoires conf, private et public.
- conf contiendra la configuration d'OpenSSL pour notre certificat racine
- private contiendra notre clef privée de CA
- public contiendra les certificats générés à l'aide de notre certificat racine
On se place dans le répertoire et on crée maintenant notre fichier de configuration pour OpenSSL :
# cd /etc/own_ca && vi conf/openssl.cnf
Dans ce fichier nous allons écrire ceci :
[ req ] default_bits = 4096 default_keyfile = ./private/root.pem default_md = sha1 prompt = no distinguished_name = root_ca_distinguished_name x509_extensions = v3_ca [ root_ca_distinguished_name ] countryName = FR stateOrProvinceName = Ile-de-France localityName = Paris 0.organizationName = MaCompagnie SA commonName = MaCompagnie SA Root CA emailAddress = adresse@domaine.tld [ v3_ca ] subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer:always basicConstraints = CA:true
Bien évidemment, vous devez remplacer ce qui est en rouge par vos propres informations.
Ensuite, nous pouvons créer notre clef :
# openssl req -nodes -config conf/openssl.cnf -days 3650 -x509 -newkey rsa:4096 -out public/root.pem -outform PEM
Votre terminal vous affiche alors un truc comme ça :
Generating a 4096 bit RSA private key ...........................................................++ ..............................++ writing new private key to './private/root.pem' -----
problems making Certificate Request
20347:error:0D07A098:asn1 encoding routines:ASN1_mbstring_ncopy:string too short:a_mbstr.c:147:minsize=1
c'est que vous avez oublié de renseigner un champ dans la section root_ca_distinguished_name, comme par exemple le champ stateOrProvinceName qu'on pourrait être tenté de laisser vide en France.
Vous avez donc votre clef privée dans private/root.pem et votre clef publique dans public/root.pem ; clefs de 4096 bits valides pour une durée de dix ans. Il nous faut maintenant le distribuer et le moyen le plus simple pour cela est de placer sur notre site un lien vers notre signature toute neuve :
# cp public/root.pem /var/www/mon-site.tld/MaCompagnie-SA.crt
Pour être certains que les clients reconnaissent correctement le fichier, nous le servons en déclarant son type MIME au serveur web :
Nginx :
# vi /etc/nginx/mime.types
on ajoute :
application/x-x509-ca-cert der pem crt cert;
dans la liste (s'il n'y est pas déjà).
Apache :
# vi /etc/apache2/httpd.conf
on ajoute :
AddType application/x-x509-ca-cert .crt .cert .pem
Comme certains clients demandent que la clef soit au format DER et que certains autres ont besoin que le nom de la clef soit le hash du certificat, nous allons créer ces deux clefs :
# openssl x509 -in public/root.pem -outform DER -out public/root.der # cp public/root.pem public/$(openssl x509 -noout -hash -in public/root.pem).0
Puisque nous avons nos clefs de CA racine, il faut que nous puissions signer les requêtes de certificats (CSR), c'est précisément dans ce but que nous faisons tout ceci :D !
On rouvre notre openssl.cnf :
# vi conf/openssl.cnf
On ajoute ceci à la suite de notre configuration :
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = .
new_certs_dir = ./signed-keys/
database = ./conf/index
certificate = ./public/root.pem
serial = ./conf/serial
private_key = ./private/root.pem
x509_extensions = usr_cert
name_opt = ca_default
cert_opt = ca_default
default_crl_days = 30
default_days = 365
default_md = sha1
preserve = no
policy = policy_match
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ usr_cert ]
basicConstraints=CA:FALSE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer:always
nsCaRevocationUrl = https://domaine.tld/exemple-ca-crl.pem
Sous la section [ CA_default ] vous pouvez éventuellement modifier la valeur de default_days qui règle la durée de validité par défaut des certificats que vous signez (365 jours en l'occurrence). N'oubliez pas de modifier la valeur de nsCaRevocationUrl (en rouge) afin de mettre la vôtre à la place : c'est l'adresse à laquelle les utilisateurs pourront se référer pour vérifier la liste de révocation de vos certificats.
Maintenant, il faut créer un répertoire pour accueillir les copies des certificats que l'on va signer afin de pouvoir facilement les trouver pour les révoquer en cas de besoin, un fichier pour accueillir les numéros de série et enfin un autre fichier pour y inscrire l'index de nos certificats signés :
# mkdir signed-keys && echo "01" > conf/serial && touch conf/index
Et voilà ! Nous sommes désormais une Autorité de Certification Racine à part entière même si bien évidemment non reconnue par les autres. Du coup, nous allons pouvoir signer les CSR qu'on voudra bien nous soumettre et ce, de la manière suivante : postulons qu'un tiers nous a fourni une CSR nommée request.csr en nous demandant de la signer. Nous allons d'abord nous assurer de l'exactitude des informations qu'elle contient :
# openssl req -in request.csr -noout -text
Certificate Request:
Data:
Version: 0 (0x0)
Subject: C=FR, ST=PACA, L=Marseille, O=MaCompagnie SA, CN=www.domaine.tld/emailAddress=adresse@domaine.tld
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (512 bit)
Modulus (512 bit):
00:d9:58:b4:ca:b5:0e:8b:86:f7:8c:16:7f:c6:a4:
74:90:cb:66:09:b6:a7:4d:e5:a1:d4:2e:cb:98:dc:
10:72:a0:9c:42:78:24:17:82:2c:0b:ff:d6:ea:67:
76:c7:60:01:ea:c7:cd:31:12:24:b4:c5:9d:02:09:
0a:d9:2b:f2:bd
Exponent: 65537 (0x10001)
Attributes:
a0:00
Signature Algorithm: sha1WithRSAEncryption
a6:e6:00:9c:f7:9e:20:08:b7:5c:4d:d4:32:e4:cb:0c:69:d2:
ad:19:f9:de:7c:9f:e1:76:05:a9:59:3e:05:6d:8b:3c:69:a2:
e3:8e:fe:e6:8b:a1:3f:a9:36:6a:80:da:c1:bb:5d:71:b3:63:
df:d4:17:6c:a3:9d:2a:62:3f:ff
La partie qui nous intéresse est en rouge dans l'exemple ci-dessus. Il faut être absolument certain que la personne qui demande le certificat est bien celle qui possède domaine.tld (il faut bien sûr vérifier aussi les autres critères, mais celui-ci est le plus important dans la mesure où c'est celui qui va être vérifié par le navigateur Web du client). Si nous sommes satisfaits des détails fournis et d'accord pour signer la requête, nous procédons alors comme suit :
# openssl ca -batch -config root.cnf -in request.csr -out request.cert Using configuration from conf/openssl.cnf Check that the request matches the signature Signature ok Certificate Details: Serial Number: 1 (0x1) Validity Not Before: Dec 9 18:29:33 2011 GMT Not After : Dec 9 18:29:33 2012 GMT Subject: countryName = FR stateOrProvinceName = PACA organizationName = MaCompagnie SA commonName = www.domaine.tld emailAddress = adresse@domaine.tld X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Subject Key Identifier: 4B:26:25:75:EE:74:63:2D:B5:07:E7:92:9F:B1:85:F6:B7:7A:78:24 X509v3 Authority Key Identifier: keyid:D5:FE:57:B9:E3:C2:6F:95:7C:29:8D:77:12:D7:94:09:43:D6:2C:52 DirName:/C=FR/ST=Ile-de-France/L=Paris/O=MaCompagnie SA/CN=MaCompagnie Root CA/emailAddress=adresse@domaine.tld serial:98:D7:B8:5A:5A:91:42:0F Netscape CA Revocation Url: https://www.doamine.tld/exemple-ca-crl.pem Certificate is to be certified until Apr 8 18:29:33 2007 GMT (365 days) Write out database with 1 new entries Data Base Updated
Après cette opération, nous nous retrouvons avec un certificat request.cert, certificat signé par nous et que nous pouvons renvoyer au demandeur. Si nous avons besoin de révoquer la signature, nous pouvons la retrouver dans signed-keys/01.pem. Par ailleurs, conf/serial a été incrémenté de 1 et conf/index a été mis a jour pour inclure les caractéristiques du nouveau certificat.
Pour pouvoir révoquer une clef, nous devons retourner une dernière fois dans notre fichier de configuration de OpenSSL :
# vi conf/openssl.cnf
On y ajoute :
[ crl_ext ] authorityKeyIdentifier=keyid:always,issuer:always
Pour révoquer une clef :
# openssl ca -config conf/openssl.cnf -revoke request.cert
qui donne :
Using configuration from conf/openssl.cnf Revoking Certificate 01. Data Base Updated
Ensuite, on génère la liste de révocation (CRL) :
# openssl ca -config conf/openssl.cnf -gencrl -out exemple-ca-crl.pem
Enfin, on place cette liste à l'endroit indiqué précédemment (https://domaine.tld/exemple-ca-crl.pem) afin que les clients puissent être avertis de la révocation.
Ça y est ! Nous somme notre propre Root CA et pouvons signer des certificats et les révoquer. Une dernière petite opération peut consister à installer notre certificat racine dans l'infrastructure CA de notre système :
# cp public/root.pem /usr/share/ca-certificates/MaCompagnie-SA.crt # echo MaCompagnie-SA.crt >> /etc/ca-certificates.conf # update-ca-certificates
Et voilà ! Y'a plus qu'à la former cette foutue chaîne de confiance ! En commençant par informer les visiteurs de vos sites et à leur demander de vous faire confiance.