7.5. Identifier Authorization
The identifier authorization process establishes the authorization of an account to manage certificates for a given identifier. This process assures the server of two things: 1. That the client controls the private key of the account key pair, and 2. That the client controls the identifier in question. This process may be repeated to associate multiple identifiers with an account (e.g., to request certificates with multiple identifiers) or to associate multiple accounts with an identifier (e.g., to allow multiple entities to manage certificates). Authorization resources are created by the server in response to newOrder or newAuthz requests submitted by an account key holder; their URLs are provided to the client in the responses to these requests. The authorization object is implicitly tied to the account key used to sign the request. When a client receives an order from the server in reply to a newOrder request, it downloads the authorization resources by sending POST-as-GET requests to the indicated URLs. If the client initiates authorization using a request to the newAuthz resource, it will have already received the pending authorization object in the response to that request.
POST /acme/authz/PAniVnsZcis HTTP/1.1 Host: example.com Content-Type: application/jose+json { "protected": base64url({ "alg": "ES256", "kid": "https://example.com/acme/acct/evOfKhNU60wg", "nonce": "uQpSjlRb4vQVCjVYAyyUWg", "url": "https://example.com/acme/authz/PAniVnsZcis" }), "payload": "", "signature": "nuSDISbWG8mMgE7H...QyVUL68yzf3Zawps" } HTTP/1.1 200 OK Content-Type: application/json Link: <https://example.com/acme/directory>;rel="index" { "status": "pending", "expires": "2016-01-02T14:09:30Z", "identifier": { "type": "dns", "value": "www.example.org" }, "challenges": [ { "type": "http-01", "url": "https://example.com/acme/chall/prV_B7yEyA4", "token": "DGyRejmCefe7v4NfDGDKfA" }, { "type": "dns-01", "url": "https://example.com/acme/chall/Rg5dV14Gh1Q", "token": "DGyRejmCefe7v4NfDGDKfA" } ] }7.5.1. Responding to Challenges
To prove control of the identifier and receive authorization, the client needs to provision the required challenge response based on the challenge type and indicate to the server that it is ready for the challenge validation to be attempted.
The client indicates to the server that it is ready for the challenge validation by sending an empty JSON body ("{}") carried in a POST request to the challenge URL (not the authorization URL). For example, if the client were to respond to the "http-01" challenge in the above authorization, it would send the following request: POST /acme/chall/prV_B7yEyA4 HTTP/1.1 Host: example.com Content-Type: application/jose+json { "protected": base64url({ "alg": "ES256", "kid": "https://example.com/acme/acct/evOfKhNU60wg", "nonce": "Q_s3MWoqT05TrdkM2MTDcw", "url": "https://example.com/acme/chall/prV_B7yEyA4" }), "payload": base64url({}), "signature": "9cbg5JO1Gf5YLjjz...SpkUfcdPai9uVYYQ" } The server updates the authorization document by updating its representation of the challenge with the response object provided by the client. The server MUST ignore any fields in the response object that are not specified as response fields for this type of challenge. Note that the challenges in this document do not define any response fields, but future specifications might define them. The server provides a 200 (OK) response with the updated challenge object as its body. If the client's response is invalid for any reason or does not provide the server with appropriate information to validate the challenge, then the server MUST return an HTTP error. On receiving such an error, the client SHOULD undo any actions that have been taken to fulfill the challenge, e.g., removing files that have been provisioned to a web server. The server is said to "finalize" the authorization when it has completed one of the validations. This is done by assigning the authorization a status of "valid" or "invalid", corresponding to whether it considers the account authorized for the identifier. If the final state is "valid", then the server MUST include an "expires" field. When finalizing an authorization, the server MAY remove challenges other than the one that was completed, and it may modify the "expires" field. The server SHOULD NOT remove challenges with status "invalid".
Usually, the validation process will take some time, so the client will need to poll the authorization resource to see when it is finalized. For challenges where the client can tell when the server has validated the challenge (e.g., by seeing an HTTP or DNS request from the server), the client SHOULD NOT begin polling until it has seen the validation request from the server. To check on the status of an authorization, the client sends a POST- as-GET request to the authorization URL, and the server responds with the current authorization object. In responding to poll requests while the validation is still in progress, the server MUST return a 200 (OK) response and MAY include a Retry-After header field to suggest a polling interval to the client.
POST /acme/authz/PAniVnsZcis HTTP/1.1 Host: example.com Content-Type: application/jose+json { "protected": base64url({ "alg": "ES256", "kid": "https://example.com/acme/acct/evOfKhNU60wg", "nonce": "uQpSjlRb4vQVCjVYAyyUWg", "url": "https://example.com/acme/authz/PAniVnsZcis" }), "payload": "", "signature": "nuSDISbWG8mMgE7H...QyVUL68yzf3Zawps" } HTTP/1.1 200 OK Content-Type: application/json Link: <https://example.com/acme/directory>;rel="index" { "status": "valid", "expires": "2018-09-09T14:09:01.13Z", "identifier": { "type": "dns", "value": "www.example.org" }, "challenges": [ { "type": "http-01", "url": "https://example.com/acme/chall/prV_B7yEyA4", "status": "valid", "validated": "2014-12-01T12:05:13.72Z", "token": "IlirfxKKXAsHtmzK29Pj8A" } ] }7.5.2. Deactivating an Authorization
If a client wishes to relinquish its authorization to issue certificates for an identifier, then it may request that the server deactivate each authorization associated with it by sending POST requests with the static object {"status": "deactivated"} to each authorization URL.
POST /acme/authz/PAniVnsZcis HTTP/1.1 Host: example.com Content-Type: application/jose+json { "protected": base64url({ "alg": "ES256", "kid": "https://example.com/acme/acct/evOfKhNU60wg", "nonce": "xWCM9lGbIyCgue8di6ueWQ", "url": "https://example.com/acme/authz/PAniVnsZcis" }), "payload": base64url({ "status": "deactivated" }), "signature": "srX9Ji7Le9bjszhu...WTFdtujObzMtZcx4" } The server MUST verify that the request is signed by the account key corresponding to the account that owns the authorization. If the server accepts the deactivation, it should reply with a 200 (OK) status code and the updated contents of the authorization object. The server MUST NOT treat deactivated authorization objects as sufficient for issuing certificates.7.6. Certificate Revocation
To request that a certificate be revoked, the client sends a POST request to the ACME server's revokeCert URL. The body of the POST is a JWS object whose JSON payload contains the certificate to be revoked: certificate (required, string): The certificate to be revoked, in the base64url-encoded version of the DER format. (Note: Because this field uses base64url, and does not include headers, it is different from PEM.) reason (optional, int): One of the revocation reasonCodes defined in Section 5.3.1 of [RFC5280] to be used when generating OCSP responses and CRLs. If this field is not set, the server SHOULD omit the reasonCode CRL entry extension when generating OCSP responses and CRLs. The server MAY disallow a subset of reasonCodes from being used by the user. If a request contains a disallowed reasonCode, then the server MUST reject it with the error type "urn:ietf:params:acme:error:badRevocationReason". The problem document detail SHOULD indicate which reasonCodes are allowed.
Revocation requests are different from other ACME requests in that they can be signed with either an account key pair or the key pair in the certificate. Example using an account key pair for the signature: POST /acme/revoke-cert HTTP/1.1 Host: example.com Content-Type: application/jose+json { "protected": base64url({ "alg": "ES256", "kid": "https://example.com/acme/acct/evOfKhNU60wg", "nonce": "JHb54aT_KTXBWQOzGYkt9A", "url": "https://example.com/acme/revoke-cert" }), "payload": base64url({ "certificate": "MIIEDTCCAvegAwIBAgIRAP8...", "reason": 4 }), "signature": "Q1bURgJoEslbD1c5...3pYdSMLio57mQNN4" } Example using the certificate key pair for the signature: POST /acme/revoke-cert HTTP/1.1 Host: example.com Content-Type: application/jose+json { "protected": base64url({ "alg": "RS256", "jwk": /* certificate's public key */, "nonce": "JHb54aT_KTXBWQOzGYkt9A", "url": "https://example.com/acme/revoke-cert" }), "payload": base64url({ "certificate": "MIIEDTCCAvegAwIBAgIRAP8...", "reason": 1 }), "signature": "Q1bURgJoEslbD1c5...3pYdSMLio57mQNN4" }
Before revoking a certificate, the server MUST verify that the key used to sign the request is authorized to revoke the certificate. The server MUST consider at least the following accounts authorized for a given certificate: o the account that issued the certificate. o an account that holds authorizations for all of the identifiers in the certificate. The server MUST also consider a revocation request valid if it is signed with the private key corresponding to the public key in the certificate. If the revocation succeeds, the server responds with status code 200 (OK). If the revocation fails, the server returns an error. For example, if the certificate has already been revoked, the server returns an error response with status code 400 (Bad Request) and type "urn:ietf:params:acme:error:alreadyRevoked". HTTP/1.1 200 OK Replay-Nonce: IXVHDyxIRGcTE0VSblhPzw Content-Length: 0 Link: <https://example.com/acme/directory>;rel="index" --- or --- HTTP/1.1 403 Forbidden Replay-Nonce: lXfyFzi6238tfPQRwgfmPU Content-Type: application/problem+json Content-Language: en Link: <https://example.com/acme/directory>;rel="index" { "type": "urn:ietf:params:acme:error:unauthorized", "detail": "No authorization provided for name example.org" }8. Identifier Validation Challenges
There are few types of identifiers in the world for which there is a standardized mechanism to prove possession of a given identifier. In all practical cases, CAs rely on a variety of means to test whether an entity applying for a certificate with a given identifier actually controls that identifier.
Challenges provide the server with assurance that an account holder is also the entity that controls an identifier. For each type of challenge, it must be the case that, in order for an entity to successfully complete the challenge, the entity must both: o Hold the private key of the account key pair used to respond to the challenge, and o Control the identifier in question. Section 10 documents how the challenges defined in this document meet these requirements. New challenges will need to document how they do. ACME uses an extensible challenge/response framework for identifier validation. The server presents a set of challenges in the authorization object it sends to a client (as objects in the "challenges" array), and the client responds by sending a response object in a POST request to a challenge URL. This section describes an initial set of challenge types. The definition of a challenge type includes: 1. Content of challenge objects 2. Content of response objects 3. How the server uses the challenge and response to verify control of an identifier Challenge objects all contain the following basic fields: type (required, string): The type of challenge encoded in the object. url (required, string): The URL to which a response can be posted. status (required, string): The status of this challenge. Possible values are "pending", "processing", "valid", and "invalid" (see Section 7.1.6). validated (optional, string): The time at which the server validated this challenge, encoded in the format specified in [RFC3339]. This field is REQUIRED if the "status" field is "valid".
error (optional, object): Error that occurred while the server was validating the challenge, if any, structured as a problem document [RFC7807]. Multiple errors can be indicated by using subproblems Section 6.7.1. A challenge object with an error MUST have status equal to "invalid". All additional fields are specified by the challenge type. If the server sets a challenge's "status" to "invalid", it SHOULD also include the "error" field to help the client diagnose why the challenge failed. Different challenges allow the server to obtain proof of different aspects of control over an identifier. In some challenges, like HTTP and DNS, the client directly proves its ability to do certain things related to the identifier. The choice of which challenges to offer to a client under which circumstances is a matter of server policy. The identifier validation challenges described in this section all relate to validation of domain names. If ACME is extended in the future to support other types of identifiers, there will need to be new challenge types, and they will need to specify which types of identifier they apply to.8.1. Key Authorizations
All challenges defined in this document make use of a key authorization string. A key authorization is a string that concatenates the token for the challenge with a key fingerprint, separated by a "." character: keyAuthorization = token || '.' || base64url(Thumbprint(accountKey)) The "Thumbprint" step indicates the computation specified in [RFC7638], using the SHA-256 digest [FIPS180-4]. As noted in [RFC7518] any prepended zero octets in the fields of a JWK object MUST be stripped before doing the computation. As specified in the individual challenges below, the token for a challenge is a string comprised entirely of characters in the URL- safe base64 alphabet. The "||" operator indicates concatenation of strings.
8.2. Retrying Challenges
ACME challenges typically require the client to set up some network- accessible resource that the server can query in order to validate that the client controls an identifier. In practice, it is not uncommon for the server's queries to fail while a resource is being set up, e.g., due to information propagating across a cluster or firewall rules not being in place. Clients SHOULD NOT respond to challenges until they believe that the server's queries will succeed. If a server's initial validation query fails, the server SHOULD retry the query after some time, in order to account for delay in setting up responses such as DNS records or HTTP resources. The precise retry schedule is up to the server, but server operators should keep in mind the operational scenarios that the schedule is trying to accommodate. Given that retries are intended to address things like propagation delays in HTTP or DNS provisioning, there should not usually be any reason to retry more often than every 5 or 10 seconds. While the server is still trying, the status of the challenge remains "processing"; it is only marked "invalid" once the server has given up. The server MUST provide information about its retry state to the client via the "error" field in the challenge and the Retry-After HTTP header field in response to requests to the challenge resource. The server MUST add an entry to the "error" field in the challenge after each failed validation query. The server SHOULD set the Retry- After header field to a time after the server's next validation query, since the status of the challenge will not change until that time. Clients can explicitly request a retry by re-sending their response to a challenge in a new POST request (with a new nonce, etc.). This allows clients to request a retry when the state has changed (e.g., after firewall rules have been updated). Servers SHOULD retry a request immediately on receiving such a POST request. In order to avoid denial-of-service attacks via client-initiated retries, servers SHOULD rate-limit such requests.8.3. HTTP Challenge
With HTTP validation, the client in an ACME transaction proves its control over a domain name by proving that it can provision HTTP resources on a server accessible under that domain name. The ACME server challenges the client to provision a file at a specific path, with a specific string as its content.
As a domain may resolve to multiple IPv4 and IPv6 addresses, the server will connect to at least one of the hosts found in the DNS A and AAAA records, at its discretion. Because many web servers allocate a default HTTPS virtual host to a particular low-privilege tenant user in a subtle and non-intuitive manner, the challenge must be completed over HTTP, not HTTPS. type (required, string): The string "http-01". token (required, string): A random value that uniquely identifies the challenge. This value MUST have at least 128 bits of entropy. It MUST NOT contain any characters outside the base64url alphabet and MUST NOT include base64 padding characters ("="). See [RFC4086] for additional information on randomness requirements. { "type": "http-01", "url": "https://example.com/acme/chall/prV_B7yEyA4", "status": "pending", "token": "LoqXcYV8q5ONbJQxbmR7SCTNo3tiAXDfowyjxAjEuX0" } A client fulfills this challenge by constructing a key authorization from the "token" value provided in the challenge and the client's account key. The client then provisions the key authorization as a resource on the HTTP server for the domain in question. The path at which the resource is provisioned is comprised of the fixed prefix "/.well-known/acme-challenge/", followed by the "token" value in the challenge. The value of the resource MUST be the ASCII representation of the key authorization. GET /.well-known/acme-challenge/LoqXcYV8...jxAjEuX0 Host: example.org HTTP/1.1 200 OK Content-Type: application/octet-stream LoqXcYV8...jxAjEuX0.9jg46WB3...fm21mqTI (In the above, "..." indicates that the token and the JWK thumbprint in the key authorization have been truncated to fit on the page.) A client responds with an empty object ({}) to acknowledge that the challenge can be validated by the server.
POST /acme/chall/prV_B7yEyA4 Host: example.com Content-Type: application/jose+json { "protected": base64url({ "alg": "ES256", "kid": "https://example.com/acme/acct/evOfKhNU60wg", "nonce": "UQI1PoRi5OuXzxuX7V7wL0", "url": "https://example.com/acme/chall/prV_B7yEyA4" }), "payload": base64url({}), "signature": "Q1bURgJoEslbD1c5...3pYdSMLio57mQNN4" } On receiving a response, the server constructs and stores the key authorization from the challenge "token" value and the current client account key. Given a challenge/response pair, the server verifies the client's control of the domain by verifying that the resource was provisioned as expected. 1. Construct a URL by populating the URL template [RFC6570] "http://{domain}/.well-known/acme-challenge/{token}", where: * the domain field is set to the domain name being verified; and * the token field is set to the token in the challenge. 2. Verify that the resulting URL is well-formed. 3. Dereference the URL using an HTTP GET request. This request MUST be sent to TCP port 80 on the HTTP server. 4. Verify that the body of the response is a well-formed key authorization. The server SHOULD ignore whitespace characters at the end of the body. 5. Verify that key authorization provided by the HTTP server matches the key authorization stored by the server. The server SHOULD follow redirects when dereferencing the URL. Clients might use redirects, for example, so that the response can be provided by a centralized certificate management server. See Section 10.2 for security considerations related to redirects.
If all of the above verifications succeed, then the validation is successful. If the request fails, or the body does not pass these checks, then it has failed. The client SHOULD de-provision the resource provisioned for this challenge once the challenge is complete, i.e., once the "status" field of the challenge has the value "valid" or "invalid". Note that because the token appears both in the request sent by the ACME server and in the key authorization in the response, it is possible to build clients that copy the token from request to response. Clients should avoid this behavior because it can lead to cross-site scripting vulnerabilities; instead, clients should be explicitly configured on a per-challenge basis. A client that does copy tokens from requests to responses MUST validate that the token in the request matches the token syntax above (e.g., that it includes only characters from the base64url alphabet).8.4. DNS Challenge
When the identifier being validated is a domain name, the client can prove control of that domain by provisioning a TXT resource record containing a designated value for a specific validation domain name. type (required, string): The string "dns-01". token (required, string): A random value that uniquely identifies the challenge. This value MUST have at least 128 bits of entropy. It MUST NOT contain any characters outside the base64url alphabet, including padding characters ("="). See [RFC4086] for additional information on randomness requirements. { "type": "dns-01", "url": "https://example.com/acme/chall/Rg5dV14Gh1Q", "status": "pending", "token": "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA" } A client fulfills this challenge by constructing a key authorization from the "token" value provided in the challenge and the client's account key. The client then computes the SHA-256 digest [FIPS180-4] of the key authorization. The record provisioned to the DNS contains the base64url encoding of this digest. The client constructs the validation domain name by prepending the label "_acme-challenge" to the domain name being validated, then provisions a TXT record with the digest value under
that name. For example, if the domain name being validated is "www.example.org", then the client would provision the following DNS record: _acme-challenge.www.example.org. 300 IN TXT "gfj9Xq...Rg85nM" A client responds with an empty object ({}) to acknowledge that the challenge can be validated by the server. POST /acme/chall/Rg5dV14Gh1Q Host: example.com Content-Type: application/jose+json { "protected": base64url({ "alg": "ES256", "kid": "https://example.com/acme/acct/evOfKhNU60wg", "nonce": "SS2sSl1PtspvFZ08kNtzKd", "url": "https://example.com/acme/chall/Rg5dV14Gh1Q" }), "payload": base64url({}), "signature": "Q1bURgJoEslbD1c5...3pYdSMLio57mQNN4" } On receiving a response, the server constructs and stores the key authorization from the challenge "token" value and the current client account key. To validate a DNS challenge, the server performs the following steps: 1. Compute the SHA-256 digest [FIPS180-4] of the stored key authorization 2. Query for TXT records for the validation domain name 3. Verify that the contents of one of the TXT records match the digest value If all of the above verifications succeed, then the validation is successful. If no DNS record is found, or DNS record and response payload do not pass these checks, then the validation fails. The client SHOULD de-provision the resource record(s) provisioned for this challenge once the challenge is complete, i.e., once the "status" field of the challenge has the value "valid" or "invalid".