Skip to content

Commit a023926

Browse files
committed
Add jwx v3 support with backward compatibility
- Add NewJWSSignerV3() and NewJWSVerifierV3() functions using jwx v3 - Use recommended non-deprecated APIs: SignerFor() and VerifierFor() - Maintain full backward compatibility with existing v2 functions - Handle parameter order differences between v2 and v3 interfaces - Add comprehensive tests including cross-version compatibility tests - Add internal documentation for migration planning and research - All tests passing (v2, v3, and cross-compatibility) This is a non-breaking change. Existing code continues to work unchanged.
1 parent afa1d36 commit a023926

8 files changed

Lines changed: 1513 additions & 33 deletions

File tree

crypto.go

Lines changed: 105 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,14 @@ import (
1212
"crypto/sha512"
1313
"crypto/subtle"
1414
"fmt"
15+
16+
// JWX v2 - for backward compatibility (used by existing NewJWSSigner/NewJWSVerifier)
1517
"github.com/lestrrat-go/jwx/v2/jwa"
1618
"github.com/lestrrat-go/jwx/v2/jws"
19+
20+
// JWX v3 - for new V3 functions (used by NewJWSSignerV3/NewJWSVerifierV3)
21+
jwav3 "github.com/lestrrat-go/jwx/v3/jwa"
22+
jwsv3 "github.com/lestrrat-go/jwx/v3/jws"
1723
)
1824

1925
// Signer includes a cryptographic key (typically a private key) and configuration of what needs to be signed.
@@ -125,16 +131,21 @@ func NewEd25519SignerFromSeed(seed []byte, config *SignConfig, fields Fields) (*
125131
return NewEd25519Signer(key, config, fields)
126132
}
127133

128-
// NewJWSSigner creates a generic signer for JWS algorithms, using the go-jwx package. The particular key type for each algorithm
134+
// NewJWSSigner creates a generic signer for JWS algorithms, using the go-jwx v2 package. The particular key type for each algorithm
129135
// is documented in that package.
130136
// Config may be nil for a default configuration.
137+
//
138+
// Note: This function uses jwx v2. For jwx v3 support, use NewJWSSignerV3 instead.
131139
func NewJWSSigner(alg jwa.SignatureAlgorithm, key interface{}, config *SignConfig, fields Fields) (*Signer, error) {
132140
if key == nil {
133141
return nil, fmt.Errorf("key must not be nil")
134142
}
135143
if alg == jwa.NoSignature {
136144
return nil, fmt.Errorf("the NONE signing algorithm is expressly disallowed")
137145
}
146+
if config == nil {
147+
config = NewSignConfig()
148+
}
138149
jwsSigner, err := jws.NewSigner(alg)
139150
if err != nil {
140151
return nil, err
@@ -148,16 +159,52 @@ func NewJWSSigner(alg jwa.SignatureAlgorithm, key interface{}, config *SignConfi
148159
}, nil
149160
}
150161

162+
// NewJWSSignerV3 creates a generic signer for JWS algorithms, using the go-jwx v3 package. The particular key type for each algorithm
163+
// is documented in that package.
164+
// Config may be nil for a default configuration.
165+
//
166+
// This function uses jwx v3 and is the recommended choice for new code using jwx v3.
167+
// It uses the recommended SignerFor() API which returns Signer2 interface.
168+
func NewJWSSignerV3(alg jwav3.SignatureAlgorithm, key interface{}, config *SignConfig, fields Fields) (*Signer, error) {
169+
if key == nil {
170+
return nil, fmt.Errorf("key must not be nil")
171+
}
172+
if alg == jwav3.NoSignature() {
173+
return nil, fmt.Errorf("the NONE signing algorithm is expressly disallowed")
174+
}
175+
if config == nil {
176+
config = NewSignConfig()
177+
}
178+
jwsSigner, err := jwsv3.SignerFor(alg)
179+
if err != nil {
180+
return nil, err
181+
}
182+
return &Signer{
183+
key: key,
184+
alg: "",
185+
config: config,
186+
fields: fields,
187+
foreignSigner: jwsSigner,
188+
}, nil
189+
}
190+
151191
func (s Signer) sign(buff []byte) ([]byte, error) {
152192
if s.foreignSigner != nil {
153-
switch signer := s.foreignSigner.(type) {
154-
case jws.Signer:
155-
{
156-
return signer.Sign(buff, s.key)
157-
}
158-
default:
159-
return nil, fmt.Errorf("expected jws.Signer, got %T", s.foreignSigner)
193+
// Try v2 signer first (jws.Signer interface: Sign(payload, key))
194+
if signerV2, ok := s.foreignSigner.(jws.Signer); ok {
195+
return signerV2.Sign(buff, s.key)
196+
}
197+
198+
// Try v3 Signer2 interface (new recommended API: Sign(key, payload))
199+
// Note: parameter order is SWAPPED compared to v2!
200+
type Signer2 interface {
201+
Sign(key interface{}, payload []byte) ([]byte, error)
202+
}
203+
if signerV3, ok := s.foreignSigner.(Signer2); ok {
204+
return signerV3.Sign(s.key, buff) // Note: key first, payload second
160205
}
206+
207+
return nil, fmt.Errorf("expected jws.Signer or Signer2 interface, got %T", s.foreignSigner)
161208
}
162209
switch s.alg {
163210
case "hmac-sha256":
@@ -300,9 +347,11 @@ func NewEd25519Verifier(key ed25519.PublicKey, config *VerifyConfig, fields Fiel
300347
}, nil
301348
}
302349

303-
// NewJWSVerifier creates a generic verifier for JWS algorithms, using the go-jwx package. The particular key type for each algorithm
350+
// NewJWSVerifier creates a generic verifier for JWS algorithms, using the go-jwx v2 package. The particular key type for each algorithm
304351
// is documented in that package. Set config to nil for a default configuration.
305352
// Fields is the list of required headers and fields, which may be empty (but this is typically insecure).
353+
//
354+
// Note: This function uses jwx v2. For jwx v3 support, use NewJWSVerifierV3 instead.
306355
func NewJWSVerifier(alg jwa.SignatureAlgorithm, key interface{}, config *VerifyConfig, fields Fields) (*Verifier, error) {
307356
if key == nil {
308357
return nil, fmt.Errorf("key must not be nil")
@@ -326,18 +375,60 @@ func NewJWSVerifier(alg jwa.SignatureAlgorithm, key interface{}, config *VerifyC
326375
}, nil
327376
}
328377

378+
// NewJWSVerifierV3 creates a generic verifier for JWS algorithms, using the go-jwx v3 package. The particular key type for each algorithm
379+
// is documented in that package. Set config to nil for a default configuration.
380+
// Fields is the list of required headers and fields, which may be empty (but this is typically insecure).
381+
//
382+
// This function uses jwx v3 and is the recommended choice for new code using jwx v3.
383+
// It uses the recommended VerifierFor() API which returns Verifier2 interface.
384+
func NewJWSVerifierV3(alg jwav3.SignatureAlgorithm, key interface{}, config *VerifyConfig, fields Fields) (*Verifier, error) {
385+
if key == nil {
386+
return nil, fmt.Errorf("key must not be nil")
387+
}
388+
if config == nil {
389+
config = NewVerifyConfig()
390+
}
391+
if alg == jwav3.NoSignature() {
392+
return nil, fmt.Errorf("the NONE signing algorithm is expressly disallowed")
393+
}
394+
verifier, err := jwsv3.VerifierFor(alg)
395+
if err != nil {
396+
return nil, err
397+
}
398+
return &Verifier{
399+
key: key,
400+
alg: "",
401+
config: config,
402+
fields: fields,
403+
foreignVerifier: verifier,
404+
}, nil
405+
}
406+
329407
func (v Verifier) verify(buff []byte, sig []byte) (bool, error) {
330408
if v.foreignVerifier != nil {
331-
switch verifier := v.foreignVerifier.(type) {
332-
case jws.Verifier:
333-
err := verifier.Verify(buff, sig, v.key)
409+
// Try v2 verifier first (jws.Verifier interface: Verify(payload, sig, key))
410+
if verifierV2, ok := v.foreignVerifier.(jws.Verifier); ok {
411+
err := verifierV2.Verify(buff, sig, v.key)
334412
if err != nil {
335413
return false, err
336414
}
337415
return true, nil
338-
default:
339-
return false, fmt.Errorf("expected jws.Verifier, got %T", v.foreignVerifier)
340416
}
417+
418+
// Try v3 Verifier2 interface (new recommended API: Verify(key, payload, sig))
419+
// Note: parameter order is DIFFERENT compared to v2!
420+
type Verifier2 interface {
421+
Verify(key interface{}, payload, signature []byte) error
422+
}
423+
if verifierV3, ok := v.foreignVerifier.(Verifier2); ok {
424+
err := verifierV3.Verify(v.key, buff, sig) // Note: key first, then payload, then signature
425+
if err != nil {
426+
return false, err
427+
}
428+
return true, nil
429+
}
430+
431+
return false, fmt.Errorf("expected jws.Verifier or Verifier2 interface, got %T", v.foreignVerifier)
341432
}
342433

343434
switch v.alg {

0 commit comments

Comments
 (0)