9Déc

Devenir sa propre autorité de certification

Par , 9 décembre 2011 | GNU/Linux, Informatique, Sécurité | 2 Commentaires

Ces der­niers temps et de plus en plus sou­vent, le pro­to­cole TLS (ancien­ne­ment SSL) et sur­tout son implé­men­ta­tion dans le pro­to­cole HTTP (ce qui donne le HTTPS) est au cœur de nom­breux et vifs débats quant à la sécu­ri­té toute rela­tive que repré­sente la méthode d'authentification la plus répan­due : l'authentification du client TLS par cer­ti­fi­cat numérique.

L'authentification du client TLS par cer­ti­fi­cat numé­rique, qu'es aquò ?

C'est quand le client (vous, par l'intermédiaire de notre navi­ga­teur Web) authen­ti­fie le ser­veur TLS sur lequel il se connecte (le site de votre banque, votre boîte e‑mail sur un por­tail Web, etc.). Cette authen­ti­fi­ca­tion est réa­li­sée via l'utilisation d'un cer­ti­fi­cat numé­rique (sorte de carte d'identité vir­tuelle approu­vée par un tiers de confiance) X.509 (norme cryp­to­gra­phique des télé­coms) déli­vré par une auto­ri­té de cer­ti­fi­ca­tion (CA). Votre navi­ga­teur Web embarque tout un tas de cer­ti­fi­cats dits racines, c'est à dire issus direc­te­ment des auto­ri­tés de cer­ti­fi­ca­tion (com­mer­ciales pour leur très grande majo­ri­té) et auto-signés. Ces cer­ti­fi­cats font office d'autorités connues et per­mettent d'en signer d'autres (moyen­nant finance) : votre banque, par exemple, achète auprès d'une auto­ri­té de cer­ti­fi­ca­tion racine, disons VISA, une cer­ti­fi­ca­tion (et donc un cer­ti­fi­cat d'autorité inter­mé­diaire) afin de pou­voir créer ses propres cer­ti­fi­cats signés par celui (racine) de VISA. Ain­si, votre navi­ga­teur Web embar­quant le cer­ti­fi­cat racine de VISA, il pour­ra éta­blir une connexion sécu­ri­sée au site de votre banque de manière tota­le­ment trans­pa­rente pour vous : le cer­ti­fi­cat de la banque étant signé par VISA et le cer­ti­fi­cat de VISA étant recon­nu comme de confiance, le navi­ga­teur fera auto­ma­ti­que­ment confiance au cer­ti­fi­cat de la banque. Vous suivez ?

Et alors ? Il est où le problème ?

Eh bien, il réside prin­ci­pa­le­ment dans le fait que ces auto­ri­tés de cer­ti­fi­ca­tion sont — je l'ai déjà dit — des entre­prises com­mer­ciales (dont le but est donc de faire des pro­fits) voire des four­nis­seurs d'accès ou même des gou­ver­ne­ments, qui prennent des inter­mé­diaires, délèguent à des inter­mé­diaires qui font de même, ne sont pas à l'abri d'une mal­veillance ou d'un pira­tage et qu'aussi, on peut tout à fait légi­ti­me­ment ne pas vou­loir leur faire confiance (per­so, un cer­ti­fi­cat du gou­ver­ne­ment bir­man, je me méfierais…)

  • les inter­mé­diaires : Paul est le plus grand sage du vil­lage, tout le monde lui fait abso­lu­ment confiance. Paul signe un papier à Natha­lie indi­quant qu'il accorde à Natha­lie toute sa confiance. Natha­lie fait de même avec Jacques, Cla­ra et Maxime, qui font ensuite de même avec… Car oui : toute auto­ri­té de cer­ti­fi­ca­tion racine peut déli­vrer un cer­ti­fi­cat inter­mé­diaire à qui bon lui semble. Ça vous parle ?
  • mal­veillance ou pira­tage : le sys­tème des cer­ti­fi­cats repose sur une infra­struc­ture à clefs publiques, c'est-à-dire qu'une clef publique est dis­po­nible à qui­conque la veut et que cette clef per­met de déchif­frer ce qui a été chif­fré avec la clef pri­vée cor­res­pon­dante. Par exemple, une auto­ri­té de cer­ti­fi­ca­tion uti­lise sa clef pri­vée pour créer un cer­ti­fi­cat, puis tout le monde peut véri­fier que le cer­ti­fi­cat est authen­tique en uti­li­sant la clef publique asso­ciée. Un sys­tème très effi­cace… tant que la clef pri­vée ne se retrouve pas dans la nature, comme c'est arri­vé récem­ment à l'autorité de cer­ti­fi­ca­tion racine Como­do : une clef pri­vée d'un de leurs inter­mé­diaires ayant été com­pro­mise, plu­sieurs cer­ti­fi­cats frau­du­leux ont vu le jour, impac­tant des sites tels que ceux de Live, GMail ou Mozilla. Comme les cer­ti­fi­cats frau­du­leux avaient été créés avec la clef pri­vée de l'intermédiaire lui-même agrée par Como­do dont les cer­ti­fi­cats racines sont inté­grés d'office dans les navi­ga­teurs Web, vous ima­gi­nez bien que les­dits navi­ga­teurs n'y ont vu que du feu.
  • accor­der sa confiance : dans un pays comme la Chine, le gou­ver­ne­ment pos­sède ses propres cer­ti­fi­cats racines qui sont évi­dem­ment ins­tal­lés dans tous les navi­ga­teurs. Cela signi­fie qu'au regard du gou­ver­ne­ment chi­nois, que vous vous connec­tiez en HTTP ou HTTPS ne fait aucune dif­fé­rence. La Chine c'est loin, me direz-vous, mais vu le nombre d'intermédiaires plus ou moins dou­teux, ça pour­rait très bien arri­ver n'importe où (et d'ailleurs, c'est le cas, même si ce n'est pas for­cé­ment mis en place par un gou­ver­ne­ment ou à l'échelle d'une nation).

Je ne peux que vous invi­ter à lire les articles de Seb­Sau­vage à ce sujet ici et et si vous ne le connais­sez pas encore, pre­nez le temps de par­cou­rir 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 tou­jours pas trou­vé la solu­tion idéale (et gagné des mil­liards avec (≧∇≦)アハハ八八ノヽノヽノヽノ \ / \), du genre chaîne de confiance véri­table un peu dans le prin­cipe du WOT mais décen­tra­li­sé + authen­ti­fi­ca­tion DNS avec des DNS eux aus­si décen­tra­li­sés mais je me suis déci­dé à fran­chir un cap : créer ma propre auto­ri­té de cer­ti­fi­ca­tion racine. Ce qui nous amène direc­te­ment au sujet prin­ci­pal de ce billet.

Be Your Own CA : com­ment deve­nir sa propre auto­ri­té de cer­ti­fi­ca­tion racine.

Les ins­truc­tions ci-des­sous sont effec­tuées sur un sys­tème Debian. Elles devraient être trans­po­sables à tout sys­tème sur lequel on peut ins­tal­ler OpenSSL, néan­moins, soyez vigilant.

Ce qui suit est une adap­ta­tion de l'excellent tuto­riel de David Pash­ley auquel vous pou­vez vous repor­ter pour plus de détails.

Avant toute chose, il faut ins­tal­ler OpenSSL :

# apt-get install openssl

Puis l'on crée les réper­toires qui vont accueillir notre cer­ti­fi­cat racine :

# mkdir -p /etc/own_ca/{conf,private,public} && chmod 400 /etc/own_ca/private

Cela va créer /etc/own_ca qui contien­dra les réper­toires conf, pri­vate et public.

  • conf contien­dra la confi­gu­ra­tion d'OpenSSL pour notre cer­ti­fi­cat racine
  • pri­vate contien­dra notre clef pri­vée de CA
  • public contien­dra les cer­ti­fi­cats géné­rés à l'aide de notre cer­ti­fi­cat racine

On se place dans le réper­toire et on crée main­te­nant notre fichier de confi­gu­ra­tion 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 évi­dem­ment, vous devez rem­pla­cer ce qui est en rouge par vos propres informations.

Ensuite, nous pou­vons créer notre clef :

# openssl req -nodes -config conf/openssl.cnf -days 3650 -x509 -newkey rsa:4096 -out public/root.pem -outform PEM

Votre ter­mi­nal vous affiche alors un truc comme ça :

Generating a 4096 bit RSA private key
...........................................................++
..............................++
writing new private key to './private/root.pem'
-----

Si par contre vous obte­nez une erreur de type

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 ren­sei­gner un champ dans la sec­tion root_ca_distinguished_name, comme par exemple le champ sta­teOr­Pro­vin­ce­Name qu'on pour­rait être ten­té de lais­ser vide en France.


Vous avez donc votre clef pri­vé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 main­te­nant le dis­tri­buer et le moyen le plus simple pour cela est de pla­cer sur notre site un lien vers notre signa­ture toute neuve :
# cp public/root.pem /var/www/mon-site.tld/MaCompagnie-SA.crt

Pour être cer­tains que les clients recon­naissent cor­rec­te­ment le fichier, nous le ser­vons en décla­rant son type MIME au ser­veur 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 cer­tains clients demandent que la clef soit au for­mat DER et que cer­tains autres ont besoin que le nom de la clef soit le hash du cer­ti­fi­cat, 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 puis­sions signer les requêtes de cer­ti­fi­cats (CSR), c'est pré­ci­sé­ment dans ce but que nous fai­sons 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 sec­tion [ CA_default ] vous pou­vez éven­tuel­le­ment modi­fier la valeur de default_days qui règle la durée de vali­di­té par défaut des cer­ti­fi­cats que vous signez (365 jours en l'occurrence). N'oubliez pas de modi­fier la valeur de nsCa­Re­vo­ca­tio­nUrl (en rouge) afin de mettre la vôtre à la place : c'est l'adresse à laquelle les uti­li­sa­teurs pour­ront se réfé­rer pour véri­fier la liste de révo­ca­tion de vos certificats.

Main­te­nant, il faut créer un réper­toire pour accueillir les copies des cer­ti­fi­cats que l'on va signer afin de pou­voir faci­le­ment les trou­ver pour les révo­quer en cas de besoin, un fichier pour accueillir les numé­ros de série et enfin un autre fichier pour y ins­crire l'index de nos cer­ti­fi­cats signés :

# mkdir signed-keys && echo "01" > conf/serial && touch conf/index

Et voi­là ! Nous sommes désor­mais une Auto­ri­té de Cer­ti­fi­ca­tion Racine à part entière même si bien évi­dem­ment non recon­nue par les autres. Du coup, nous allons pou­voir signer les CSR qu'on vou­dra bien nous sou­mettre et ce, de la manière sui­vante : pos­tu­lons qu'un tiers nous a four­ni une CSR nom­mée request.csr en nous deman­dant de la signer. Nous allons d'abord nous assu­rer de l'exactitude des infor­ma­tions 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 par­tie qui nous inté­resse est en rouge dans l'exemple ci-des­sus. Il faut être abso­lu­ment cer­tain que la per­sonne qui demande le cer­ti­fi­cat est bien celle qui pos­sède domaine.tld (il faut bien sûr véri­fier aus­si les autres cri­tères, mais celui-ci est le plus impor­tant dans la mesure où c'est celui qui va être véri­fié par le navi­ga­teur Web du client). Si nous sommes satis­faits des détails four­nis et d'accord pour signer la requête, nous pro­cé­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é­ra­tion, nous nous retrou­vons avec un cer­ti­fi­cat request.cert, cer­ti­fi­cat signé par nous et que nous pou­vons ren­voyer au deman­deur. Si nous avons besoin de révo­quer la signa­ture, nous pou­vons la retrou­ver dans signed-keys/01.pem. Par ailleurs, conf/serial a été incré­men­té de 1 et conf/index a été mis a jour pour inclure les carac­té­ris­tiques du nou­veau certificat.

Pour pou­voir révo­quer une clef, nous devons retour­ner une der­nière fois dans notre fichier de confi­gu­ra­tion de OpenSSL :

# vi conf/openssl.cnf

On y ajoute :

[ crl_ext ]
authorityKeyIdentifier=keyid:always,issuer:always

Pour révo­quer 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évo­ca­tion (CRL) :

# openssl ca -config conf/openssl.cnf -gencrl -out exemple-ca-crl.pem

Enfin, on place cette liste à l'endroit indi­qué pré­cé­dem­ment (https://domaine.tld/exemple-ca-crl.pem) afin que les clients puissent être aver­tis de la révocation.

Ça y est ! Nous somme notre propre Root CA et pou­vons signer des cer­ti­fi­cats et les révo­quer. Une der­nière petite opé­ra­tion peut consis­ter à ins­tal­ler notre cer­ti­fi­cat 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 voi­là ! Y'a plus qu'à la for­mer cette fou­tue chaîne de confiance ! En com­men­çant par infor­mer les visi­teurs de vos sites et à leur deman­der de vous faire confiance.

Back to top

Pas peur d'Hadopi

Ce site Web est accessible en




ipv6 ready