Date de publication du RFC : Mars 2019
Auteur(s) du RFC : R. Barnes (Cisco), J. Hoffman-Andrews (EFF), D. McCarney (Let's Encrypt), J. Kasten (University of Michigan)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF acme
Première rédaction de cet article le 11 avril 2019
Une grande partie de la sécurité du Web, et d'ailleurs de plein d'autres chose sur l'Internet, repose sur des certificats où une Autorité de Certification (AC) garantit que vous êtes bien ce que vous prétendez être. Traditionnellement, l'émission d'un certificat se faisait selon un processus manuel, lent et coûteux, à part dans quelques AC automatisées et gratuites comme CAcert. Mais il n'existait pas de mécanisme standard pour cette automatisation. (Et CAcert n'a pas d'API, même non-standard.) Un tel mécanisme standard existe désormais, avec le protocole ACME, normalisé dans ce RFC. Son utilisateur le plus connu est l'AC Let's Encrypt.
Pour comprendre ACME, il faut d'abord revenir aux utilisations des certificats. La norme technique pour les certificats utilisés sur l'Internet se nomme PKIX et est normalisée dans le RFC 5280. PKIX est un profil (une restriction d'une norme beaucoup plus large - et bien trop large, comme le sont souvent les normes des organismes comme l'UIT ou l'ISO) de X.509. Un certificat PKIX comprend, entre autres :
On note que le certificat est public. N'importe qui peut récupérer
le certificat de, par exemple, un site Web. Voici un exemple avec
OpenSSL et
www.labanquepostale.fr
pour un certificat de
type EV :
% openssl s_client -connect www.labanquepostale.fr:443 -showcerts | openssl x509 -text Certificate: Data: Version: 3 (0x2) Serial Number: 0d:8f:ec:dd:d8:7b:83:b8:a0:1e:eb:c2:a0:2c:10:9b Signature Algorithm: sha256WithRSAEncryption Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert SHA2 Extended Validation Server CA Validity Not Before: Sep 5 00:00:00 2018 GMT Not After : Sep 4 12:00:00 2020 GMT Subject: businessCategory = Private Organization, jurisdictionC = FR, serialNumber = 421 100 645, C = FR, L = PARIS, O = LA BANQUE POSTALE SA, OU = DISFE, CN = www.labanquepostale.fr ...
et un avec GnuTLS
pour un certificat DV (Domain Validation), mamot.fr
:
% gnutls-cli mamot.fr - subject `CN=mamot.fr', issuer `CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US', serial 0x035516154ab9120c186e9211d0da6296af62, RSA key 2048 bits, signed using RSA-SHA256, activated `2019-01-13 23:00:32 UTC', expires `2019-04-13 23:00:32 UTC', key-ID `sha256:ef62c4aae2a9a99c00c33f2bbac9c40b980c70400a056e2a8042885e501ce283' ...
D'ailleurs, des services comme Certificate
Transparency (RFC 6962), accessible entre autres en
, donnent accès facilement à
tous les certificats émis par les AC
participantes.https://crt.sh/
Du fait que seul le titulaire connait la clé privée, la capacité à signer des messages vérifiables avec la clé publique permet d'authentifier le partenaire avec lequel on communique. Grâce à la signature de l'AC, quiconque fait confiance à cette AC particulière peut être sûr que le certificat appartient bien au titulaire. Dans l'exemple avec OpenSSL, le certificat de la Banque Postale était signé par DigiCert, si on fait confiance à DigiCert, on sait qu'on est bien connecté à la Banque Postale.
Qui sont les AC ? Ce sont la plupart du temps des entreprises
commerciales qui sont payées par les titulaires de certificat, et
elles sont censées vérifier la sincérité de leurs clients. Cette
vérification peut être manuelle, partiellement ou totalement
automatique. Normalement, les certificats de type EV
(Extended Validation), comme celui de la Banque
Postale plus haut, font l'objet d'une vérification manuelle. Cela
permet de vérifier l'identité officielle (celle gérée par l'État)
du titulaire. Les certificats DV (Domain
Validation), comme celui de
mamot.fr
, eux, peuvent être validés
automatiquement, ils assurent uniquement le fait que le titulaire
contrôle bien le nom de
domaine utilisé comme sujet. (Pour avoir tous les
horribles détails, y compris les certificats OV - Organization Validated - dont je n'ai pas
parlé, on peut consulter les « Baseline
Requirements for the Issuance and Management of Publicly-Trusted
Certificates » du CA/Browser
Forum.) Ainsi, pour CAcert, on doit prouver le contrôle du
domaine en répondant aux courriers envoyés aux adresses publiques
de contact pour le domaine.
Les certificats peuvent servir à de nombreux protocoles de sécurité mais le plus connu est TLS (normalisé dans le RFC 8446). Comme il n'est pas le seul protocole pour lequel on a des certificats, il est erroné de parler de « certificats TLS » ou, pire encore, de « certificats SSL ». TLS est un protocole client/serveur, où le client authentifie le serveur mais où le serveur authentifie rarement le client. Il est à la base de la sécurisation d'un grand nombre de services sur l'Internet, à commencer par le Web avec HTTPS (RFC 2818). L'authentification du serveur par le client est faite en vérifiant (attention, je vais simplifier) :
Une fois cette authentification faite, TLS assure l'intégrité et la confidentialité de la communication.
Attention, on parle bien d'authentification, pas de
confiance. Malgré ce que vous pourrez lire dans les « La sécurité
pour les nuls », le fameux « cadenas vert » ne signifie pas du
tout que vous pouvez faire vos achats en ligne en toute
sécurité. Il indique seulement que le partenaire a bien le nom que
vous avez demandé, et qu'un tiers ne pourra pas écouter ou
modifier la conversation. Il n'indique pas
que le partenaire soit digne de confiance ; l'AC ne peut pas
vérifier cela ! Ainsi, dans l'exemple plus haut, TLS et
l'authentification par certificat garantissent bien qu'on se
connecte au serveur HTTPS de la Maison-Blanche,
www.whitehouse.gov
, mais pas que
Trump dise la vérité !
J'ai parlé du magasin où se trouvent les clés des AC à qui on fait confiance. Qui décide du contenu de ce magasin ? C'est une question complexe, il n'y a pas une liste d'AC faisant autorité. La plupart des systèmes d'exploitation ont une liste à eux, créée en suivant des critères plus ou moins opaques. Les applications (comme le navigateur Web) utilisent ce magasin global du système ou, parfois, ont leur propre magasin, ce qui aggrave encore la confusion. Les utilisateurs peuvent (c'est plus ou moins facile) ajouter des AC ou bien en retirer.
Et comment obtient-on un certificat ? Typiquement, on crée d'abord une demande de certificat (CSR pour Certificate Signing Request, cf. RFC 2986). Avec OpenSSL, cela peut se faire avec :
% openssl req -new -nodes -newkey rsa:2048 -keyout server.key -out server.csr
On se connecte ensuite au site Web de l'AC choisie, et on lui soumet le CSR. Ici, un exemple avec CAcert :
L'AC doit alors faire des vérifications, plus ou moins rigoureuses. Par exemple, l'AC fait une requête whois, note l'adresse de courrier du domaine, envoie un message contenant un défi et le client de l'AC doit y répondre pour prouver qu'il a bien accès à cette adresse et contrôle donc bien le domaine. L'AC crée ensuite le certificat qu'elle vous renvoie. Il faut alors l'installer sur le serveur (HTTPS, par exemple). L'opération est complexe, et beaucoup d'utilisateurs débutants cafouillent.
C'est ce processus non-standard et compliqué que le protocole ACME vise à normaliser et à automatiser. Ce RFC a une longue histoire mais est déjà déployé en production par au moins une AC.
Le principe d'ACME est simple : l'AC fait tourner un serveur
ACME, qui attend les requêtes des clients. Le client ACME (un
logiciel comme dehydrated ou
certbot) génère la
CSR, se connecte au serveur, et demande un certificat signé pour
un nom donné. Le serveur va alors renvoyer un
défi qui va permettre au client de prouver
qu'il contrôle bien le nom de domaine demandé. Il existe plusieurs
types de défis, mais le plus simple est un nom de fichier
que le serveur ACME choisit, demandant au client ACME de mettre un
fichier de ce nom sur son site Web. Si le nom de fichier était
Vyzs0Oqkfa4gn4skMwszORg6vJaO73dvMLN0uX38TDw
,
le serveur ACME va devenir client HTTP et chercher à récupérer
http://DOMAIN/.well-known/acme-challenge/Vyzs0Oqkfa4gn4skMwszORg6vJaO73dvMLN0uX38TDw
. S'il
y réussit, il considère que le client ACME contrôle bien le nom de
domaine, et il signe alors le certificat, qui est renvoyé au
client lorsque celui-ci soumet la CSR.
Le modèle idéal d'utilisation d'ACME est présenté dans la section 2. (En pratique, il n'est pas vraiment réalisé, notamment parce qu'il n'existe pratiquement qu'une seule AC utilisant ACME, Let's Encrypt. Il n'y a donc pas encore beaucoup de diversité.) L'espoir est qu'un jour, on puisse faire comme suit :
Ainsi, une procédure manuelle et pénible pourra devenir assez simple, encourageant une présence en ligne plus sécurisée. Cela pourrait devenir aussi simple que d'avoir un certificat auto-signé.
La section 4 du RFC expose de manière générale le protocole ACME (le RFC complet fait 94 pages, car il y a beaucoup de détails à spécifier). Rappelez-vous avant de la lire que, pour ACME, le client est celui qui demande le certificat (c'est donc typiquement un serveur Internet, par exemple un serveur HTTPS) et le serveur ACME est l'AC. Quand je dirais « client » ou « serveur » tout court, il s'agira du client et du serveur ACME.
ACME encode ses messages en JSON (RFC 8259). Le client doit d'abord avoir un compte auprès du serveur (avec Let's Encrypt, cela peut être fait automatiquement sans que l'utilisateur s'en rende compte). Par exemple, avec dehydrated, cela se fait ainsi :
% dehydrated --register --accept-terms + Generating account key... + Registering account key with ACME server... + Done!
Et on trouve dans le répertoire accounts/
la
clé privée du compte, et les informations du compte :
% cat accounts/aHR0cHM6Ly9...9yeQo/registration_info.json { "id": 5...1, "key": { "kty": "RSA", "n": "wv...HCk", "e": "AQAB" }, "contact": [], "initialIp": "2001:4b98:dc0:41:216:3eff:fe27:3d3f", "createdAt": "2019-03-12T19:32:20.018154799Z", "status": "valid" }
Pour certbot, on peut le faire tourner avec l'option
-v
pour avoir les mêmes informations. certbot
affiche également des messages d'ordre administratif comme :
Enter email address (used for urgent renewal and security notices) (Enter 'c' to cancel): stephane+letsencrypt@bortzmeyer.org ... Please read the Terms of Service at https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must agree in order to register with the ACME server at https://acme-v02.api.letsencrypt.org/directory - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (A)gree/(C)ancel: A JWS payload: b'{\n "contact": [\n "mailto:stephane+letsencrypt@bortzmeyer.org"\n ],\n "termsOfServiceAgreed": true,\n "resource": "new-reg"\n}' { "id": 53367492, "key": { ... "contact": [ "mailto:stephane+letsencrypt@bortzmeyer.org" ], "createdAt": "2019-03-15T16:07:58.29914038Z", "status": "valid" } Reporting to user: Your account credentials have been saved in your Certbot configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Would you be willing to share your email address with the Electronic Frontier Foundation, a founding partner of the Let's Encrypt project and the non-profit organization that develops Certbot? We'd like to send you email about our work encrypting the web, EFF news, campaigns, and ways to support digital freedom. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: No ...
Le compte sera authentifié en utilisant une biclé (clé privée et clé publique). Il y aura ensuite quatre étapes :
Mais comment transporte-t-on ces messages en JSON ? La section 6 du RFC répond à cette question : on utilise HTTPS. En prime, les messages sont signés avec JWS (RFC 7515), en utilisant la clé privée du client pour les requêtes. Voici par exemple la réponse d'un serveur ACME lorsqu'on l'interroge sur un défi en cours :
{ "type": "http-01", "status": "pending", "url": "https://acme-v02.api.letsencrypt.org/acme/challenge/7TAkQBMmFqm8Rhs6Sn8SFCne2MoZXoEHCz0Px7f0dpE/13683685175", "token": "mMXGXjEijKBZXl2RuL0rjlektPPpy-ozJpZ2vB4w6Dw" }
Les messages d'erreur utilisent le RFC 7807. En voici un exemple :
{ "type": "http-01", "status": "invalid", "error": { "type": "urn:acme:error:unauthorized", "detail": "Invalid response from http://mercredifiction.bortzmeyer.org/.well-known/acme-challenge/rE-rIfjjCfMlivxLfoJmMbRyspwmld97Xnxmy7K0-JA: \"\u003c!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"\u003e\n\u003chtml\u003e\u003chead\u003e\n\u003ctitle\u003e404 Not Found\u003c/title\u003e\n\u003c/head\u003e\u003cbody\u003e\n\u003ch1\u003eNot Found\u003c/h1\u003e\n\u003cp\"", "status": 403 ... [Le message d'erreur indique également typiquement l'URL demandé, et les adresses IP utilisées, ce qui est crucial si le serveur HTTP a plusieurs adresses IP, par exemple une en IPv4 et une en IPv6. Il faut donc bien lire tout le message d'erreur.]
Une liste des erreurs possibles est enregistrée à l'IANA. Voici par exemple une erreur CAA (RFC 8659) :
"error": { "type": "urn:acme:error:caa", "detail": "CAA record for mercredifiction.bortzmeyer.org prevents issuance", "status": 403 },
Comment un client ACME trouve-t-il les
URL pour les différentes opérations ? Il y
a un URL à connaitre, le répertoire
(directory). Une requête à cet URL (par exemple
curl
https://acme-v02.api.letsencrypt.org/directory
va renvoyer
un objet JSON qui contient la liste des autres URL (section 7, une
des plus cruciales du RFC). Voici un exemple chez Let's
Encrypt :
{ ... "meta": { "caaIdentities": [ "letsencrypt.org" ], "termsOfService": "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf", "website": "https://letsencrypt.org" }, "newAccount": "https://acme-v02.api.letsencrypt.org/acme/new-acct", "newNonce": "https://acme-v02.api.letsencrypt.org/acme/new-nonce", "newOrder": "https://acme-v02.api.letsencrypt.org/acme/new-order", "revokeCert": "https://acme-v02.api.letsencrypt.org/acme/revoke-cert" }
On peut ensuite créer un compte (le champ
newAccount
dans l'exemple ci-dessus) puis demander
des certificats (champ newOrder
dans
l'exemple ci-dessus), ici (Let's Encrypt) en écrivant à
https://acme-v02.api.letsencrypt.org/acme/new-order
:
{ "payload": "ewogICJpZGVudGlmaWVycyI6IFsKICAgIHsKICAgICAgInR5cGUiOiAiZG5zIiwKICAgICAgInZhbHVlIjogInRlc3QtYWNtZS5ib3J0em1leWVyLmZyIgogICAgfQogIF0KfQ", "protected": "eyJhbGciOiAiUlMyNTYiLCAidXJsIjogImh0dHBzOi8vYWNtZS12MDIuYXBpLmxldHNlbmNyeXB0Lm9yZy9hY21lL25ldy1vcmRlciIsICJraWQiOiAiaHR0cHM6Ly9hY21lLXYwMi5hcGkubGV0c2VuY3J5cHQub3JnL2FjbWUvYWNjdC81MzE3NzA1MCIsICJub25jZSI6ICJyZXNXTXFtQkJYbVZrZ2JfSnVQU3VEcmlmQzhBbDZrTm1JeDZuNkVwRDFZIn0", "signature": "MP9rXTjX4t1Be-y6dhPOP7JE3B401wokydUlG8gJGWqibTM_gydkUph1smtrUZ5W4RXNTEnlmiFwoiU4eHLD-8MzN5a3G668VbgzKd0VN7Y1GxQBGtsj9fShx4VMjSGLzVq1f7bKCbdX3DYn0LaiRDApgNXiMfoEnPLltu5Ud7RBNOaWY8zE0yAV7e3NFlF9Wfaii5Ff9OT1ZCD8LusOHP-gA4VkimQ9ofYr32wZYgsUFu6G--QflP0tjc5eKYMe1cKlgpyKZsDtBurWwvKlj2cU_PUdOZvjXSBbHX18jVlwglzfFnu0xTaDGTTvOuMBfjnWJCWpr-oA7Ih48dL-Jg" }
Eh oui, tout est signé, en JWS (RFC 7515) et base64isé (cf. section 7.4 du RFC). Ici, le décodage Base64 nous dira que la requête était :
{ { "identifiers": [ { "type": "dns", "value": "test-acme.bortzmeyer.fr" } ] } , {"alg": "RS256", "url": "https://acme-v02.api.letsencrypt.org/acme/new-order", "kid": "https://acme-v02.api.letsencrypt.org/acme/acct/53177050", "nonce": "resWMqmBBXmVkgb_JuPSuDrifC8Al6kNmIx6n6EpD1Y"} }
Donc, une demande de certificat pour test-acme.bortzmeyer.fr
.
Les autres opérations possibles avec un serveur ACME sont enregistrées à l'IANA. Par exemple, on peut révoquer un certificat.
La réponse sera :
{ "status": "pending", "expires": "2019-03-19T19:50:41.434669372Z", "identifiers": [ { "type": "dns", "value": "test-acme.bortzmeyer.fr" } ], "authorizations": [ "https://acme-v02.api.letsencrypt.org/acme/authz/FVMFaHS_oWjqfR-rWd6eBKMlt1EWfIcf6i7D4wU_swM" ], "finalize": "https://acme-v02.api.letsencrypt.org/acme/finalize/53177050/352606317" }
Le client ACME va alors télécharger l'autorisation à l'URL
indiqué, récupérant ainsi les défis qu'il devra affronter (section
7.5 du RFC). Une fois qu'il a fait ce qui lui était demandé par le
serveur, il utilise l'URL donné dans le champ
finalize
pour indiquer au serveur que c'est
bon, que le serveur peut vérifier. La commande
certbot
avec l'option -v
vous permettra de voir tout ce dialogue.
Le protocole ACME peut être utilisé par d'autres AC que Let's
Encrypt. Avec le client dehydrated, il suffira, quand de telles AC
seront disponibles, de mettre CA=URL
dans le
fichier de configuration (l'URL par défaut est
https://acme-v02.api.letsencrypt.org/directory
). Un exemple d'autre AC utilisant ACME est BuyPass (pas testé).
Mais en quoi consistent exactement les
défis, dont j'ai déjà parlé plusieurs fois ?
La section 8 les explique. L'idée de base d'un défi ACME est de
permettre de prouver qu'on contrôle réellement un identificateur,
typiquement un nom de
domaine. ACME ne normalise pas un type de défi
particulier. Le cadre est ouvert, et de nouveaux défis pourront
être ajoutés dans le futur. Le principe est toujours le même :
demander au client ACME de faire quelque chose que seul le vrai
titulaire de l'identificateur pourrait faire. Un défi, tel
qu'envoyé par le serveur ACME, a un type (le plus utilisé
aujourd'hui, est de loin, est le défi
http-01
), un état (en attente ou bien, au
contraire, validé) et un texte d'erreur, au cas où la validation
ait échoué. Plusieurs défis, comme http-01
ont également un jeton, un cookie, un texte
généré par le serveur, et non prévisible par le client ou par le
reste du monde, et qu'il faudra placer quelque part où le serveur
pourra le vérifier. Le serveur ACME ne testera que lorsque le
client lui aura dit « c'est bon, je suis prêt, j'ai fait tout ce
que tu m'as défié de faire ». Le RFC demande également au serveur
de réessayer après cinq ou dix secondes, si la vérification ne
marche pas du premier coup, au cas où le client ait été trop
rapide à se dire prêt.
Le plus connu et le plus utilisé des défis, à l'heure actuelle,
est http-01
. Le client ACME doit configurer
un serveur HTTP où une page (oui, je sais,
le terme correct est « ressource ») a comme nom le contenu du
jeton. Le serveur ACME va devenir client HTTP pour récupérer cette
page et, s'il y arrive, cela prouvera que le client contrôlait
bien le nom de domaine qu'il avait indiqué. De manière
surprenante, et qui déroute beaucoup de débutants, le défi se fait
bien sur HTTP et pas HTTPS, parce que beaucoup d'hébergements Web
partagés ne donnent pas suffisamment de contrôle à l'hébergé.
Le jeton est une chaîne de caractères utilisant le jeu de caractères de Base64, pour passer partout. Voici un exemple de défi HTTP envoyé par le serveur :
{ "identifier": { "type": "dns", "value": "test-acme.bortzmeyer.fr" }, "status": "pending", "expires": "2019-03-19T19:50:41Z", "challenges": [ { "type": "http-01", "status": "pending", "url": "https://acme-v02.api.letsencrypt.org/acme/challenge/FVMFaHS_oWjqfR-rWd6eBKMlt1EWfIcf6i7D4wU_swM/13574068498", "token": "4kpeqw7DVMrY6MI3tw1-tTq9oySN2SeMudaD32IcxNM" } ...
L'URL qu'utilisera le serveur est
http://DOMAINE-DEMANDÉ/.well-known/acme-challenge/JETON
(ou, en syntaxe du RFC 6570,
http://{domain}/.well-known/acme-challenge/{token}
). Comme
expliqué plus haut, c'est bien http://
et pas
https://
. Les URL avec
.well-known
sont documentés dans le RFC 8615 et acme-challenge
est désormais dans
le registre.
Imaginons qu'on utilise le serveur HTTP Apache et qu'on veuille répondre à ce défi. Le plus simple est de configurer le serveur ainsi :
<VirtualHost *:80> Alias /.well-known/acme-challenge /var/lib/dehydrated/acme-challenges <Directory /var/lib/dehydrated/acme-challenges> Options None AllowOverride None ...
Cela indique à Apache que les réponses aux défis seront dans le
répertoire
/var/lib/dehydrated/acme-challenges
,
répertoire où le client ACME dehydrated va mettre ses
fichiers. Avec le serveur HTTP Nginx, le
principe est le même :
server { location ^~ /.well-known/acme-challenge { alias /var/lib/dehydrated/acme-challenges; } }
Bien sûr, de nombreuses autres solutions sont possibles. Le serveur HTTP peut intégrer le client ACME, par exemple. Autre exemple, le client ACME certbot inclut son propre serveur HTTP, et peut donc répondre aux défis tout seul, sans Apache.
Ensuite, on lance le client ACME, éventuellement en lui spécifiant où il doit écrire la réponse aux défis :
% certbot certonly --webroot -w /usr/share/nginx/html -d MONDOMAINE.eu.org
certbot va mettre le certificat généré et signé dans son
répertoire, typiquement
/etc/letsencrypt/live/MONDOMAINE.eu.org/fullchain.pem
. Et
on programme son système (par exemple avec
cron) pour relancer le client ACME tous les
jours (les clients ACME typique vérifient la date d'expiration du
certificat, et n'appellent l'AC que si cette date est proche.)
Notez bien qu'il est crucial de superviser l'expiration des
certificats. On voit fréquemment des sites Web utilisant
Let's Encrypt devenir inaccessibles parce que le certificat a été
expiré. Beaucoup d'administrateurs système
croient que parce que Let's Encrypt est « automatique », il n'y a
aucun risque. Mais ce n'est pas vrai : non seulement la commande
de renouvellement peut ne pas être exécutée, ou bien mal se passer
mais, même si le certificat est bien renouvellé, cela ne garantit
pas que le serveur HTTP soit rechargé.
Petite anecdote personnelle : pour le blog que vous êtes en train de lire, cela avait été un peu plus compliqué. En effet, le blog a deux copies, sur deux machines différentes. J'ai donc du rediriger les vérifications ACME sur une seule des deux machines. En Apache :
ProxyRequests Off ProxyPass /.well-known/acme-challenge/ http://MACHINE-DE-RÉFÉRENCE.bortzmeyer.org/.well-known/acme-challenge/ ProxyPreserveHost On
À noter qu'un serveur HTTP paresseux qui se contenterait de
répondre 200 (OK) à chaque requête sous
/.well-known/acme-challenge
n'arriverait pas à répondre
avec succès aux défis HTTP. En effet, le fichier doit non
seulement exister mais également contenir une chaîne de caractères
faite à partir d'éléments fournis par le serveur ACME (cf. section 8.3).
Un autre type de défi répandu est le défi
dns-01
, où le client doit mettre dans le
DNS un enregistrement
TXT
_acme-challenge.DOMAINE-DEMANDÉ
contenant le jeton. Cela nécessite donc un serveur
DNS faisant autorité qui permette les mises à jour dynamiques, via
le RFC 2136 ou bien via une
API. Notez que le RFC recommande (section
10.2) que l'AC fasse ses requêtes DNS via un résolveur qui valide
avec DNSSEC. (Le serveur ACME ne demande pas
directement aux serveurs faisant autorité, il passe par un
résolveur. Attention donc à la mémorisation par les résolveurs des
réponses, jusqu'au TTL.)
On peut utiliser le défi DNS avec des jokers (pour avoir un
certificat pour *.MONDOMAINE.fr
) mais c'est
un peu plus compliqué (section 7.1.3 si vous voulez vraiment les détails).
D'autres types de défis pourront être ajouté dans le futur. Un
registre
IANA en garde la liste. Notez que des types de défis
peuvent également être supprimés comme
tls-sni-01
et tls-sni-02
, jugés à l'usage pas assez sûrs.
Le but de ce RFC est la sécurité, donc toute faiblesse d'ACME dans ce domaine serait grave. La section 10 du RFC se penche donc sur la question. Elle rappelle les deux objectifs de sécurité essentiels :
Le RFC 3552 décrit le modèle de menace typique de l'Internet. ACME a deux canaux de communication, le canal ACME proprement dit, utilisant HTTPS, et le canal de validation, par lequel se vérifient les réponses aux défis. ACME doit pouvoir résister à des attaques passives et actives sur ces deux canaux.
ACME n'est qu'un protocole, il reçoit des demandes, envoie des
requêtes, traite des réponses, mais il ne sait pas ce qui se passe
à l'intérieur des machines. Les défis, par exemple, peuvent être
inutiles si la machine testée est mal gérée (section 10.2). Si, par exemple, le
serveur HTTP est sur un serveur avec plusieurs utilisateurs, et où
tout utilisateur peut bricoler la configuration HTTP, ou bien
écrire dans le répertoire .well-known
, alors
tout utilisateur sur ce serveur pourra avoir un certificat. Idem
évidemment si le serveur est piraté. Et, si on sous-traite le
serveur de son organisation à l'extérieur, le sous-traitant peut
également faire ce qu'il veut et obtenir des certificats pour son
client (« il n'y a pas de
cloud, il y a juste
l'ordinateur de quelqu'un d'autre »).
ACME permet d'obtenir des certificats DV et ceux-ci dépendent évidemment des noms de domaine et du DNS. Un attaquant qui peut faire une attaque Kaminsky, par exemple, peut envoyer les requêtes du serveur ACME chez lui. Plus simple, même si le RFC n'en parle guère (il se focalise sur les attaques DNS, pas sur celles portant sur les noms de domaine), un attaquant qui détourne le nom de domaine, comme vu fin 2018 au Moyen-Orient, peut évidemment obtenir les certificats qu'il veut, contrairement à la légende répandue comme quoi TLS protègerait des détournements.
Comment se protéger contre ces attaques ? Le RFC recommande d'utiliser un résolveur DNS validant (vérifiant les signatures DNSSEC) ce que peu d'AC font (Let's Encrypt est une exception), de questionner le DNS depuis plusieurs points de mesure, pour limiter l'efficacité d'attaques contre le routage (cf. celle contre MyEtherWallet en avril 2018), et pourquoi pas d'utiliser TCP plutôt qu'UDP pour les requêtes DNS (ce qui présente l'avantage supplémentaire de priver de certificat les domaines dont les serveurs de noms sont assez stupides pour bloquer TCP). Voir aussi la section 11.2, qui revient sur ces conseils pratiques. Par exemple, une AC ne doit évidemment pas utiliser le résolveur DNS de son opérateur Internet, encore moins un résolveur public.
ACME est un protocole, pas une politique. L'AC reste maitresse de sa poltique d'émission des certificats. ACME ne décrit donc pas les autres vérifications qu'une AC pourrait avoir envie de faire :
Les certificats DV (ceux faits avec ACME) sont sans doute moins fiables que les EV (les DV n'ont qu'une vérification automatique, avec peu de sécurité puisque, par exemple, DNSSEC n'est pas obligatoire) et il est donc prudent de limiter leur durée de validité. Let's Encrypt fait ainsi des certificats à courte durée de vie, seulement trois mois, mais ce n'est pas trop grave en pratique, puisque le renouvellement peut être complètement automatisé.
Quels sont les mises en œuvre disponibles d'ACME ? Comme le RFC
est publié longtemps après les premiers déploiements, il y en a
déjà pas mal. Let's Encrypt maintient une
liste de clients. Personnellement, j'ai pratiqué certbot et dehydrated
mais il en existe d'autres, comme acme-tiny, qui
semble simple et compréhensible. Un avantage que je trouve à
dehydrated est qu'il est bien plus simple de garde sa clé lors des
renouvellements, par exemple pour
DANE : il suffit de mettre
PRIVATE_KEY_RENEW="no"
dans le fichier de
configuration. En revanche, dehydrated est à la fois pas assez et
trop bavard. Pas assez car il n'a pas d'option permettant de voir
la totalité du dialogue en JSON avec le serveur (contrairement à
certbot) et trop car il affiche des messages même quand il n'a rien
fait (parce que le certificat était encore valide pour assez
longtemps). Pas moyen de le faire taire, et rediriger la sortie
standard ne marche pas car on veut savoir quand il y a eu
renouvellement effectif.
On dispose également de bibliothèques
permettant au programmeur ou à la programmeuse de développer plus
facilement un client ACME. (Par exemple
Protocol::ACME
(encore que j'ai l'impression qu'il n'est plus maintenu, un
programmeur Perl disponible pour évaluer ce
qui existe ?). Pour les programmeures
Python, il y a le module
acme
qui est celui utilisé par le client
certbot, mais qui est aussi distribué indépendamment. En
Go, il y a LeGo. Mais on peut aussi
mettre le client ACME dans le serveur HTTP, comme le permet
Apache
Et les serveurs ACME ? Évidemment, peu de gens monteront une AC mais, si vous voulez le faire, le serveur de Let's Encrypt, Boulder, est en logiciel libre.
Notez que ce RFC ne parle que de la validation de noms de domaines mais ACME pourra, dans le futur, être utilisé pour valider la « possession » d'une adresse IP, ou d'autres identifiants.
Et si vous voulez un résumé rapide d'ACME par ses auteurs, allez lire cet article sur le blog de l'IETF.
Version PDF de cette page (mais vous pouvez aussi imprimer depuis votre navigateur, il y a une feuille de style prévue pour cela)
Source XML de cette page (cette page est distribuée sous les termes de la licence GFDL)