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".