7. Gestion des certificats - Partie 2
(Suite du chapitre 7, Partie 1)
7.1.4. Objets d'autorisation (Authorization Objects)
Un objet d'autorisation ACME représente l'autorisation accordée par le serveur à un compte pour représenter un identifiant. En plus de l'identifiant, une autorisation comprend plusieurs champs de métadonnées, tels que le statut de l'autorisation (par exemple, « pending », « valid » ou « revoked ») et les défis utilisés pour valider la possession de l'identifiant.
La structure d'une ressource d'autorisation ACME est la suivante :
identifier (requis, objet) : L'identifiant que le compte est autorisé à représenter.
-
type (requis, chaîne) : Le type de l'identifiant (voir ci-dessous et section 9.7.7).
-
value (requis, chaîne) : L'identifiant lui-même.
status (requis, chaîne) : Le statut de cette autorisation. Les valeurs possibles sont « pending », « valid », « invalid », « deactivated », « expired » et « revoked ». Voir section 7.1.6.
expires (optionnel, chaîne) : Horodatage après lequel le serveur considérera cette autorisation comme invalide, encodé au format spécifié dans [RFC3339]. Ce champ est REQUIS pour les objets dont le champ « status » est « valid ».
challenges (requis, tableau d'objets) : Pour les autorisations en attente, les défis que le client peut accomplir pour prouver la possession de l'identifiant. Pour les autorisations valides, le défi validé. Pour les autorisations invalides, les défis tentés mais échoués. Chaque entrée du tableau est un objet dont les paramètres sont nécessaires pour valider le défi. Le client DEVRAIT tenter d'accomplir l'un des défis, et le serveur DEVRAIT considérer n'importe lequel d'entre eux comme suffisant pour rendre l'autorisation valide.
wildcard (optionnel, booléen) : Pour les autorisations créées à la suite d'une requête newOrder contenant un identifiant DNS avec un nom de domaine générique comme valeur, ce champ DOIT être présent et avoir la valeur true. Pour les autres autorisations, il NE DOIT PAS être présent. Les noms de domaine génériques sont décrits à la section 7.1.3.
Le seul type d'identifiant défini par cette spécification est le nom de domaine pleinement qualifié (type : « dns »). Le nom de domaine DOIT être encodé tel qu'il apparaît dans le certificat. C'est-à-dire qu'il DOIT être encodé selon les règles de la section 7 de [RFC5280]. Le serveur DOIT vérifier que toute valeur d'identifiant commençant par le préfixe d'encodage compatible ASCII « xn-- » tel que défini dans [RFC5890] est correctement encodée. Les noms de domaine génériques (dont la première étiquette est « * ») NE DOIVENT PAS être inclus dans les objets d'autorisation. Si un objet d'autorisation transmet une autorisation pour le domaine de base d'un identifiant DNS newOrder contenant un nom de domaine générique, le champ d'autorisation optionnel « wildcard » DOIT être présent avec la valeur true.
La section 8 décrit un ensemble de défis pour la validation des noms de domaine.
{
"status": "valid",
"expires": "2015-03-01T14:09:07.99Z",
"identifier": {
"type": "dns",
"value": "www.example.org"
},
"challenges": [
{
"url": "https://example.com/acme/chall/prV_B7yEyA4",
"type": "http-01",
"status": "valid",
"token": "DGyRejmCefe7v4NfDGDKfA",
"validated": "2014-12-01T12:05:58.16Z"
}
],
"wildcard": false
}
7.1.5. Objets de défi (Challenge Objects)
Un objet de défi ACME représente une proposition faite par le serveur pour valider la possession d'un identifiant par le client d'une manière particulière. Contrairement aux autres objets listés ci-dessus, les objets de défi n'ont pas de structure standard unique. Le contenu d'un objet de défi dépend de la méthode de validation utilisée. La structure générale des objets de défi et un ensemble initial de méthodes de validation sont décrits à la section 8.
7.1.6. Changements d'état (Status Changes)
Chaque type d'objet ACME traverse une machine à états simple au cours de sa durée de vie. Le champ « status » de l'objet indique dans quel état se trouve actuellement l'objet.
Les objets de défi sont créés à l'état « pending ». Ils passent à l'état « processing » lorsque le client répond au défi (voir section 7.5.1) et que le serveur commence à tenter de vérifier si le client a accompli le défi. Notez que dans l'état « processing », le serveur peut tenter de valider le défi plusieurs fois (voir section 8.2). De même, une demande de nouvelle tentative du client n'entraîne pas de changement d'état. Si la validation réussit, le défi passe à l'état « valid » ; si une erreur se produit, le défi passe à l'état « invalid ».
pending
|
| Receive
| response
V
processing <-+
| | | Server retry or
| | | client retry request
| +----+
|
|
Successful | Failed
validation | validation
+---------+---------+
| |
V V
valid invalid
State Transitions for Challenge Objects
Les objets d'autorisation sont créés à l'état « pending ». Si l'un des défis listés dans l'autorisation passe à l'état « valid », l'autorisation passe également à l'état « valid ». Si le client tente d'accomplir un défi mais échoue, ou si une erreur se produit alors que l'autorisation est encore en attente, l'autorisation passe à l'état « invalid ». Une fois qu'une autorisation est à l'état « valid », elle peut expirer (« expired »), être désactivée par le client (« deactivated », voir section 7.5.2), ou être révoquée par le serveur (« revoked »).
pending --------------------+
| |
Challenge failure | |
or | |
Error | Challenge valid |
+---------+---------+ |
| | |
V V |
invalid valid |
| |
| |
| |
+--------------+--------------+
| | |
| | |
Server | Client | Time after |
revoke | deactivate | "expires" |
V V V
revoked deactivated expired
State Transitions for Authorization Objects
Les objets de commande sont créés à l'état « pending ». Une fois que toutes les autorisations listées dans l'objet de commande sont à l'état « valid », la commande passe à l'état « ready ». La commande passe à l'état « processing » après que le client soumet une requête à l'URL « finalize » de la commande et que la CA commence le processus de délivrance du certificat. Une fois le certificat délivré, la commande passe à l'état « valid ». Si une erreur se produit à l'une de ces étapes, la commande passe à l'état « invalid ». La commande passe également à l'état « invalid » si elle expire ou si l'une de ses autorisations entre dans un état final autre que « valid » (« expired », « revoked » ou « deactivated »).
pending --------------+
| |
| All authz |
| "valid" |
V |
ready ---------------+
| |
| Receive |
| finalize |
| request |
V |
processing ------------+
| |
| Certificate | Error or
| issued | Authorization failure
V V
valid invalid
State Transitions for Order Objects
Les objets de compte sont créés à l'état « valid », car aucune action supplémentaire n'est nécessaire pour créer un compte après une requête newAccount réussie. Si le compte est désactivé par le client ou révoqué par le serveur, il passe à l'état correspondant.
valid
|
|
+-----------+-----------+
Client | Server |
deactiv.| revoke |
V V
deactivated revoked
State Transitions for Account Objects
Notez que, selon le comportement du serveur, certains de ces états peuvent ne jamais apparaître dans le champ « status ». Par exemple, un serveur qui délivre de manière synchrone n'affichera jamais une commande à l'état « processing ». Un serveur qui supprime immédiatement les autorisations expirées n'affichera jamais une autorisation à l'état « expired ».
7.2. Obtention d'un nonce
Avant d'envoyer une requête POST au serveur, un client ACME a besoin d'un nonce anti-relecture frais à placer dans l'en-tête « nonce » du JWS. Dans la plupart des cas, le client obtiendra un nonce à partir d'une requête précédente. Cependant, un client peut parfois avoir besoin d'obtenir un nouveau nonce, par exemple lors de la première requête au serveur ou si un nonce existant n'est plus valide.
Pour obtenir un nonce frais, le client envoie une requête HEAD à la ressource newNonce du serveur. La réponse du serveur DOIT contenir un champ d'en-tête Replay-Nonce contenant un nonce frais et DEVRAIT avoir le code de statut 200 (OK). Le serveur DOIT également répondre aux requêtes GET vers cette ressource, en retournant un corps vide (tout en fournissant toujours l'en-tête Replay-Nonce), avec le code de statut 204 (No Content).
HEAD /acme/new-nonce HTTP/1.1
Host: example.com
HTTP/1.1 200 OK
Replay-Nonce: oFvnlFP1wIhRlYS2jTaXbA
Cache-Control: no-store
Link: `https://example.com/acme/directory`;rel="index"
La mise en cache par proxy des réponses de la ressource newNonce peut amener les clients à recevoir le même nonce à plusieurs reprises, entraînant des erreurs « badNonce ». Le serveur DOIT inclure un champ d'en-tête Cache-Control avec la directive « no-store » dans les réponses de la ressource newNonce pour empêcher la mise en cache de cette ressource.
7.3. Gestion des comptes
Dans cette section, nous décrivons comment les clients ACME créent des comptes sur un serveur ACME et effectuent certaines modifications sur les comptes après leur création.
Un client crée un nouveau compte en envoyant une requête POST à l'URL newAccount du serveur. Le corps de la requête est un objet de compte partiel contenant un sous-ensemble des champs suivants :
contact (optionnel, tableau de chaînes) : Même signification que le champ serveur correspondant défini à la section 7.1.2.
termsOfServiceAgreed (optionnel, booléen) : Même signification que le champ serveur correspondant défini à la section 7.1.2.
onlyReturnExisting (optionnel, booléen) : Si ce champ est présent avec la valeur « true », le serveur NE DOIT PAS créer un nouveau compte si le compte n'existe pas déjà. Cela permet aux clients de rechercher l'URL d'un compte à partir de la clé du compte (voir section 7.3.1).
externalAccountBinding (optionnel, objet) : Même signification que le champ serveur correspondant défini à la section 7.1.2.
POST /acme/new-account HTTP/1.1
Host: example.com
Content-Type: application/jose+json
{
"protected": base64url({
"alg": "ES256",
"jwk": {...},
"nonce": "6S8IqOGY7eL2lsGoTZYifg",
"url": "https://example.com/acme/new-account"
}),
"payload": base64url({
"termsOfServiceAgreed": true,
"contact": [
"mailto:[email protected]",
"mailto:[email protected]"
]
}),
"signature": "RZPOnYoPs1PhjszF...-nh6X1qtOFPB519I"
}
Le serveur DOIT ignorer toute valeur fournie dans le champ « orders » de l'objet de compte envoyé par le client, ainsi que tout autre champ qu'il ne reconnaît pas. Si de nouveaux champs sont spécifiés à l'avenir, leurs spécifications DOIVENT décrire si les clients peuvent les fournir. Le serveur NE DOIT PAS refléter le champ « onlyReturnExisting » ni aucun champ non reconnu dans l'objet de compte résultant. Cela permet aux clients de détecter quand le serveur ne prend pas en charge les champs d'extension.
Le serveur DEVRAIT valider que les URL de contact dans le champ « contact » sont valides et prises en charge par le serveur. Si le serveur valide les URL de contact, il DOIT prendre en charge le schéma « mailto ». Les clients NE DOIVENT PAS fournir d'URL « mailto » contenant des « hfields » [RFC6068] ou plusieurs « addr-spec » dans le composant « to » dans le champ « contact ». Si le serveur rencontre une URL de contact « mailto » qui ne satisfait pas ces critères, il DEVRAIT la rejeter comme invalide.
Si le serveur rejette une URL de contact en raison d'un schéma non pris en charge, il DOIT retourner une erreur de type « unsupportedContact » avec une description de l'erreur et les types d'URL de contact que le serveur considère acceptables. Si le serveur rejette une URL de contact en raison d'un schéma pris en charge mais d'une valeur invalide, le serveur DOIT retourner une erreur de type « invalidContact ».
Si le serveur souhaite exiger que les clients acceptent les conditions d'utilisation du service ACME, il DOIT indiquer l'URL à laquelle ces conditions peuvent être consultées dans le sous-champ « termsOfService » du champ « meta » de l'objet répertoire, et le serveur DOIT rejeter les requêtes newAccount qui ne définissent pas le champ « termsOfServiceAgreed » à « true ». Les clients NE DEVRAIENT PAS accepter automatiquement les conditions par défaut. Au contraire, ils DEVRAIENT nécessiter une interaction utilisateur pour accepter les conditions.
Le serveur crée le compte et stocke la clé publique utilisée pour valider le JWS (c'est-à-dire l'élément « jwk » de l'en-tête JWS) pour authentifier les futures requêtes du compte. Le serveur retourne cet objet de compte dans une réponse 201 (Created), avec l'URL du compte dans le champ d'en-tête Location. L'URL du compte est utilisée comme valeur « kid » dans le JWS pour authentifier les requêtes ultérieures pour ce compte (voir section 6.2). L'URL du compte est également utilisée pour les requêtes d'opérations de gestion sur ce compte, comme décrit ci-dessous.
HTTP/1.1 201 Created
Content-Type: application/json
Replay-Nonce: D8s4D2mLs8Vn-goWuPQeKA
Link: `https://example.com/acme/directory`;rel="index"
Location: https://example.com/acme/acct/evOfKhNU60wg
{
"status": "valid",
"contact": [
"mailto:[email protected]",
"mailto:[email protected]"
],
"orders": "https://example.com/acme/acct/evOfKhNU60wg/orders"
}
7.3.1. Recherche d'une URL de compte à partir d'une clé
Si le serveur reçoit une requête newAccount signée avec une clé pour laquelle il a déjà enregistré un compte, il DOIT retourner une réponse avec le code de statut 200 (OK) et fournir l'URL de ce compte dans le champ d'en-tête Location. Le corps de cette réponse représente l'objet de compte tel qu'il existait sur le serveur avant cette requête ; tout champ de l'objet de requête DOIT être ignoré. Cela permet aux clients qui possèdent une clé de compte mais pas l'URL de compte correspondante de récupérer l'URL du compte.
Si un client souhaite rechercher l'URL d'un compte existant et ne souhaite pas créer un compte si le compte n'existe pas, il DEVRAIT le faire en envoyant une requête POST à l'URL newAccount dont la charge utile JWS a le champ « onlyReturnExisting » défini à « true » ({"onlyReturnExisting": true}). Si le client envoie une telle requête et que le compte n'existe pas, le serveur DOIT retourner le code de statut 400 (Bad Request) et une réponse d'erreur de type « urn:ietf:params:acme:error:accountDoesNotExist ».
7.3.2. Mise à jour du compte
Si le client souhaite mettre à jour ces informations à l'avenir, il envoie une requête POST avec les informations mises à jour à l'URL du compte. Le serveur DOIT ignorer toute mise à jour du champ « orders », du champ « termsOfServiceAgreed » (voir section 7.3.3), du champ « status » (sauf dans les cas autorisés par la section 7.3.6), ou de tout autre champ qu'il ne reconnaît pas. Si le serveur accepte la mise à jour, il DOIT retourner une réponse avec le code de statut 200 (OK) et l'objet de compte résultant.
Par exemple, pour mettre à jour les informations de contact dans le compte ci-dessus, le client peut envoyer la requête suivante :
POST /acme/acct/evOfKhNU60wg HTTP/1.1
Host: example.com
Content-Type: application/jose+json
{
"protected": base64url({
"alg": "ES256",
"kid": "https://example.com/acme/acct/evOfKhNU60wg",
"nonce": "ax5RnthDqp_Yf4_HZnFLmA",
"url": "https://example.com/acme/acct/evOfKhNU60wg"
}),
"payload": base64url({
"contact": [
"mailto:[email protected]",
"mailto:[email protected]"
]
}),
"signature": "hDXzvcj8T6fbFbmn...rDzXzzvzpRy64N0o"
}
7.3.3. Modifications des conditions d'utilisation
Comme décrit ci-dessus, un client peut indiquer son accord avec les conditions d'utilisation de la CA en définissant le champ « termsOfServiceAgreed » dans son objet de compte à « true ».
Si le serveur a modifié ses conditions d'utilisation depuis que le client les a initialement acceptées, et que le serveur n'est pas disposé à traiter les requêtes sans accord explicite sur les nouvelles conditions, il DOIT retourner le code de statut 403 (Forbidden) et une réponse d'erreur de type « urn:ietf:params:acme:error:userActionRequired ». Cette réponse DOIT contenir un champ d'en-tête Link avec la relation de lien « terms-of-service » et l'URL des conditions d'utilisation les plus récentes.
Le document de problème retourné avec l'erreur DOIT également inclure un champ « instance » indiquant l'URL vers laquelle le client devrait diriger un utilisateur humain pour obtenir des instructions sur la façon d'accepter les conditions.
HTTP/1.1 403 Forbidden
Replay-Nonce: T81bdZroZ2ITWSondpTmAw
Link: `https://example.com/acme/directory`;rel="index"
Link: `https://example.com/acme/terms/2017-6-02`;rel="terms-of-service"
Content-Type: application/problem+json
Content-Language: en
{
"type": "urn:ietf:params:acme:error:userActionRequired",
"detail": "Terms of service have changed",
"instance": "https://example.com/acme/agreement/?token=W8Ih3PswD-8"
}
7.3.4. Liaison de compte externe (External Account Binding)
Un serveur PEUT exiger la présence d'une valeur pour le champ « externalAccountBinding » dans les requêtes « newAccount ». Cela peut être utilisé pour associer un compte ACME à un compte existant dans un système non-ACME, tel qu'une base de données clients d'une CA.
Pour activer la liaison de compte ACME, la CA exploitant le serveur ACME doit fournir au client ACME une clé MAC et un identifiant de clé via un mécanisme externe à ACME. L'identifiant de clé DOIT être une chaîne ASCII. La clé MAC DEVRAIT être fournie sous forme encodée en base64url pour maximiser la compatibilité entre les systèmes de provisionnement non-ACME et les clients ACME.
Le client ACME calcule ensuite un JWS de liaison pour indiquer que le titulaire du compte externe approuve la clé de compte ACME. La charge utile de ce JWS est la clé de compte ACME en cours d'enregistrement, sous forme JWK. L'en-tête protégé du JWS DOIT satisfaire les critères suivants :
- Le champ « alg » DOIT indiquer un algorithme basé sur MAC
- Le champ « kid » DOIT contenir l'identifiant de clé fourni par la CA
- Le champ « nonce » NE DOIT PAS être présent
- Le champ « url » DOIT être défini à la même valeur que le JWS externe
Le champ « signature » du JWS contiendra la valeur MAC calculée à l'aide de la clé MAC fournie par la CA.
(En raison de contraintes de longueur, les sections 7.3.5 à 7.6 sont dans le fichier suivant)