Description
The goal of this proposal is to agree on the implementation details of RFC8555 in #21081.
The acme package currently implements an approximation of draft-02, aka "ACMEv1 API".
The RFC8555 is the final version of the ACME protocol, aka "ACMEv2 API", based on draft-18. Let's Encrypt announced End of Life of their ACMEv1 in https://community.letsencrypt.org/t/end-of-life-plan-for-acmev1/88430 where first deadline is Nov 2019 past which no new account registrations will be allowed.
Note that we have 2 packages in scope:
- https://golang.org/x/crypto/acme: this is a barebones low level client essentially mirroring the ACME API with some helper functions;
- https://golang.org/x/crypto/acme/autocert: it is based on the former, offering to users users completely automated workflow of cert issuance and renewals.
While this issue is mostly concerned with the acme
package, autocert
package will also be impacted in different ways based on this proposal resolution although it should be a relatively easy set of changes since most of its functionality is automated and unexported.
There are currently two conflicting proposals. I will list pros & cons for each one as I see them.
1. Replace golang.org/x/crypto/acme
with a strict RFC8555 implementation, essentially removing all remnants of draft-02.
An example of this is https://golang.org/cl/86635.
Pros:
- removes draft-02 bits which aren't used or replaced with alternatives in the RFC
- already have a CL although it needs to catch up with some later additions
to the current acme package and split up in smaller CLs to make it possible
for a reasonable human review - clean slate: can completely rewrite all of acme and the Client API
to possibly improve although I don't have concrete shiny examples
Cons:
- breaks all existing users
- makes acme and autocert packages incompatible with other ACME CAs which haven't
implemented RFC8555 yet; at the time of writing:- BuyPass: only ACMEv1 in production
- Entrust: seems to provide only ACMEv1 endpoint
- GlobalSign: unclear but I suspect v1, although I've heard they might be working on v2; totally speculative
- Venafi: judging from their docs it's a v1 although based on draft-06; certainly not RFC anyway
- EJBCA: draft-12, so it isn't actually too far from the RFC
- there are a couple private CAs that I know of; they're still at draft-02
2. Add RFC855 support to the existing acme package without breaking its users and their issuance using ACME CAs
The major exported changes would be the following:
- new
acme.Client
methodsCreateOrder
andFinalizeOrder
to implement order-based issuance flow which is preferred in the RFC, as opposed to the pre-authorization flow using the existingAuthorize
method; the pre-authorization flow is optional in RFC and in fact Let's Encrypt does not provide it in their ACMEv2 but some other CAs do - new exported structs such as
Order
to accomodate the new order-based issuance flow and new fields in the existing exported structs such as those in acme.Directory in https://go-review.googlesource.com/c/crypto/+/182937/2/acme/types.go; I expect them to have valid zero values or be populated by the acme client accordingly - JWS request signature format and requirement of
kid
andurl
fields; although most changes
should be transparent, they may require some newacme.Client
methods to accommodate the new JWS/JWK formats
I do not expect for the existing exported methods of acme.Client to be removed or their signatures changed. Their implementation will branch according to the endpoint in use: ACMEv1 or ACMEv2. This is possible because the Client performs directory fetch automatically upon first network round-trip for any client call whenever required using its Discover method. It can thus identify which version of ACME protocol is in use at the right time.
Later on, we can amend the acme client and remove ACMEv1 support as more CAs catch up with the RFC compliance.
Pros:
- doesn't break existing users, or at least it shouldn't - that's the idea
- keeps working with the CAs mentioned above which haven't migrated to the RFC yet
Cons
- legacy baggage to support non-RFC compliant CAs until the majority of them are,
which most likely means more complicated code until the support for non-compliant CAs
is dropped completely
A non-exhaustive list of alternatives I've been thinking of:
- Use go mod and have two versions of /x/crypto since acme is a sub directory. I don't belive
acme changes alone justify this. - Move current acme,autocert packages into something like /v1 sub directory and replace acme pkg with an RFC8555-rewrite. We now have go mod; this feels like a step backwards.
- Add RFC855-only package into a /v2 and at some point replace the current acme with it. Same
as before: feels like a step backwards considering go mod. - Fork current acme outside for /x/crypto and replace x/crypto/acme with RFC8555 to let those
who's still stuck with non-RFC compliant CAs still run. This fork will unlikely get future
improvements unless someone will have time to backport the changes. - Move the whole /x/crypto/acme/... somewhere else outside of /x/crypto. This would've allowed go mod versioning. It's probably too big of a change and a bit ouf of scope here.
Personally, I'm in favour of (2), i.e. add RFC support to the existing acme client and keep it working with all major ACME CAs out there until reasonably possible without too much of an overhead.