Nous écrivons un plugin pour recevoir les certificats génériques Let's Encrypt

Bonjour à nouveau, cher lecteur. Le deuxième chapitre sur les aventures de Let's Encrypt dans le panneau ISPmanager est déclaré ouvert. Dans un article précédent, nous avons discuté du plugin pour ACME v01. Dans ce document, nous parlerons de son évolution du point de vue de la logique de travail avec l'utilisateur et, bien sûr, du protocole ACME v02 avec prise en charge des certificats génériques.



Soins excessifs


En essayant d'entourer l'utilisateur avec soin, vous pouvez aller loin. Jusqu'à présent, il ne pourra pas du tout travailler avec des fonctionnalités. Et la première partie de notre histoire est à ce sujet.

Lors du développement du module, nous avons voulu éviter au client une longue préparation au problème du certificat. Deux restrictions ont été introduites pour cela: elles ne permettaient de commander SSL que pour les domaines Web enregistrés dans le panneau et uniquement pour les alias de domaine que le panneau connaît.

Les deux restrictions semblaient logiques. Le premier ne vous permettait pas de commander des certificats pour des domaines inexistants et de produire des entités «mortes» - des certificats qui ne seraient pas émis, car il n'y a nulle part où mettre les jetons de vérification. Le second a également éliminé les entités inutiles et ne permettait toujours pas de commander des certificats pour "*." - alias - à l'époque, LE ne supportait tout simplement pas ces certificats.

Tout allait bien jusqu'au jour où une fonctionnalité pour vérifier un domaine via des enregistrements DNS et la possibilité de commander un certificat pour un domaine de messagerie est apparue dans LE . Ensuite, lors de la commande d'un domaine de messagerie, nous avons décidé d'ajouter les alias suivants: "mail", "pop", "smtp" - après tout, le plus souvent, des certificats leur sont connectés. Au final, cela s'est mal passé: il y avait des utilisateurs qui avaient initialement configuré leurs serveurs de messagerie sur des alias complètement différents. En raison de nos limites de commande, ils n'ont pas pu ajouter les noms requis.

Heureusement, nous avons rapidement réalisé et corrigé l'erreur, permettant aux utilisateurs de spécifier les données nécessaires lors de la commande d'un certificat. Pourtant, il y a parfois trop de soucis :).

Caractère générique


Parlons maintenant du passage à ACME v02 , car ce n'est que dans cette version du protocole LE que la prise en charge des certificats génériques est apparue. Commençons par un nouveau ou plutôt un répertoire modifié:

curl -o- 'https://acme-v02.api.letsencrypt.org/directory' { "keyChange": "https://acme-v02.api.letsencrypt.org/acme/key-change", "mIU2Y2m2FsA": "https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417", "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" } 

La première différence et la plus évidente est que les touches sont différentes :). À mon avis, ils sont devenus beaucoup plus intuitifs. La deuxième différence est une URL distincte pour obtenir Replay-Nonce. Cela se fait maintenant comme ceci:

 curl -LD - 'https://acme-v02.api.letsencrypt.org/acme/new-nonce' HTTP/1.1 204 No Content Server: nginx Replay-Nonce: QQgdAERh1MLQ6LHC0SVmB9OJXBcEWnwGB53CP0V4JlQ X-Frame-Options: DENY Strict-Transport-Security: max-age=604800 Expires: Sat, 02 Jun 2018 09:49:47 GMT Cache-Control: max-age=0, no-cache, no-store Pragma: no-cache Date: Sat, 02 Jun 2018 09:49:47 GMT Connection: keep-alive 

Nonce, bien sûr, nous sera utile plus d'une fois.

Parlons maintenant des changements non évidents qu'implique la transition vers ACME v02.

Au cas où, permettez-moi de vous rappeler à quoi ressemblait notre ancienne demande POST pour communiquer avec la première version d' ACME :

 { "header": jws, // JSON Web Signature "protected": Base64Url(jws + Replay-Nonce), // Nonce —    "payload": Base64Url(payload), //  "signature": Base64Url(sign(protected.payload, private.pem)) //  } 

Maintenant, la structure générale des données sera différente:

 { "protected": Base64Url(protected), "payload": Base64Url(payload), // "signature": Base64Url(sign(protected.payload, private.pem)) } 

Comme vous pouvez le voir, le champ d'en-tête a été annulé. La phase préparatoire, à la grande joie des «amoureux de la cryptographie» comme moi, n'a pas changé du tout: nous aurons besoin des mêmes clés rsa , JWK et JWS (plus à ce sujet dans la première partie ).

Inscription


Pour enregistrer un utilisateur, il vous suffit d'accepter le contrat d'utilisation et d'envoyer une demande de "newAccount" à partir du répertoire.

 payload = {"termsOfServiceAgreed": true} 

Et compilez le bon protégé:

 { "alg" : "RS256", "jwk" : jwk, \\ JSON Web Key “url” : url, \\       “nonce” : Replay-Nonce \\    } 

Nous formons le corps de la demande, l'envoyons et ... prenons notre temps! Traitez soigneusement et soigneusement les en-têtes de réponse d' ACME . Nous trouvons un en-tête appelé Emplacement et enregistrons son contenu. Il s'agit de ce que l'on appelle le KID - la clé d'identification de l'utilisateur nouvellement enregistré. Toutes les demandes ultérieures devront contenir cette valeur dans protected au lieu de JWK . Attention : si vous continuez à envoyer des demandes selon l'ancien schéma, seuls les messages d'erreur seront la réponse.

Voici notre protégé ultérieur:

 { "alg" : "RS256", "kid" : kid, \\    “url” : url, \\        “nonce” : Replay-Nonce \\    } 

Commande de certificat


Nous nous préparons à envoyer une demande au répertoire ["newOrder"]. Nous ajoutons à la charge utile tous les alias de notre domaine web pour lesquels nous allons émettre un certificat:

 payload ={ "identifiers":[ { "type":"dns", "value":"name1" }, ... { "type":"dns", "value":"nameN" } ] } 

Gardez à l'esprit que si vous souhaitez émettre un certificat générique, les noms ne doivent contenir que le nom principal et «*». - un alias. La présence de tout autre nom entraînera une erreur de publication.

Dans la réponse, nous obtenons un JSON contenant des méthodes pour vérifier la propriété du domaine et l'URL qui sera utilisée pour terminer la délivrance du certificat.

 { "status":"pending", "expires":"2018-06-08T08:05:49.437251947Z", "identifiers":[ { "type":"dns", "value":"name1" }, { "type":"dns", "value":"www.name1" } ], "authorizations":[ //    "https://acme-v02.api.letsencrypt.org/acme/authz/Xp0a_...", "https://acme-v02.api.letsencrypt.org/acme/authz/o3Bvy..." ], "finalize":"https://acme-v02.api.letsencrypt.org/acme/finalize/..." //   } 

De plus, nous recevons des instructions détaillées sur les chèques:

 curl -o- 'https://acme-v02.api.letsencrypt.org/acme/authz/Xp0a_...' { "identifier":{ "type":"dns", "value":"name1" }, "status":"pending", "expires":"2018-06-08T08:05:49Z", "challenges":[ { "type":"http-01", "status":"pending", "url":"https://acme-v02.api.letsencrypt.org/acme/challenge/Xp0a_.../4906756205", "token":"Me_cKM2Stu3iyCJQWEssho8Kj2nvRKuSJvIPF5tRyko" }, { "type":"dns-01", "status":"pending", "url":"https://acme-v02.api.letsencrypt.org/acme/challenge/Xp0a_.../4906756206", "token":"p-0xyySPQClTXVlgTxwJUvVOQtdHmNPpFht95bWrq8s" } ] } 

Le processus de confirmation n'est pas différent de ce qui a été implémenté pour ACME v01 . Remarque: pour un certificat générique, vous devez sélectionner la confirmation «dns-01».

Obtention d'un certificat


Après la procédure de confirmation, il reste à appeler l'URL Finalize . De légers retards sont possibles, par conséquent, une demande GET à cette adresse doit être effectuée jusqu'à ce que nous obtenions ce qui suit dans la réponse:

 { "status": "valid", ///<    "expires": "2018-06-11T10:39:24Z", "identifiers": [ { "type": "dns", "value": "name1" }, { "type": "dns", "value": "name2" } ], "authorizations": [ "https://acme-v02.api.letsencrypt.org/acme/authz/Xp0a_...", "https://acme-v02.api.letsencrypt.org/acme/authz/o3Bvy..." ], "finalize": "https://acme-v02.api.letsencrypt.org/acme/finalize/...", "certificate": "https://acme-v02.api.letsencrypt.org/acme/cert/..." ///<  } 

Le certificat contiendra déjà une chaîne, il est donc complètement prêt pour le travail.

Par rapport à la première, la deuxième version d' ACME est devenue beaucoup plus pratique et compréhensible. L'intégration de l'écriture est devenue encore plus facile, étant donné que la «cryptographie» elle-même n'a pas changé. Je suivrai avec intérêt le développement de cet outil étonnant et je reviendrai certainement ici avec de nouvelles informations si des changements importants et utiles se produisent.

Source: https://habr.com/ru/post/fr413429/


All Articles