Skip to content

Commit

Permalink
acme: expose Client KID field
Browse files Browse the repository at this point in the history
Expose the previously private KID field of the Client type. This allows
callers which have locally cached their key identity to avoid needing
to make a call to the ACME service every time they construct a new
client.

Fixes golang/go#46303

Change-Id: I219167c5b941f56a2028c4bc253ff56386845549
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/354697
Trust: Katie Hockman <[email protected]>
Reviewed-by: Katie Hockman <[email protected]>
Trust: Roland Shoemaker <[email protected]>
Run-TryBot: Roland Shoemaker <[email protected]>
TryBot-Result: Gopher Robot <[email protected]>
  • Loading branch information
rolandshoemaker committed Jan 31, 2022
1 parent 198e437 commit 30dcbda
Show file tree
Hide file tree
Showing 5 changed files with 18 additions and 16 deletions.
14 changes: 8 additions & 6 deletions acme/acme.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ type Client struct {

cacheMu sync.Mutex
dir *Directory // cached result of Client's Discover method
kid keyID // cached Account.URI obtained from registerRFC or getAccountRFC
// KID is the key identifier provided by the CA. If not provided it will be
// retrieved from the CA by making a call to the registration endpoint.
KID KeyID

noncesMu sync.Mutex
nonces map[string]struct{} // nonces collected from previous responses
Expand All @@ -140,21 +142,21 @@ type Client struct {
//
// When in pre-RFC mode or when c.getRegRFC responds with an error, accountKID
// returns noKeyID.
func (c *Client) accountKID(ctx context.Context) keyID {
func (c *Client) accountKID(ctx context.Context) KeyID {
c.cacheMu.Lock()
defer c.cacheMu.Unlock()
if !c.dir.rfcCompliant() {
return noKeyID
}
if c.kid != noKeyID {
return c.kid
if c.KID != noKeyID {
return c.KID
}
a, err := c.getRegRFC(ctx)
if err != nil {
return noKeyID
}
c.kid = keyID(a.URI)
return c.kid
c.KID = KeyID(a.URI)
return c.KID
}

// Discover performs ACME server discovery using c.DirectoryURL.
Expand Down
10 changes: 5 additions & 5 deletions acme/jws.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ import (
"math/big"
)

// keyID is the account identity provided by a CA during registration.
type keyID string
// KeyID is the account key identity provided by a CA during registration.
type KeyID string

// noKeyID indicates that jwsEncodeJSON should compute and use JWK instead of a KID.
// See jwsEncodeJSON for details.
const noKeyID = keyID("")
const noKeyID = KeyID("")

// noPayload indicates jwsEncodeJSON will encode zero-length octet string
// in a JWS request. This is called POST-as-GET in RFC 8555 and is used to make
Expand All @@ -43,14 +43,14 @@ type jsonWebSignature struct {

// jwsEncodeJSON signs claimset using provided key and a nonce.
// The result is serialized in JSON format containing either kid or jwk
// fields based on the provided keyID value.
// fields based on the provided KeyID value.
//
// If kid is non-empty, its quoted value is inserted in the protected head
// as "kid" field value. Otherwise, JWK is computed using jwkEncode and inserted
// as "jwk" field value. The "jwk" and "kid" fields are mutually exclusive.
//
// See https://tools.ietf.org/html/rfc7515#section-7.
func jwsEncodeJSON(claimset interface{}, key crypto.Signer, kid keyID, nonce, url string) ([]byte, error) {
func jwsEncodeJSON(claimset interface{}, key crypto.Signer, kid KeyID, nonce, url string) ([]byte, error) {
alg, sha := jwsHasher(key.Public())
if alg == "" || !sha.Available() {
return nil, ErrUnsupportedKey
Expand Down
2 changes: 1 addition & 1 deletion acme/jws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ func TestJWSEncodeJSON(t *testing.T) {
}

func TestJWSEncodeKID(t *testing.T) {
kid := keyID("https://example.org/account/1")
kid := KeyID("https://example.org/account/1")
claims := struct{ Msg string }{"Hello JWS"}
// JWS signed with testKeyEC
const (
Expand Down
2 changes: 1 addition & 1 deletion acme/rfc8555.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (c *Client) registerRFC(ctx context.Context, acct *Account, prompt func(tos
}
// Cache Account URL even if we return an error to the caller.
// It is by all means a valid and usable "kid" value for future requests.
c.kid = keyID(a.URI)
c.KID = KeyID(a.URI)
if res.StatusCode == http.StatusOK {
return nil, ErrAccountAlreadyExists
}
Expand Down
6 changes: 3 additions & 3 deletions acme/rfc8555_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ func TestRFC_Register(t *testing.T) {
if !didPrompt {
t.Error("tos prompt wasn't called")
}
if v := cl.accountKID(ctx); v != keyID(okAccount.URI) {
if v := cl.accountKID(ctx); v != KeyID(okAccount.URI) {
t.Errorf("account kid = %q; want %q", v, okAccount.URI)
}
}
Expand Down Expand Up @@ -482,7 +482,7 @@ func TestRFC_RegisterExternalAccountBinding(t *testing.T) {
if !didPrompt {
t.Error("tos prompt wasn't called")
}
if v := cl.accountKID(ctx); v != keyID(okAccount.URI) {
if v := cl.accountKID(ctx); v != KeyID(okAccount.URI) {
t.Errorf("account kid = %q; want %q", v, okAccount.URI)
}
}
Expand All @@ -502,7 +502,7 @@ func TestRFC_RegisterExisting(t *testing.T) {
if err != ErrAccountAlreadyExists {
t.Errorf("err = %v; want %v", err, ErrAccountAlreadyExists)
}
kid := keyID(s.url("/accounts/1"))
kid := KeyID(s.url("/accounts/1"))
if v := cl.accountKID(context.Background()); v != kid {
t.Errorf("account kid = %q; want %q", v, kid)
}
Expand Down

0 comments on commit 30dcbda

Please sign in to comment.