Skip to content
This repository has been archived by the owner on Apr 24, 2020. It is now read-only.

Remove GET requests #445

Merged
merged 11 commits into from
Sep 24, 2018
185 changes: 131 additions & 54 deletions draft-ietf-acme-acme.md
Original file line number Diff line number Diff line change
Expand Up @@ -425,11 +425,6 @@ For all other requests, the request is signed using an existing account and
there MUST be a "kid" field. This field MUST contain the account URL received by
POSTing to the newAccount resource.

Note that authentication via signed JWS request bodies implies that GET requests
are not authenticated. Servers MUST NOT respond to GET requests for resources
that might be considered sensitive. Account resources are the only sensitive
resources defined in this specification.

If the client sends a JWS signed with an algorithm that the server does not
support, then the server MUST return an error with status code 400 (Bad Request)
and type "urn:ietf:params:acme:error:badSignatureAlgorithm". The problem
Expand All @@ -443,6 +438,42 @@ set to "application/jose+json". If a request does not meet this
requirement, then the server MUST return a response with status code
415 (Unsupported Media Type).

## GET and POST-as-GET Requests

Note that authentication via signed JWS request bodies implies that
requests without an entity body are not authenticated, in particular
GET requests. Except for the cases described in this section, if
the server receives a GET request, it MUST return an error with
status code 405 "Method Not Allowed" and type "malformedRequest".

If a client wishes to fetch a resource from the server (which would
otherwise be done with a GET), then it MUST send a POST request with
a JWS body as described above, where the payload of the JWS is a
zero-length octet string. In other words, the "payload" field of the
JWS object MUST be present and set to the empty string ("").

We will refer to these as "POST-as-GET" requests. On receiving a
request with a zero-length (and thus non-JSON) payload, the server
MUST authenticate the sender and verify any access control rules.
Otherwise, the server MUST treat this request as having the same
semantics as a GET request for the same resource.

The server MUST allow GET requests for the directory and newNonce
resources (see {{resources}}), in addition to POST-as-GET requests
for these resources. This enables clients to bootstrap into the
ACME authentication system.

The server MAY allow GET requests for certificate resources in
order to allow certificates to be fetched by a lower-privileged
process, e.g., the web server that will use the referenced
certificate chain. (See {{?I-D.ietf-acme-star}} for more advanced
cases.) A server that allows GET requests for certificate resources
can still provide a degree of access control by assigning them
capability URLs {{?W3C.WD-capability-urls-20140218}}.
As above, if the server does not allow GET requests for a given
resource, it MUST return an error with status code 405 "Method Not
Allowed" and type "malformedRequest".

## Request URL Integrity

It is common in deployment for the entity terminating TLS for HTTPS to be different
Expand Down Expand Up @@ -735,18 +766,18 @@ establish a new account with the server, prove control of an identifier, issue a
certificate, and fetch an updated certificate some time after issuance. The
"->" is a mnemonic for a Location header pointing to a created resource.

| Action | Request | Response |
|:----------------------|:--------------------------|:---------------|
| Get directory | GET directory | 200 |
| Get nonce | HEAD newNonce | 200 |
| Create account | POST newAccount | 201 -> account |
| Submit order | POST newOrder | 201 -> order |
| Fetch challenges | GET order authorizations | 200 |
| Respond to challenges | POST challenge urls | 200 |
| Poll for status | GET order | 200 |
| Finalize order | POST order finalize | 200 |
| Poll for status | GET order | 200 |
| Download certificate | GET order certificate | 200 |
| Action | Request | Response |
|:----------------------|:---------------------------|:---------------|
| Get directory | GET directory | 200 |
| Get nonce | HEAD newNonce | 200 |
| Create account | POST newAccount | 201 -> account |
| Submit order | POST newOrder | 201 -> order |
| Fetch challenges | POST-as-GET authorizations | 200 |
| Respond to challenges | POST challenge urls | 200 |
| Poll for status | POST-as-GET order | 200 |
| Finalize order | POST order finalize | 200 |
| Poll for status | POST-as-GET order | 200 |
| Download certificate | POST-as-GET certificate | 200 |

The remainder of this section provides the details of how these resources are
structured and how the ACME protocol makes use of them.
Expand Down Expand Up @@ -855,7 +886,7 @@ by the client.

orders (required, string):
: A URL from which a list of orders submitted by this account can be fetched via
a GET request, as described in {{orders-list}}.
a POST-as-GET request, as described in {{orders-list}}.

~~~~~~~~~~
{
Expand All @@ -872,7 +903,7 @@ a GET request, as described in {{orders-list}}.
#### Orders List

Each account object includes an "orders" URL from which a list of orders created
by the account can be fetched via GET request. The result of the GET request
by the account can be fetched via POST-as-GET request. The result of the request
MUST be a JSON object whose "orders" field is an array of URLs, each identifying
an order belonging to the account. The server SHOULD include pending orders,
and SHOULD NOT include orders that are invalid in the array of URLs. The server
Expand Down Expand Up @@ -940,7 +971,7 @@ authorizations (required, array of string):
before the requested certificate can be issued (see
{{identifier-authorization}}), including unexpired authorizations that the client has completed in the past for identifiers specified in the order. The authorizations required are dictated by server policy and there may not be a 1:1 relationship between the order identifiers and the authorizations required. For final orders (in the "valid" or "invalid" state), the authorizations that
were completed. Each entry is a URL from which an authorization can be fetched
with a GET request.
with a POST-as-GET request.

finalize (required, string):
: A URL that a CSR must be POSTed to once all of the order's authorizations are
Expand Down Expand Up @@ -1408,14 +1439,6 @@ Content-Type: application/jose+json
}
~~~~~~~~~~

### Account Information

Servers MUST NOT respond to GET requests for account resources as these
requests are not authenticated. If a client wishes to query the server for
information about its account (e.g., to examine the "contact" or "orders"
fields), then it SHOULD do so by sending a POST request with an empty update.
That is, it should send a JWS whose payload is an empty object ({}).

### Changes of Terms of Service

As described above, a client can indicate its agreement with the CA's terms of
Expand Down Expand Up @@ -1639,9 +1662,13 @@ orders or authorization transactions based on a change of account key.

### Account Deactivation

A client can deactivate an account by posting a signed update to the account URL
with a status field of "deactivated." Clients may wish to do this when the
account key is compromised or decommissioned.
A client can deactivate an account by posting a signed update to the account URL with
a status field of "deactivated." Clients may wish to do this when the account
key is compromised or decommissioned. A deactivated account can no longer request
certificate issuance or access resources related to the account, such as orders
or authorizations. If a server receives a POST or POST-as-GET from
a deactivated account, it MUST return an error response with status
code 401 (Unauthorized) and type "urn:ietf:params:acme:error:unauthorized".

~~~~~~~~~~
POST /acme/acct/1 HTTP/1.1
Expand Down Expand Up @@ -1821,7 +1848,7 @@ server SHOULD leave the order in the "ready" state, to allow the
client to submit a new finalize request with an amended CSR.

A valid request to finalize an order will return the order to be finalized.
The client should begin polling the order by sending a GET request to the order
The client should begin polling the order by sending a POST-as-GET request to the order
resource to obtain its current state. The status of the order will indicate what
action the client should take:

Expand All @@ -1836,7 +1863,7 @@ action the client should take:
fulfilled, and is awaiting finalization. Submit a finalization
request.

* "processing": The certificate is being issued. Send a GET request after the
* "processing": The certificate is being issued. Send a POST-as-GET request after the
yaronf marked this conversation as resolved.
Show resolved Hide resolved
time given in the "Retry-After" header field of the response, if
any.

Expand Down Expand Up @@ -1955,7 +1982,7 @@ described in {{identifier-authorization}} to complete the authorization process.

### Downloading the Certificate

To download the issued certificate, the client simply sends a GET request to the
To download the issued certificate, the client simply sends a POST-as-GET request to the
certificate URL.

The default format of the certificate is application/pem-certificate-chain (see {{iana-considerations}}).
Expand Down Expand Up @@ -2024,15 +2051,28 @@ 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 new order request,
it downloads the authorization resources by sending GET requests to the
indicated URLs. If the client initiates authorization using a request to the
new authorization resource, it will have already received the pending
authorization object in the response to that request.
When a client receives an order from the server in reply to a new order 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 new authorization resource, it
will have already received the pending authorization object in the response
to that request.

~~~~~~~~~~
GET /acme/authz/1234 HTTP/1.1
POST /acme/authz/1234 HTTP/1.1
Host: example.com
Content-Type: application/jose+json
Accept: application/pkix-cert

{
"protected": base64url({
"alg": "ES256",
"kid": "https://example.com/acme/acct/1",
"nonce": "uQpSjlRb4vQVCjVYAyyUWg",
"url": "https://example.com/acme/authz/1234",
}),
"payload": "",
"signature": "nuSDISbWG8mMgE7H...QyVUL68yzf3Zawps"
}

HTTP/1.1 200 OK
Content-Type: application/json
Expand Down Expand Up @@ -2121,15 +2161,28 @@ 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 GET request to
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.

~~~~~~~~~~
GET /acme/authz/1234 HTTP/1.1
POST /acme/authz/1234 HTTP/1.1
Host: example.com
Content-Type: application/jose+json
Accept: application/pkix-cert

{
"protected": base64url({
"alg": "ES256",
"kid": "https://example.com/acme/acct/1",
"nonce": "uQpSjlRb4vQVCjVYAyyUWg",
"url": "https://example.com/acme/authz/1234",
}),
"payload": "",
"signature": "nuSDISbWG8mMgE7H...QyVUL68yzf3Zawps"
}

HTTP/1.1 200 OK
Content-Type: application/json
Expand Down Expand Up @@ -2443,12 +2496,6 @@ include base64 padding characters ("="). See {{!RFC4086}} for additional inform
on randomness requirements.

~~~~~~~~~~
GET /acme/authz/1234/0 HTTP/1.1
Host: example.com

HTTP/1.1 200 OK
Content-Type: application/json

{
"type": "http-01",
"url": "https://example.com/acme/authz/0",
Expand Down Expand Up @@ -2549,12 +2596,6 @@ base64url alphabet, including padding characters ("="). See {{!RFC4086}} for
additional information on randomness requirements.

~~~~~~~~~~
GET /acme/authz/1234/2 HTTP/1.1
Host: example.com

HTTP/1.1 200 OK
Content-Type: application/json

{
"type": "dns-01",
"url": "https://example.com/acme/authz/1234/2",
Expand Down Expand Up @@ -3274,6 +3315,42 @@ CAs using ACME to allow clients to agree to terms of service should keep in mind
that ACME clients can automate this agreement, possibly not involving a human
user.

ACME does not specify how the server constructs the URLs that it
uses to address resources. If the server operator uses URLs that
are predictable to third parties, this can leak information about
what URLs exist on the server, since an attacker can probe for
whether POST-as-GET request to the URL returns "Not Found" or
"Unauthorized".

For example, suppose that the CA uses highly structured URLs with
several low-entropy fields:

* Accounts: https://example.com/:accountID
* Orders: https://example.com/:accountID/:orderID
* Authorizations: https://example.com/:accountID/:authorizationID
* Certificates: https://example.com/:accountID/:certID

If the ID fields have low entropy, then an attacker can find out how
many users a CA has, how many authorizations each account has, etc.

In order to avoid leaking these correlations, servers SHOULD assign
capability URLs for dynamically-created resources
{{?W3C.WD-capability-urls-20140218}}. These URLs incorporate large
unpredictable components to prevent third parties from guessing
them. These URLs SHOULD NOT have a structure that would enable a
third party to infer correlations between resources.

For example, a CA might assign URLs for each resource type from an
independent namespace, using unpredictable IDs for each resource:

* Accounts: https://example.com/acct/:accountID
* Orders: https://example.com/order/:orderID
* Authorizations: https://example.com/authz/:authorizationID
* Certificates: https://example.com/cert/:certID

Such a scheme would leak only the type of resource, hiding the
additional correlations revealed in the example above.

# Operational Considerations

There are certain factors that arise in operational reality that operators of
Expand Down