Automatic Certificate Management Environment (ACME)
Extracted elements (31)
POST-as-GET was chosen over unauthenticated GET so that all resource accesses (fetching certificates, authorizations, orders) are authenticated via JWS. Plain GET requests cannot carry a signed body, leaving them unauthenticated and susceptible to unauthorized access.
The 'url' field is bound into the JWS protected header because TLS-terminating intermediaries such as CDNs can modify the HTTP request URL after TLS is terminated. HTTPS alone does not protect the URL from modification by such in-path entities.
TLS 1.3 0-RTT early data is explicitly permitted for ACME because the protocol's own nonce-based anti-replay mechanism covers all operations where replay would be harmful, making the TLS-layer 0-RTT replay risk moot for ACME payloads.
ACME servers intended to be accessible from browser-based clients SHOULD enable CORS and set the Access-Control-Allow-Origin header to '*'. Without CORS headers, same-origin policy in browsers blocks cross-origin ACME requests.
All ACME requests with a non-empty body MUST encapsulate their payload in a JWS object signed with the account private key. The JWS MUST be in Flattened JSON Serialization, MUST NOT have multiple signatures, and the 'alg' field MUST NOT be 'none' or any MAC-based algorithm.
All requests and responses sent via HTTP by ACME clients, servers, and validation servers, as well as inputs for digest computations, MUST be encoded using the UTF-8 character set.
An ACME server MUST implement the ES256 signature algorithm and SHOULD implement EdDSA with the Ed25519 variant. If a client uses an unsupported algorithm, the server MUST return HTTP 400 with error type 'badSignatureAlgorithm' and include an 'algorithms' field listing supported values.
Authenticated resource fetching MUST use POST-as-GET: a POST with a JWS whose payload field is set to the empty string (""). Plain GET requests (except for directory and newNonce) MUST be rejected with HTTP 405 and error type 'malformed'.
Clients SHOULD NOT automatically agree to terms of service by default and SHOULD require user interaction for agreement. If a server's ToS change requires re-agreement, it MUST return HTTP 403 with error type 'userActionRequired', a 'terms-of-service' Link header, and an 'instance' URL directing the user to agree.
Every JWS sent by an ACME client MUST include a 'nonce' header parameter with a value previously issued by the server in a Replay-Nonce header field. Once a nonce appears in a request, the server MUST treat it as invalid. The server MUST include a Replay-Nonce header in every successful response to a POST request.
For a wildcard domain name identifier in a newOrder request, the authorization returned by the server MUST NOT include the '*.' prefix in the authorization identifier value and MUST include the 'wildcard' field set to true.
For the dns-01 challenge, the client MUST provision a DNS TXT record at _acme-challenge.<domainName> containing the base64url encoding of the SHA-256 digest of the key authorization.
For the http-01 challenge, the server validates by performing an HTTP GET to http://<domain>/.well-known/acme-challenge/<token>. The client MUST ensure this resource returns the key authorization with Content-Type application/octet-stream.
The 'authorizations' and 'identifiers' arrays of an order object are immutable once set; the server MUST NOT change their contents after creation. A client observing a change SHOULD consider the order invalid.
The key authorization value used in challenges MUST be formed as token || '.' || base64url(JWK Thumbprint of the account public key). Challenge tokens MUST be at least 128 bits of entropy and use only URL-safe base64 characters.
The server MUST include a Cache-Control header with the 'no-store' directive in responses for the newNonce resource to prevent proxy caching, which would cause clients to receive duplicate nonces and trigger 'badNonce' errors.
Use of HTTPS is REQUIRED for all ACME communications. ACME servers SHOULD follow the TLS recommendations of RFC 7525. ACME clients MUST send a User-Agent header field including the ACME software name and version.
An ACME account object contains status (valid/deactivated/revoked), contact URL array, termsOfServiceAgreed, externalAccountBinding, and an orders URL. It is identified by the URL returned in the Location header of the 201 response to newAccount.
An ACME authorization object binds an account to an identifier (type + value, e.g., dns + 'www.example.org') and lists challenges the client may complete. A server considers authorization satisfied when any single challenge transitions to 'valid'.
An ACME order object represents a certificate issuance request and tracks identifiers, required authorization URLs, a finalize URL for CSR submission, optional notBefore/notAfter hints, an error object, and the certificate URL once issued.
External account binding links an ACME account to an existing non-ACME account via a MAC-signed inner JWS whose payload is the ACME account key in JWK form. The inner JWS protected header MUST use a MAC algorithm, MUST include the CA-provided key identifier as 'kid', MUST omit 'nonce', and MUST set 'url' to the same value as the outer JWS.
The ACME directory object is a JSON object mapping resource type names (newNonce, newAccount, newOrder, newAuthz, revokeCert, keyChange) to their URLs, plus an optional 'meta' object containing termsOfService, website, caaIdentities, and externalAccountRequired. It is the sole URL that clients need to bootstrap.
RFC 8555 creates eight new IANA registries under the ACME namespace: Account Object Fields, Order Object Fields, Authorization Object Fields, Error Types (in the urn:ietf:params:acme:error: namespace), Resource Types, Directory Meta Fields, Identifier Types, and Validation Methods.
The media type application/pem-certificate-chain is registered for ACME certificate download responses: an ordered sequence of PEM-encoded X.509 certificates, leaf first, suitable for direct installation.
ACME validation callbacks (especially http-01) can be abused as a server-side request forgery (SSRF) vector, causing the CA to make requests to internal network addresses. CAs should restrict outbound validation connections to public IP space.
Challenge tokens MUST have at least 128 bits of entropy to prevent brute-force pre-positioning attacks in which an adversary guesses the token, provisions the expected response, and then triggers certificate issuance.
The integrity of ACME authorizations depends on DNS security. Attackers who can manipulate DNS responses (e.g., via cache poisoning) can redirect http-01 or dns-01 challenges and obtain fraudulent certificates. ACME servers SHOULD use DNSSEC-validating resolvers and query from multiple network vantage points.
Authorization states: pending → valid (any challenge validated) or invalid (challenge fails/error); valid → revoked (server action), deactivated (client action), or expired (time passes 'expires'). Order states: pending → ready (all authz valid) → processing (finalize submitted) → valid (cert issued) or invalid (error, authz failure, or expiry).
Challenge states: pending (created) → processing (client responds, server begins validation) → valid (validation succeeds) or invalid (validation fails). The server may retry validation within the processing state without causing a state transition.
Binary fields in ACME JSON objects are encoded as base64url per RFC 4648 Section 5 with the RFC 7515 profile: URL-safe alphabet, trailing '=' characters MUST be stripped, and values with trailing '=' MUST be rejected as improperly encoded.
The Replay-Nonce HTTP header field carries a server-generated value encoded as base64url (ABNF: 1*base64url). The server MUST generate values that are unique per message with high probability and unpredictable to third parties. Clients MUST ignore invalid Replay-Nonce values.