-
Notifications
You must be signed in to change notification settings - Fork 192
Minor fixes in responses to pre-RFC-Editor review with EKR #467
Changes from 4 commits
1e3bb8c
106e49e
8b3a32a
b4930f4
729a9ef
447d4fe
0bc1c98
f08d5ae
bfbf23e
46c277d
09d8091
7069548
8e725f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -226,7 +226,7 @@ from the client. | |
# Protocol Overview | ||
|
||
ACME allows a client to request certificate management actions using a set of | ||
JavaScript Object Notation (JSON) messages carried over HTTPS. | ||
JavaScript Object Notation (JSON) messages carried over HTTPS {{!RFC7159}} {{!RFC2818}}. | ||
Issuance using ACME resembles a traditional CA's issuance process, in which a user creates an account, | ||
requests a certificate, and proves control of the domain(s) in that certificate in | ||
order for the CA to issue the requested certificate. | ||
|
@@ -509,7 +509,8 @@ any signed request from the client to carry such a nonce. | |
An ACME server provides nonces to clients using the HTTP Replay-Nonce header field, | ||
as specified in {{replay-nonce}} below. The server MUST include a Replay-Nonce | ||
header field in every successful response to a POST request and SHOULD provide | ||
it in error responses as well. | ||
it in error responses as well. Servers SHOULD use globally scoped nonces, so that | ||
a nonce, once issued, will be accepted on any HTTP request. | ||
|
||
Every JWS sent by an ACME client MUST include, in its protected header, the | ||
"nonce" header parameter, with contents as defined in | ||
|
@@ -688,7 +689,7 @@ enables: | |
ACME is structured as a REST {{REST}} application with the following types of resources: | ||
|
||
* Account resources, representing information about an account | ||
({{account-objects}}, {{account-creation}}) | ||
({{account-objects}}, {{account-management}}) | ||
* Order resources, representing an account's requests to issue certificates | ||
({{order-objects}}) | ||
* Authorization resources, representing an account's authorization to act for an | ||
|
@@ -699,7 +700,7 @@ ACME is structured as a REST {{REST}} application with the following types of re | |
({{downloading-the-certificate}}) | ||
* A "directory" resource ({{directory}}) | ||
* A "newNonce" resource ({{getting-a-nonce}}) | ||
* A "newAccount" resource ({{account-creation}}) | ||
* A "newAccount" resource ({{account-management}}) | ||
* A "newOrder" resource ({{applying-for-certificate-issuance}}) | ||
* A "revokeCert" resource ({{certificate-revocation}}) | ||
* A "keyChange" resource ({{account-key-roll-over}}) | ||
|
@@ -866,7 +867,7 @@ contact (optional, array of string): | |
: An array of URLs that the server can use to contact the client for issues | ||
related to this account. For example, the server may wish to notify the | ||
client about server-initiated revocation or certificate expiration. | ||
For information on supported URL schemes, see {{account-creation}} | ||
For information on supported URL schemes, see {{account-management}} | ||
|
||
termsOfServiceAgreed (optional, boolean): | ||
: Including this field in a new-account request, with a value of true, indicates | ||
|
@@ -1276,12 +1277,11 @@ The server MUST include a Cache-Control header field with the "no-store" | |
directive in responses for the new-nonce resource, in order to prevent | ||
caching of this resource. | ||
|
||
## Account Creation | ||
## Account Management | ||
|
||
A client creates a new account with the server by sending a POST request to the | ||
bifurcation marked this conversation as resolved.
Show resolved
Hide resolved
|
||
server's new-account URL. The body of the request is a stub account object | ||
optionally containing the "contact" and "termsOfServiceAgreed" fields, and | ||
optionally the "onlyReturnExisting" and "externalAccountBinding" fields. | ||
containing some subset of the following fields: | ||
|
||
contact (optional, array of string): | ||
: Same meaning as the corresponding server field defined in {{account-objects}} | ||
|
@@ -1360,7 +1360,8 @@ JWS (i.e., the "jwk" element of the JWS header) to authenticate future requests | |
from the account. The server returns this account object in a 201 (Created) | ||
response, with the account URL in a Location header field. The account URL is | ||
used as the "kid" value in the JWS authenticating subsequent requests by this | ||
account (See {{request-authentication}}). | ||
account (see {{request-authentication}}). The account URL is also used for | ||
requests for management actions on this account, as described below. | ||
|
||
~~~~~~~~~~ | ||
HTTP/1.1 201 Created | ||
|
@@ -1817,7 +1818,7 @@ The CSR encodes the client's requests with regard to the content of the | |
certificate to be issued. The CSR MUST indicate the exact same set of requested | ||
identifiers as the initial new-order request. Identifiers of type "dns" MUST appear either in the commonName portion | ||
of the requested subject name, or in an extensionRequest attribute {{!RFC2985}} | ||
requesting a subjectAltName extension. (These identifiers may appear | ||
requesting a subjectAltName extension, or both. (These identifiers may appear | ||
in any sort order.) Specifications that define | ||
new identifier types must specify where in the certificate signing | ||
request these | ||
|
@@ -2036,7 +2037,7 @@ in DER format. Server support for alternate formats is OPTIONAL. For | |
formats that can only express a single certificate, the server SHOULD | ||
provide one or more `Link: rel="up"` header fields pointing to an issuer or | ||
issuers so that ACME clients can build a certificate chain as defined | ||
in TLS {{!RFC8446}}. | ||
in TLS (see Section 4.4.2 of {{!RFC8446}}). | ||
|
||
## Identifier Authorization | ||
|
||
|
@@ -2823,19 +2824,22 @@ Template: | |
* Field name: The string to be used as a field name in the JSON object | ||
* Field type: The type of value to be provided, e.g., string, boolean, array of | ||
string | ||
* Client configurable: Boolean indicating whether the server should accept | ||
values provided by the client | ||
* Requests: Either the value "none" or a list of types of requests | ||
where the field is allowed in a request object, taken from the | ||
following values: | ||
* "new" - Requests to the "newAccount" URL | ||
* "account" - Requests to an account URL | ||
* Reference: Where this field is defined | ||
|
||
Initial contents: The fields and descriptions defined in {{account-objects}}. | ||
|
||
| Field Name | Field Type | Configurable | Reference | | ||
| Field Name | Field Type | Requests | Reference | | ||
|:-------------------------|:----------------|:-------------|:----------| | ||
| status | string | false | RFC XXXX | | ||
| contact | array of string | true | RFC XXXX | | ||
| externalAccountBinding | object | true | RFC XXXX | | ||
| termsOfServiceAgreed | boolean | true | RFC XXXX | | ||
| orders | string | false | RFC XXXX | | ||
| status | string | new, account | RFC XXXX | | ||
| contact | array of string | new, account | RFC XXXX | | ||
| externalAccountBinding | object | new | RFC XXXX | | ||
| termsOfServiceAgreed | boolean | new | RFC XXXX | | ||
| orders | string | none | RFC XXXX | | ||
|
||
\[\[ RFC EDITOR: Please replace XXXX above with the RFC number assigned to this | ||
document ]] | ||
|
@@ -3380,8 +3384,13 @@ account holder could take within the scope of ACME: | |
|
||
For this reason, it is RECOMMENDED that account key pairs be used for no other | ||
purpose besides ACME authentication. For example, the public key of an account | ||
key pair SHOULD NOT be included in a certificate. ACME clients and servers | ||
SHOULD verify that a CSR submitted in a finalize request does not contain a | ||
key pair MUST NOT be included in a certificate. ACME clients MUST NOT reuse | ||
the same account key for multiple accounts, and MUST NOT allow account key | ||
roll-over to a previously-used account key. ACME servers MUST NOT create a new | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think adding "MUST NOT allow account key roll-over to a previously-used account key" is overly prescriptive and under specified for this late in the game. Why isn't this restriction also mentioned in the key rollover section of the draft? The list of steps the server needs to take in https://tools.ietf.org/html/draft-ietf-acme-acme-16#section-7.3.5 mentions "Check that no account exists whose account key is the same as the key in the "jwk" header parameter of the inner JWS." but nothing about also verifying that the new key has never been used by the account previously. What threat is this addressing that justifies the new complexity? Are we sure the security win is proportional? What error is returned if a client tries to roll-over to a key that has been used by the account in the past? How much key history does the server need to keep? What happens if an ACME account decides to roll-over to a new randomly generated keypair every minute? What should servers do to avoid that being abused? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that the "MUST NOT allow account key roll-over to a previously-used account key" is a requirement on ACME clients rather than ACME servers. It's not clear why a client would bother to implement such a check, since it requires keeping around old keys, and so far client implementers have shown a desire to minimize the amount of state they need to retain. So I'm against adding this, on the principle that we shouldn't add MUSTs that won't actually get implemented (and don't break anything if they're not implemented). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Ahhhh! I apologize. I totally missed that part. I agree with you that it seems like it isn't likely to get implemented. I'm also dubious of the value if the server doesn't enforce this constraint as well, and as mentioned I think the server enforcing it has its own set of complications. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I read "MUST NOT allow" as a clunky way of saying "MUST NOT do" and given that the client probably generates the account key itself, this seems quite easy to enforce. WRT the value if the server doesn't enforce it, I'm not following why that would be the case. We, for instance, often want clients to generate fresh DH shares, even though the server usually does not check that they have done so. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are clients (such as the one I'm working on) which simply use whatever the user provides, and which don't have any state (besides what the user provides, i.e. path to account private key, and maybe the account URI). There's no way to implement this since key generation is not done by them, and the user could simply switch back and forth between two different keys -- the client wouldn't notice. I guess there are some more clients which work similarly. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If that's the intent, the clause should just be written as "the subscriber MUST NOT xxx". But I think that's not likely to be effective; most subscribers aren't reading the RFC, just using an off-the-shelf client. Maybe this belongs more in the security considerations section, describing what will happen if a user does rotate to an old key for some reason? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think that that's right. You usually have to read IETF specs with the mindset that everything on one side of the connection is a monolithic unit, and this is no exception There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So you'd be satisfied with a "subscriber MUST" here in place of the "client MUST"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the desired state here is that if the client or server has the state to determine that key reuse has occurred, then it must check and reject reuse. (Arguably, you can never use the same account key for multiple accounts if you only deal with one account at a time.) Would you be more comfortable with these requirements if they had that caveat? Say:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Do any clients meeting this criteria exist? Does the benefit of addressing this niche justify last-minute specification changes? I feel like its no in both cases. If we absolutely have to land this text to make forward progress then I'm not strongly opposed but it doesn't seem practically useful to me. |
||
account using an account key already associated with an account on the server. | ||
|
||
ACME clients and servers | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think a spurious newline slipped in here |
||
MUST verify that a CSR submitted in a finalize request does not contain a | ||
public key for any known account key pair. In particular, when a server | ||
receives a finalize request, it MUST verify that the public key in a CSR is not | ||
the same as the public key of the account key pair used to authenticate that | ||
|
@@ -3420,8 +3429,9 @@ is required to contain at least 128 bits of entropy for the following security | |
properties. First, the ACME client should not be able to influence the ACME | ||
server's choice of token as this may allow an attacker to reuse a domain owner's | ||
previous challenge responses for a new validation request. Secondly, the entropy | ||
requirement prevents ACME clients from implementing a "naive" validation server | ||
that automatically replies to challenges by predicting the token. | ||
requirement makes it more difficult for ACME clients to implement a "naive" | ||
validation server that automatically replies to challenges without being | ||
configured per-challenge. | ||
|
||
## Malformed Certificate Chains | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewing the conversation on this, I think this SHOULD is too strong and should be a MAY. For example, Let's Encrypt scopes nonces by client IP, for ease of implementation. One could easily imagine another implementation that chooses to scope by account.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's an interop concern here, in that clients need to know how they can use nonces. I would probably make the slightly stronger argument that we should forbid servers from doing things that would break the obvious ways for clients to handle nonces (i.e., in one pool per client).
For example, a server could have a scheme where (1) a
newNonce
-issued nonce is good for talking to any resource, but (2) nonces issued from other resources can only be used with resources of the same class. That would cause a lot of fail/newNonce/retry loops for a client doing the obvious thing.TBH, incorporating client IP seems kind of on the edge, as it's not crazy to imagine that a client could change addresses during the course of an ACME issuance flow.
How about something like this:
The latter part ensures that the fail/newNonce/retry loop works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that's true. Clients that send a nonce to a server from the wrong scope will get back a nonce rejection error that itself has a new nonce to use that the server will accept subsequently. The spec already says that a client SHOULD retry in this case. Some imagined (e.g. not implemented, not discussed on list by anyone) server nonce implementations like per-resource scoping might provoke more retries from clients but that seems like a fair trade-off for a hypothetical design choice and not a concern that justifies changing the draft text.
I don't think the text should have a "SHOULD NOT" added that directly contradicts all of the existing server implementations I'm aware of, and certainly the largest production ACME implementation and its ecosystem of compatible clients.
At this stage of the process I really think that every change should have an extremely strong justification. This change contradicts all implementation experience we have and the rationale for it (e.g. supporting servers implementing per-resource nonce schemes) does not seem strong enough to meet the bar for merging.