diff --git a/acme/api/account.go b/acme/api/account.go index 451655aaa..34c9301d8 100644 --- a/acme/api/account.go +++ b/acme/api/account.go @@ -36,7 +36,7 @@ func (a *AccountService) NewEAB(ctx context.Context, req acme.Account, kid, hmac return acme.ExtendedAccount{}, err } - eabJWS, err := a.core.jws().SignEAB(a.core.GetDirectory().NewAccountURL, kid, hmac) + eabJWS, err := a.core.signer().SignEAB(a.core.GetDirectory().NewAccountURL, kid, hmac) if err != nil { return acme.ExtendedAccount{}, fmt.Errorf("acme: error signing eab content: %w", err) } @@ -94,7 +94,7 @@ func (a *AccountService) Deactivate(ctx context.Context, accountURL string) erro func (a *AccountService) KeyChange(ctx context.Context, newKey crypto.Signer) error { uri := a.core.GetDirectory().KeyChangeURL - eabJWS, err := a.core.jws().SignKeyChange(uri, newKey) + eabJWS, err := a.core.signer().SignKeyChange(uri, newKey) if err != nil { return err } diff --git a/acme/api/api.go b/acme/api/api.go index 57c79e745..6d2a7f0b9 100644 --- a/acme/api/api.go +++ b/acme/api/api.go @@ -70,8 +70,8 @@ func New(httpClient *http.Client, userAgent, caDirURL, kid string, privateKey cr return c, nil } -func (a *Core) jws() *secure.JWS { - return secure.NewJWS(a.privateKey, a.kid, a.nonceManager) +func (a *Core) signer() *secure.Signer { + return secure.NewSigner(a.privateKey, a.kid) } // setKid Sets the key identifier (account URI). @@ -138,7 +138,7 @@ func (a *Core) retrievablePost(ctx context.Context, uri string, content []byte, } func (a *Core) signedPost(ctx context.Context, uri string, content []byte, response any) (*http.Response, error) { - signedContent, err := a.jws().SignContent(ctx, uri, content) + signedContent, err := a.signer().SignContent(a.nonceManager.NewNonceSource(ctx), uri, content) if err != nil { return nil, fmt.Errorf("failed to post JWS message: failed to sign content: %w", err) } @@ -158,7 +158,7 @@ func (a *Core) signedPost(ctx context.Context, uri string, content []byte, respo // GetKeyAuthorization Gets the key authorization. func (a *Core) GetKeyAuthorization(token string) (string, error) { - return a.jws().GetKeyAuthorization(token) + return a.signer().GetKeyAuthorization(token) } func (a *Core) GetDirectory() acme.Directory { diff --git a/acme/api/internal/secure/jws.go b/acme/api/internal/secure/signer.go similarity index 71% rename from acme/api/internal/secure/jws.go rename to acme/api/internal/secure/signer.go index 0160b1e72..be4804b8f 100644 --- a/acme/api/internal/secure/jws.go +++ b/acme/api/internal/secure/signer.go @@ -1,7 +1,6 @@ package secure import ( - "context" "crypto" "crypto/ecdsa" "crypto/elliptic" @@ -15,35 +14,32 @@ import ( "github.com/go-jose/go-jose/v4" ) -type nonceSourceCreator interface { - NewNonceSource(ctx context.Context) jose.NonceSource -} - -// JWS Represents a JWS. -type JWS struct { +// Signer Represents a Signer. +type Signer struct { privKey crypto.Signer kid string // Key identifier - nonces nonceSourceCreator } -// NewJWS Create a new JWS. -func NewJWS(privateKey crypto.Signer, kid string, nonceManager nonceSourceCreator) *JWS { - return &JWS{ +// NewSigner Create a new Signer. +func NewSigner(privateKey crypto.Signer, kid string) *Signer { + return &Signer{ privKey: privateKey, - nonces: nonceManager, kid: kid, } } -// SignContent Signs a content with the JWS. -func (j *JWS) SignContent(ctx context.Context, url string, content []byte) (*jose.JSONWebSignature, error) { +// SignContent Signs a content with the Signer. +func (j *Signer) SignContent(ns jose.NonceSource, url string, content []byte) (*jose.JSONWebSignature, error) { signKey := jose.SigningKey{ Algorithm: signatureAlgorithm(j.privKey), - Key: jose.JSONWebKey{Key: j.privKey, KeyID: j.kid}, + Key: jose.JSONWebKey{ + Key: j.privKey, + KeyID: j.kid, + }, } options := &jose.SignerOptions{ - NonceSource: j.nonces.NewNonceSource(ctx), + NonceSource: ns, ExtraHeaders: map[jose.HeaderKey]any{ "url": url, }, @@ -53,8 +49,8 @@ func (j *JWS) SignContent(ctx context.Context, url string, content []byte) (*jos return sign(content, signKey, options) } -// SignEAB Signs an external account binding with the JWS. -func (j *JWS) SignEAB(url, kid string, hmac []byte) (*jose.JSONWebSignature, error) { +// SignEAB Signs an external account binding with the Signer. +func (j *Signer) SignEAB(url, kid string, hmac []byte) (*jose.JSONWebSignature, error) { jwk := jose.JSONWebKey{Key: j.privKey} jwkJSON, err := jwk.Public().MarshalJSON() @@ -62,7 +58,10 @@ func (j *JWS) SignEAB(url, kid string, hmac []byte) (*jose.JSONWebSignature, err return nil, fmt.Errorf("acme: error encoding eab jwk key: %w", err) } - signKey := jose.SigningKey{Algorithm: jose.HS256, Key: hmac} + signKey := jose.SigningKey{ + Algorithm: jose.HS256, + Key: hmac, + } options := &jose.SignerOptions{ EmbedJWK: false, @@ -81,7 +80,7 @@ func (j *JWS) SignEAB(url, kid string, hmac []byte) (*jose.JSONWebSignature, err } // GetKeyAuthorization Gets the key authorization for a token. -func (j *JWS) GetKeyAuthorization(token string) (string, error) { +func (j *Signer) GetKeyAuthorization(token string) (string, error) { publicKey := j.privKey.Public() // Generate the Key Authorization for the challenge @@ -98,7 +97,7 @@ func (j *JWS) GetKeyAuthorization(token string) (string, error) { return token + "." + keyThumb, nil } -func (j *JWS) SignKeyChange(url string, newKey crypto.Signer) (*jose.JSONWebSignature, error) { +func (j *Signer) SignKeyChange(url string, newKey crypto.Signer) (*jose.JSONWebSignature, error) { if j.kid == "" { return nil, errors.New("missing kid") } @@ -115,7 +114,10 @@ func (j *JWS) SignKeyChange(url string, newKey crypto.Signer) (*jose.JSONWebSign OldKey: oldKeyJSON, } - signKey := jose.SigningKey{Algorithm: signatureAlgorithm(newKey), Key: newKey} + signKey := jose.SigningKey{ + Algorithm: signatureAlgorithm(newKey), + Key: newKey, + } options := &jose.SignerOptions{ EmbedJWK: true, diff --git a/acme/api/internal/secure/jws_test.go b/acme/api/internal/secure/signer_test.go similarity index 69% rename from acme/api/internal/secure/jws_test.go rename to acme/api/internal/secure/signer_test.go index 155a1fe91..fab23ed03 100644 --- a/acme/api/internal/secure/jws_test.go +++ b/acme/api/internal/secure/signer_test.go @@ -1,7 +1,6 @@ package secure import ( - "context" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" @@ -16,43 +15,37 @@ import ( "github.com/stretchr/testify/require" ) -type MockNonceManager struct{} - -func (f *MockNonceManager) NewNonceSource(ctx context.Context) jose.NonceSource { - return &MockNonceSource{} -} - type MockNonceSource struct{} func (b *MockNonceSource) Nonce() (string, error) { return "xxxNoncexxx", nil } -func TestJWS_SignContent(t *testing.T) { +func TestSigner_SignContent(t *testing.T) { privKey, err := rsa.GenerateKey(rand.Reader, 2048) require.NoError(t, err) - jws := NewJWS(privKey, "https://example.com", &MockNonceManager{}) + signer := NewSigner(privKey, "https://example.com") - content, err := jws.SignContent(t.Context(), "https://foo.example", []byte("{}")) + content, err := signer.SignContent(&MockNonceSource{}, "https://foo.example", []byte("{}")) require.NoError(t, err) check(t, content) } -func TestJWS_SignEAB(t *testing.T) { +func TestSigner_SignEAB(t *testing.T) { privKey, err := rsa.GenerateKey(rand.Reader, 2048) require.NoError(t, err) - jws := NewJWS(privKey, "https://example.com", &MockNonceManager{}) + signer := NewSigner(privKey, "https://example.com") - content, err := jws.SignEAB("https://foo.example/a", "https://foo.example/b", x509.MarshalPKCS1PrivateKey(privKey)) + content, err := signer.SignEAB("https://foo.example/a", "https://foo.example/b", x509.MarshalPKCS1PrivateKey(privKey)) require.NoError(t, err) check(t, content) } -func TestJWS_SignKeyChange(t *testing.T) { +func TestSigner_SignKeyChange(t *testing.T) { const ( kid = "https://example.com/acme/acct/evOfKhNU60wg" endpoint = "https://example.com/acme/key-change" @@ -61,12 +54,12 @@ func TestJWS_SignKeyChange(t *testing.T) { oldKey, err := rsa.GenerateKey(rand.Reader, 2048) require.NoError(t, err) - jws := NewJWS(oldKey, kid, &MockNonceManager{}) + signer := NewSigner(oldKey, kid) newKey, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader) require.NoError(t, err) - content, err := jws.SignKeyChange(endpoint, newKey) + content, err := signer.SignKeyChange(endpoint, newKey) require.NoError(t, err) check(t, content)