Re: [Acme] ACME draft is now in WGLC.

Martin Thomson <martin.thomson@gmail.com> Mon, 13 February 2017 05:26 UTC

Return-Path: <martin.thomson@gmail.com>
X-Original-To: acme@ietfa.amsl.com
Delivered-To: acme@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id 5DD0912947C for <acme@ietfa.amsl.com>; Sun, 12 Feb 2017 21:26:44 -0800 (PST)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -2.699
X-Spam-Level:
X-Spam-Status: No, score=-2.699 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7, SPF_PASS=-0.001, URIBL_BLOCKED=0.001] autolearn=ham autolearn_force=no
Authentication-Results: ietfa.amsl.com (amavisd-new); dkim=pass (2048-bit key) header.d=gmail.com
Received: from mail.ietf.org ([4.31.198.44]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id i92XPMsTQCbY for <acme@ietfa.amsl.com>; Sun, 12 Feb 2017 21:26:42 -0800 (PST)
Received: from mail-qk0-x232.google.com (mail-qk0-x232.google.com [IPv6:2607:f8b0:400d:c09::232]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id BC58312940E for <acme@ietf.org>; Sun, 12 Feb 2017 21:26:41 -0800 (PST)
Received: by mail-qk0-x232.google.com with SMTP id s140so84880401qke.0 for <acme@ietf.org>; Sun, 12 Feb 2017 21:26:41 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=6giMJWwVk/fsBQ8jH3K0vBI2HxYWv6n2PRdm3gH6NVI=; b=lHsI6ZZB+2b2XBmkOye2nfaGGA5tZWioX5ILgWE1sJ4yixwatPvoEfqSO9o2Jnfrru cuI8L6HQ/uY7szRrKE7Z7oh/fAeHtlVFDE/+KQhM0hMvBGrj8HXz14+m2OwL2oVB4CjA 3pBJXqReix59/4osAnXByrIo9fhtJczoMaJDOIAVOu7K1dyEkrHwKPQ4BlX9xkM3MgtI b4/aco3juUrye/HJr4Ka9ulBAiBWXLUwpHIzPMHwE88rN9V99Z0zjL6XKtil/GcGRtBv haLuDNDz7BmpT2rvb2JjpNYkM1P6fp66HDXWUW2MUV6gfeEw/LO8GW9n12omll1jzzYn 0wsg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=6giMJWwVk/fsBQ8jH3K0vBI2HxYWv6n2PRdm3gH6NVI=; b=rieWMc8fmJt2le91OSoVe6dV8eCuClweO5H2u9HNyYQEWqtIhegqNhURGKZtoP2/s1 4mPS0V8W+oYsYnX9UNVcaOl7siT9MFpAUrL3C0RjlgOvRTTBgiunfln+9V3uTbN7yUV+ xKmxSkBWr4BqJdJBkoC9i2/PPaLK7V3eGve00/vxCfjimJSDUPSVKKd9PeXqBy1JL4TO oMo52aIWxqypoTVSRyyM4c82HlUyKwbnvnrTFjjZ7SAlEvkpF+yuJQEkEZfGjMTsgEdF e6zXj51Dtd8audZCwEgT+D5d0ugpV47O73nSJsA+LnEo7x3UHHwlzUX8DHpd23kEyxtB ivjg==
X-Gm-Message-State: AMke39nN4H/YwGLzou6vMANvTcbdlyH6UUEktl6UmQm6i4sGqdsRXINnVXixUhO5m9gf9/aK/h5kPeBE5Vv3uw==
X-Received: by 10.233.216.68 with SMTP id u65mr19375069qkf.68.1486963600510; Sun, 12 Feb 2017 21:26:40 -0800 (PST)
MIME-Version: 1.0
Received: by 10.140.19.112 with HTTP; Sun, 12 Feb 2017 21:26:39 -0800 (PST)
In-Reply-To: <83f7104eef75470181d7f81fc7604a8e@usma1ex-dag1mb3.msg.corp.akamai.com>
References: <8473d9ba84894d49b2f2232370d66b46@usma1ex-dag1mb3.msg.corp.akamai.com> <83f7104eef75470181d7f81fc7604a8e@usma1ex-dag1mb3.msg.corp.akamai.com>
From: Martin Thomson <martin.thomson@gmail.com>
Date: Mon, 13 Feb 2017 16:26:39 +1100
Message-ID: <CABkgnnUbpFgGp3NRAocu2M4d1Zp-xjcxNFQyZ97pygTA6JM2cQ@mail.gmail.com>
To: "Salz, Rich" <rsalz@akamai.com>
Content-Type: text/plain; charset="UTF-8"
Archived-At: <https://mailarchive.ietf.org/arch/msg/acme/2ihRBcXDDx2x1D_XI2-HBgODBpY>
Cc: "acme@ietf.org" <acme@ietf.org>
Subject: Re: [Acme] ACME draft is now in WGLC.
X-BeenThere: acme@ietf.org
X-Mailman-Version: 2.1.17
Precedence: list
List-Id: Automated Certificate Management Environment <acme.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/acme>, <mailto:acme-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/acme/>
List-Post: <mailto:acme@ietf.org>
List-Help: <mailto:acme-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/acme>, <mailto:acme-request@ietf.org?subject=subscribe>
X-List-Received-Date: Mon, 13 Feb 2017 05:26:44 -0000

On 11 February 2017 at 05:56, Salz, Rich <rsalz@akamai.com> wrote:
> ACME WGLC

It's been a while since I did a review of this, so I spent a few hours on it.

This document is in pretty good shape.  I have a lot of comments (a
LOT), and some of these are serious enough that I'd want to see
another WGLC, but they are relatively minor.  Overall the document is
in very good shape; most of my comments are of the nitpicking variety.

This is a pretty significant piece of work and that this is as good as
it is represents cause for congratulations to those involved (except
me, I'm just a hazard).


Meta

I found the use of lowercase versions of RFC 2119 keywords quite
distracting, and occasionally confusing.  It's often the case that the
lowercase version is used where a simple imperative statement would
work.  I haven't called out many of those in my review, except where
they caused what I think to be a genuine problem.

I have created an editorial pull request on the spec.  There were lots
of tiny fixes (including some opportunities to correct the above).  In
some cases, that PR will conflict with substantial changes that I
think need to happen, so you might want to attend to that first.

   https://github.com/ietf-wg-acme/acme/pull/243


S5.1

   Clients SHOULD
   support HTTP public key pinning [RFC7469], and servers SHOULD emit
   pinning headers.

and

   ACME clients SHOULD send a User-Agent header in accordance with
   [RFC7231], including the name and version of the ACME software in
   addition to the name and version of the underlying HTTP client
   software.

and

   Such servers SHOULD
   set the Access-Control-Allow-Origin header field to the value "*".

Why?  It's usually good practice with a SHOULD to provide some sort of
reason why choosing not to comply might be necessary, or to otherwise
motivate the choice.  All three seem relatively easy to fix with a
simple sentence (pinning good m'kay, client bugs(?), building a
web-based client).

S5.2

   For all other requests, there MUST be a "kid" field.  This field must
   contain the account URI received by POSTing to the new-reg resource.

MUST?

   Servers MUST NOT respond to GET
   requests for resources that might be considered sensitive.

Since this is a requirement, it might pay to do a little due diligence
on what might be sensitive.  I'm not sure that all implementers will
have the same view (or same motivations) when it comes to this.

  server MUST return an error

This would benefit from a reference to S5.7, as does all the other
instances of error handling.  Though this section includes an example
(that seems unnecessary), it's very hard to tell if this is normative
or not from context.

   In the examples below, JWS objects are shown in the JSON or flattened
   JSON serialization, with the protected header and payload expressed
   as base64url(content) instead of the actual base64-encoded value, so
   that the content is readable.  Some fields are omitted for brevity,
   marked with "...".

I didn't really understand this without an example to use for
reference.  Given that the first actual use of this form is 15 (!)
pages further down the document, maybe you could move this there.

S5.3

   JWK thumbprint [citation needed]

S5.4

I would reference RFC 7230, Section 2.7.3 "http and https URI
Normalization and Comparison" here and note the risk that
normalization could cause comparison failures.  A recommendation that
URLs generated by the server SHOULD be normalized according to that
section so that the risk of normalization is reduced.

S5.5

   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.

This seems to purposefully neglect to mention other requests, like
GET.  Does the "SHOULD" apply just to POST requests, or is it any
method?

This section says that nonces are mandatory with POST requests, but
does not offer a way to get a nonce that does not require a nonce.
Please make this observation and reference S6.2.

S5.6

Once again, mention is made of error descriptions without a forward reference.

   Additionally, the server
   SHOULD send a "Retry-After" header indicating when the current
   request may succeed again.

"may" or "could"?

S5.7

In a couple of places, a specific error URN is mandated (with MUST),
but this section only uses SHOULD for the error description.

   Authorization and challenge objects can also contain error
   information to indicate why the server was unable to validate
   authorization.

Where and how would this appear?  This needs more definition (I
looked, but I didn't find anything further down).

S6.1

The list of resources could use some references to the sections that
define them.

S6.1.2

   status (required, string):  The status of this account.  Possible
      values are: "valid", "deactivated", and "revoked".  The value
      "deactivated" should be used to indicate user initiated
      deactivation whereas "revoked" should be used to indicate
      administratively initiated deactivation.

I assume that "user" and "administratively" mean "client" and "server"
respectively.  Please clarify this point, it's confusing.

S6.1.3

   authorizations (required, array of string):  For pending orders, the
      authorizations that the client needs to complete before the
      requested certificate can be issued (see Section 6.5).  For final
      orders, the authorizations that were completed.  Each entry is a
      URL from which an authorization can be fetched with a GET request.

Which states correspond to final?

If an order is pending with one authorization complete and another
incomplete, do I read that the complete authorization is NOT listed
here? But that doesn't fit with this:

   The elements of the "authorizations" array are immutable once set.

It might pay to clarify this some.

S6.1.4

   [[ Open issue: More flexible scoping? ]]

Red flag.  In my view, the simple approach is fine.  New authorization
resources are cheap.  They can even be cloned easily, even allowing
one challenge to fulfill multiple.

      A client should attempt to fulfill at most one of these challenges,
      and a server should consider any one of the challenges sufficient
      to make the authorization valid.

lowercase should or SHOULD or MUST?  This really needs more meat if it
is to be useful.  If we accept that a client can attempt to fulfill
more than one challenge on the basis that they might fail, then permit
them to try many, but encourage only one.  On the server side, if a
server later discovers that the challenges are insufficient, then
permit that too.

"A client only needs to complete one of these challenges, though it
MAY attempt more than one challenge if errors prevent it from
completing its first choice.  A server therefore MUST accept any
challenge, though a server MAY still choose not to permit an
authorization for other reasons."

Or something along those lines.  (BTW, I applaud the simplification
from earlier versions.)

S6.3

   A client creates a new account with the server by sending a POST
   request to the server's new-account URI.  The body of the request is
   a stub account object containing only the "contact" field.

In addition to the user account binding (S6.3.2), the example violates
this by including a ToS agreement.  I suspect the above is incorrect.

   [...] the server MUST reject new-account
   requests that do not have the "terms-of-service-agreed" set to
   "true".

Which error code do we use here?

S6.3.1

Is the intent that the "instance" document be loaded in a web browser,
as opposed to being poked by an ACME client?  It might help to
explicitly say that.

S6.3.2

   [...] and MUST reflect [the?] value of the
   "external-account-binding" field in the resulting account object

Is this a direct copy of the MAC that was provided?  Do you realize
that this enables a user with access to any account that was created
with a binding to replay the binding in new accounts without actually
having the MAC key?  Would it be acceptable to just reflect that the
binding exists?  (Potentially bad idea: just include the key id; if
the CA wants, that key identifier could be a URL to the external
account details page and do double-duty.)

Note that this would be a violation of the stated security goal of not
having integrity compromised by a TLS MitM or CDN.  It doesn't
necessarily permit misissuance unless the binding to the account
carries authorizations across, or things like that.

S6.3.3

"NOT REQUIRED" isn't a thing (at least as far as I can tell).  "MAY
omit the "nonce" parameter" would be fine, I think.  Frankly, I don't
see why they can't both be required to include a nonce, but I guess
that the account URI should be plenty specific enough to avoid any
problems with copy and paste of the inner JWS.

S6.3.4

   It is up to server policy
   how long to retain data related to that account, whether to revoke
   certificates issued by that account, and whether to send email to
   that account's contacts.

This is terrible.  If I wish to decommission an account key, then I
can't because I might find that my certificates are all suddenly
revoked.  Think about a large organization that has a pool of
authorized accounts used for managing certificates.  If one of those
needs to fall out of the pool (the machine hosting the key is being
scrapped or rebuilt, for instance), then you don't want to have all
the certificates that it issued disappearing suddenly.

If there are good reasons to revoke certificates, then be definite
about it and say that they go away, at least then people can plan
around the problem.

S6.4

   The body of this response is
   an order object reflecting the client's request and any
   authorizations the client must complete before the certificate will
   be issued.

I don't think that this is "MUST", but it's a confusing word to use here.

BTW, I like the description of the states in terms of what the client
should do.  There are other cases where this would be valuable, such
as in S6.5.


S6.4.1

...mentions "combinations", but I think that this has gone away.

   The server can also provide the client with direct access to an SCT
   for a certificate using a Link relation header field with relation
   "ct-sct".

Where is this link relation type registered?  It isn't in either the
IANA considerations section or in the registry:
http://www.iana.org/assignments/link-relations/link-relations.xhtml

The same goes for the other link relation types that are used in the
example.  I see neither "revoke" nor "directory" being registered.
BTW, "index" would probably do well instead of "directory", "revoke"
seems specific enough to this usage - like "ct-sct" that using a URI
for the relation type would probably be better than registering a link
relation.

S6.5.1

   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 may modify the "expires" field.

This just said two conflicting things about the "expires" field.  I
think that this could be: "When the authorization is finalized, if it
is "valid" then `expires` MUST be set, otherwise `expires` MUST be
removed.  A server MAY remove challenges other than the one that was
completed from a finalized authorization."

  Usually, the validation process will take some time,

Could this instead be "The validation process could take some time",
rather than making some statement based on what we know now in this
very narrow application of the protocol?

   In responding to poll requests while
   the validation is still in progress, the server MUST return a 202
   (Accepted) response

The 202 is an odd choice here.  The resource exists and has content,
so 200 works perfectly well for this purpose.

The use of Retry-After here is odd, but I think that it's fine.  I
would separate this out in a new paragraph: "A server MAY include a
Retry-After header field in its responses to clients, clients that are
polling for updates SHOULD wait at least this amount of time before
making another request to that resource."

S6.6

   The server MAY disallow a subset of reasonCodes from
      being used by the user.

Does a server ignore the reasonCode, or does it reject the request
when an impermissible code is chosen by the client?

S7

   This section describes an initial set of challenge types.  Each
   challenge must describe:

MUST, I think

S7.1

   UTF-8 form (or, equivalently, ASCII).

A normative citation for RFC 3269 is needed (and maybe even RFC 20).

S7.2

   Because many webservers 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.

MUST

   2.  Verify that the resulting URI is well-formed.

How is this ever not true?  The URI has to be well-formed since the
template is correct by design and the values for domain and token have
already been checked.

S7.3&4

   It is RECOMMENDED that the server open multiple TLS connections from
   various network perspectives, in order to make MitM attacks harder.

Isn't this equally valid for http?  (Or - more to the point - equally
invalid here?)

S9.2

I think that it makes sense here to say somewhere that while a TLS
MitM or CDN might compromise confidentiality (which has some
implications for account holders), they cannot compromise integrity.

Stylistically, this section is two things: a discussion of the ACME
channel and then a discussion of the challenge channel, would
subsections help?

   For identifiers
   where the server already has some public key associated with the
   domain this attack can be prevented by requiring the client to prove
   control of the corresponding private key.

This doesn't seem right.  I believe that the model permits multiple
accounts to act for a single domain.  Not doing so would represent a
pretty big operational burden.  What public key does this then refer
to?  Or is this promise not valid?

S9.3

You should also recommend rate limits on account creation, or your
other mitigations might be weakened.

S9.4

Does an ACME server send Referer[sic]?  What should it set it to?

S9.5

This should probably recommend doing these checks - to the extent
possible - before creating the order.  Though issuance is the ultimate
thing that needs to be controlled, allowing an order to proceed just
makes extra work for all involved.

S10.2

   A CA that accepts TLS-based proof of domain control should attempt to
   check whether a domain is hosted on a domain with a default virtual
   host before allowing an authorization request for this host to use a
   TLS-based challenge.  A default virtual host can be detected by
   initiating TLS connections to the host with random SNI values within
   the namespace used for the TLS-based challenge (the "acme.invalid"
   namespace for "tls-sni-02").

This doesn't seem right.  If the default vhost is an attacker, then
they can generate the answers the server expects.  Based on this text,
I don't actually know what the right answer might be, is it a TLS
unrecognized_name alert?