Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: x/crypto/acme: Add External Account Binding Support #41430

Closed
jdkasten opened this issue Sep 16, 2020 · 10 comments
Closed

proposal: x/crypto/acme: Add External Account Binding Support #41430

jdkasten opened this issue Sep 16, 2020 · 10 comments

Comments

@jdkasten
Copy link

RFC 8555's External Account Binding is not currently supported by x/crypto/acme while there are multiple certificate authorities that require the feature. (Sectigo, zerossl, etc)

External Account Binding (EAB) occurs in ACME's "new-account" RPC. Within acme.go this is handled by Register()

The public API for this method would not have to change. Notably, the call takes in an Account struct which is a non-wire compatible version of an ACME Account object. Since the normal wire protocol account object contains the EAB, a simple extension of the Account struct seems appropriate. This new field would contain an "EAB struct" that would be easily configurable by end users. The EAB struct can be similarly serialized into an ACME EAB JWS within the existing Register method.

As far as requirements go, the RFC states that

  1. EAB key needs to be a MAC key
  2. The key identifier (kid) be ASCII.
  3. CA's SHOULD provide the key in base64url-encoded format for compatibility.

I have seen many client implementations assume HMAC SHA256 is used, though this is not guaranteed by the protocol. [1, 2]

The External account binding struct would need to look something like

// ExternalAccountBinding contains the data needed to form a request with
// an external account binding.
// See https://tools.ietf.org/html/rfc8555#section-7.3.4 for more details.
type ExternalAccountBinding struct {
	// KID is the Key ID of the symmetric MAC key that the CA uses to
	// identify an external account from ACME.
	KID string

	// Key is the bytes of a symmetric key that the CA uses to identify
	// the account. The KID should reference the same key that the CA holds.
	Key []byte

	// KeyAlgorithm of the JWS. Only the HMAC algorithms are supported
        // https://tools.ietf.org/html/rfc7518#section-3.1
	KeyAlgorithm string
}

Adapted from @munnerz's existing PR for this functionality.

@gopherbot gopherbot added this to the Proposal milestone Sep 16, 2020
@FiloSottile
Copy link
Contributor

Looks good to me, thank you. I suspect Account is the right place to put it, but I am not a fan of adding private keys to a type that did not have one before and might get logged. We should probably add a String method to hide the key from formatting.

Given Client has the account key, would it be a better place for the ExternalAccountBinding field?

/cc @rolandshoemaker

@rolandshoemaker
Copy link
Member

Account is probably the correct place for it since the EAB is only needed during account creation and putting it in Client may suggest that the user needs to populate it for all subsequent API calls after Client.Register, which could cause them to persist the key longer than they need to.

Agreed we should probably put something in place to prevent logging the field. I realize now that it's not explicitly called out in the RFC but the best practice should be for EAB keys to be one-time use (such that a EAB key can only be used to associate an external account with a single ACME account) but I suspect there will be implementations out there that will allow an EAB key to be used multiple times, so leaking the key would be bad.

@jdkasten
Copy link
Author

Thank you for the reviews. I agree that additional precautions should be implemented to help protect the key from being accidentally logged.

@rolandshoemaker
Copy link
Member

I think my only other real comment on this would be to replace KeyAlgorithm with a enum instead of a string, since we're only going to be supporting like three things, but ¯_(ツ)_/¯.

@jdkasten
Copy link
Author

jdkasten commented Oct 2, 2020

Assuming this proposal is in a reasonable state, I will aim to build upon the existing work by munnerz@ with the changes discussed here.

@gopherbot
Copy link
Contributor

Change https://golang.org/cl/269279 mentions this issue: acme: Add External Account Binding Support

@tmthrgd
Copy link
Contributor

tmthrgd commented Dec 17, 2020

I realise the CL has just landed so unfortunately not the best timing, but I’m quite confused about why the caller should have to specify the MAC algorithm. The RFC says only that “the CA operating the ACME server needs to provide the ACME client with a MAC key and a key identifier” with no mention of the algorithm.

It seems to me that the algorithm is entirely an internal implantation detail and should not be visible to callers. Furthermore, there’s no compelling reason (that I’m aware of) for callers to want to change this, all of the options are secure, in particular HMAC-SHA256 is a perfectly secure choice here that’s most likely to be compatible across the ecosystem. This really just seems like needless complexity and cryptographic agility that callers will have to understand and deal with (something I do know @FiloSottile has rightly championed against in the past).

The field and constants also provide no documentation about how a caller should pick the algorithm, which at the very least should be rectified. Otherwise I think most choices will be something like: HS256 is the first one so pick that or HS512 is the biggest number so it must be most secure.

Ultimately, is there any real use case where always using HS256 wouldn’t work? If so, how likely are callers to understand and correctly deal with that situation? It seems like that’s the approach used elsewhere and it would both simplify the API, the implementation and ease of use.

@jameshartig
Copy link
Contributor

I wonder if it could default to HMAC-SHA256 (if field was left empty) and then someone would only change it from the default if they explicitly told to.

@FiloSottile
Copy link
Contributor

FiloSottile commented Dec 21, 2020

Ah, yes, I should have caught that. I thought the MAC algorithm was a property of the key, where each key needs to be used with a server-picked algorithm, but if it's not we should just hardcode HMAC-SHA256 and try to shape the ecosystem for the better (as there is definitely no need for agility here).

The API is one weekend old, so informally I can't imagine we will break anyone by dropping it, and formally there is no compatibility promise in x/ repos at v0.0.0. (We still provide extremely strict backwards compatibility, but this feels like a good opportunity for an exception.)

I'll send a CL in a minute. We can always add it back if we're wrong.

@gopherbot
Copy link
Contributor

Change https://golang.org/cl/279453 mentions this issue: acme: hardcode and remove ExternalAccountBinding.Algorithm

gopherbot pushed a commit to golang/crypto that referenced this issue Dec 21, 2020
HMAC-SHA256 is a perfectly fine MAC algorithm, and there is no need to
ask the user to choose one.

This does break compatibility with the previous API, but it had been
live only for a weekend, so hopefully still in a window in which we can
make changes with a limited blast radius.

Updates golang/go#41430

Change-Id: I03741a545b25b9fcc147760cd20e9d7029844a6c
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/279453
Trust: Filippo Valsorda <filippo@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: James Kasten <jdkasten@google.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
@golang golang locked and limited conversation to collaborators Dec 21, 2021
LewiGoddard pushed a commit to LewiGoddard/crypto that referenced this issue Feb 16, 2023
Implements https://tools.ietf.org/html/rfc8555#section-7.3.4

Fixes golang/go#41430

Co-authored-by: James Munnelly <james@munnelly.eu>
Change-Id: Icd0337fddbff49e7e79fb9105c2679609f990285
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/269279
Run-TryBot: Katie Hockman <katie@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Katie Hockman <katie@golang.org>
Trust: Roland Shoemaker <roland@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
BiiChris pushed a commit to BiiChris/crypto that referenced this issue Sep 15, 2023
Implements https://tools.ietf.org/html/rfc8555#section-7.3.4

Fixes golang/go#41430

Co-authored-by: James Munnelly <james@munnelly.eu>
Change-Id: Icd0337fddbff49e7e79fb9105c2679609f990285
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/269279
Run-TryBot: Katie Hockman <katie@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Katie Hockman <katie@golang.org>
Trust: Roland Shoemaker <roland@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
desdeel2d0m added a commit to desdeel2d0m/crypto that referenced this issue Jul 1, 2024
Implements https://tools.ietf.org/html/rfc8555#section-7.3.4

Fixes golang/go#41430

Co-authored-by: James Munnelly <james@munnelly.eu>
Change-Id: Icd0337fddbff49e7e79fb9105c2679609f990285
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/269279
Run-TryBot: Katie Hockman <katie@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Katie Hockman <katie@golang.org>
Trust: Roland Shoemaker <roland@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants