Skip to content

Commit b357385

Browse files
authored
Moving DecodeSegement to Parser (#278)
* Moving `DecodeSegement` to `Parser` This would allow us to remove some global variables and move them to parser options as well as potentially introduce interfaces for json and b64 encoding/decoding to replace the std lib, if someone wanted to do that for performance reasons. We keep the functions exported because of explicit user demand. * Sign/Verify does take the decoded form now
1 parent c6ec5a2 commit b357385

19 files changed

+212
-196
lines changed

ecdsa.go

+7-15
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,7 @@ func (m *SigningMethodECDSA) Alg() string {
5555

5656
// Verify implements token verification for the SigningMethod.
5757
// For this verify method, key must be an ecdsa.PublicKey struct
58-
func (m *SigningMethodECDSA) Verify(signingString, signature string, key interface{}) error {
59-
var err error
60-
61-
// Decode the signature
62-
var sig []byte
63-
if sig, err = DecodeSegment(signature); err != nil {
64-
return err
65-
}
66-
58+
func (m *SigningMethodECDSA) Verify(signingString string, sig []byte, key interface{}) error {
6759
// Get the key
6860
var ecdsaKey *ecdsa.PublicKey
6961
switch k := key.(type) {
@@ -97,19 +89,19 @@ func (m *SigningMethodECDSA) Verify(signingString, signature string, key interfa
9789

9890
// Sign implements token signing for the SigningMethod.
9991
// For this signing method, key must be an ecdsa.PrivateKey struct
100-
func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string, error) {
92+
func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) ([]byte, error) {
10193
// Get the key
10294
var ecdsaKey *ecdsa.PrivateKey
10395
switch k := key.(type) {
10496
case *ecdsa.PrivateKey:
10597
ecdsaKey = k
10698
default:
107-
return "", ErrInvalidKeyType
99+
return nil, ErrInvalidKeyType
108100
}
109101

110102
// Create the hasher
111103
if !m.Hash.Available() {
112-
return "", ErrHashUnavailable
104+
return nil, ErrHashUnavailable
113105
}
114106

115107
hasher := m.Hash.New()
@@ -120,7 +112,7 @@ func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string
120112
curveBits := ecdsaKey.Curve.Params().BitSize
121113

122114
if m.CurveBits != curveBits {
123-
return "", ErrInvalidKey
115+
return nil, ErrInvalidKey
124116
}
125117

126118
keyBytes := curveBits / 8
@@ -135,8 +127,8 @@ func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string
135127
r.FillBytes(out[0:keyBytes]) // r is assigned to the first half of output.
136128
s.FillBytes(out[keyBytes:]) // s is assigned to the second half of output.
137129

138-
return EncodeSegment(out), nil
130+
return out, nil
139131
} else {
140-
return "", err
132+
return nil, err
141133
}
142134
}

ecdsa_test.go

+21-5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package jwt_test
33
import (
44
"crypto/ecdsa"
55
"os"
6+
"reflect"
67
"strings"
78
"testing"
89

@@ -65,7 +66,7 @@ func TestECDSAVerify(t *testing.T) {
6566
parts := strings.Split(data.tokenString, ".")
6667

6768
method := jwt.GetSigningMethod(data.alg)
68-
err = method.Verify(strings.Join(parts[0:2], "."), parts[2], ecdsaKey)
69+
err = method.Verify(strings.Join(parts[0:2], "."), decodeSegment(t, parts[2]), ecdsaKey)
6970
if data.valid && err != nil {
7071
t.Errorf("[%v] Error while verifying key: %v", data.name, err)
7172
}
@@ -90,12 +91,13 @@ func TestECDSASign(t *testing.T) {
9091
toSign := strings.Join(parts[0:2], ".")
9192
method := jwt.GetSigningMethod(data.alg)
9293
sig, err := method.Sign(toSign, ecdsaKey)
93-
9494
if err != nil {
9595
t.Errorf("[%v] Error signing token: %v", data.name, err)
9696
}
97-
if sig == parts[2] {
98-
t.Errorf("[%v] Identical signatures\nbefore:\n%v\nafter:\n%v", data.name, parts[2], sig)
97+
98+
ssig := encodeSegment(sig)
99+
if ssig == parts[2] {
100+
t.Errorf("[%v] Identical signatures\nbefore:\n%v\nafter:\n%v", data.name, parts[2], ssig)
99101
}
100102

101103
err = method.Verify(toSign, sig, ecdsaKey.Public())
@@ -155,10 +157,24 @@ func BenchmarkECDSASigning(b *testing.B) {
155157
if err != nil {
156158
b.Fatalf("[%v] Error signing token: %v", data.name, err)
157159
}
158-
if sig == parts[2] {
160+
if reflect.DeepEqual(sig, decodeSegment(b, parts[2])) {
159161
b.Fatalf("[%v] Identical signatures\nbefore:\n%v\nafter:\n%v", data.name, parts[2], sig)
160162
}
161163
}
162164
})
163165
}
164166
}
167+
168+
func decodeSegment(t interface{ Fatalf(string, ...any) }, signature string) (sig []byte) {
169+
var err error
170+
sig, err = jwt.NewParser().DecodeSegment(signature)
171+
if err != nil {
172+
t.Fatalf("could not decode segment: %v", err)
173+
}
174+
175+
return
176+
}
177+
178+
func encodeSegment(sig []byte) string {
179+
return (&jwt.Token{}).EncodeSegment(sig)
180+
}

ed25519.go

+10-15
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ func (m *SigningMethodEd25519) Alg() string {
3434

3535
// Verify implements token verification for the SigningMethod.
3636
// For this verify method, key must be an ed25519.PublicKey
37-
func (m *SigningMethodEd25519) Verify(signingString, signature string, key interface{}) error {
38-
var err error
37+
func (m *SigningMethodEd25519) Verify(signingString string, sig []byte, key interface{}) error {
3938
var ed25519Key ed25519.PublicKey
4039
var ok bool
4140

@@ -47,12 +46,6 @@ func (m *SigningMethodEd25519) Verify(signingString, signature string, key inter
4746
return ErrInvalidKey
4847
}
4948

50-
// Decode the signature
51-
var sig []byte
52-
if sig, err = DecodeSegment(signature); err != nil {
53-
return err
54-
}
55-
5649
// Verify the signature
5750
if !ed25519.Verify(ed25519Key, []byte(signingString), sig) {
5851
return ErrEd25519Verification
@@ -63,23 +56,25 @@ func (m *SigningMethodEd25519) Verify(signingString, signature string, key inter
6356

6457
// Sign implements token signing for the SigningMethod.
6558
// For this signing method, key must be an ed25519.PrivateKey
66-
func (m *SigningMethodEd25519) Sign(signingString string, key interface{}) (string, error) {
59+
func (m *SigningMethodEd25519) Sign(signingString string, key interface{}) ([]byte, error) {
6760
var ed25519Key crypto.Signer
6861
var ok bool
6962

7063
if ed25519Key, ok = key.(crypto.Signer); !ok {
71-
return "", ErrInvalidKeyType
64+
return nil, ErrInvalidKeyType
7265
}
7366

7467
if _, ok := ed25519Key.Public().(ed25519.PublicKey); !ok {
75-
return "", ErrInvalidKey
68+
return nil, ErrInvalidKey
7669
}
7770

78-
// Sign the string and return the encoded result
79-
// ed25519 performs a two-pass hash as part of its algorithm. Therefore, we need to pass a non-prehashed message into the Sign function, as indicated by crypto.Hash(0)
71+
// Sign the string and return the result. ed25519 performs a two-pass hash
72+
// as part of its algorithm. Therefore, we need to pass a non-prehashed
73+
// message into the Sign function, as indicated by crypto.Hash(0)
8074
sig, err := ed25519Key.Sign(rand.Reader, []byte(signingString), crypto.Hash(0))
8175
if err != nil {
82-
return "", err
76+
return nil, err
8377
}
84-
return EncodeSegment(sig), nil
78+
79+
return sig, nil
8580
}

ed25519_test.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func TestEd25519Verify(t *testing.T) {
4949

5050
method := jwt.GetSigningMethod(data.alg)
5151

52-
err = method.Verify(strings.Join(parts[0:2], "."), parts[2], ed25519Key)
52+
err = method.Verify(strings.Join(parts[0:2], "."), decodeSegment(t, parts[2]), ed25519Key)
5353
if data.valid && err != nil {
5454
t.Errorf("[%v] Error while verifying key: %v", data.name, err)
5555
}
@@ -77,8 +77,10 @@ func TestEd25519Sign(t *testing.T) {
7777
if err != nil {
7878
t.Errorf("[%v] Error signing token: %v", data.name, err)
7979
}
80-
if sig == parts[2] && !data.valid {
81-
t.Errorf("[%v] Identical signatures\nbefore:\n%v\nafter:\n%v", data.name, parts[2], sig)
80+
81+
ssig := encodeSegment(sig)
82+
if ssig == parts[2] && !data.valid {
83+
t.Errorf("[%v] Identical signatures\nbefore:\n%v\nafter:\n%v", data.name, parts[2], ssig)
8284
}
8385
}
8486
}

hmac.go

+5-11
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,13 @@ func (m *SigningMethodHMAC) Alg() string {
4646
}
4747

4848
// Verify implements token verification for the SigningMethod. Returns nil if the signature is valid.
49-
func (m *SigningMethodHMAC) Verify(signingString, signature string, key interface{}) error {
49+
func (m *SigningMethodHMAC) Verify(signingString string, sig []byte, key interface{}) error {
5050
// Verify the key is the right type
5151
keyBytes, ok := key.([]byte)
5252
if !ok {
5353
return ErrInvalidKeyType
5454
}
5555

56-
// Decode signature, for comparison
57-
sig, err := DecodeSegment(signature)
58-
if err != nil {
59-
return err
60-
}
61-
6256
// Can we use the specified hashing method?
6357
if !m.Hash.Available() {
6458
return ErrHashUnavailable
@@ -79,17 +73,17 @@ func (m *SigningMethodHMAC) Verify(signingString, signature string, key interfac
7973

8074
// Sign implements token signing for the SigningMethod.
8175
// Key must be []byte
82-
func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) (string, error) {
76+
func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) ([]byte, error) {
8377
if keyBytes, ok := key.([]byte); ok {
8478
if !m.Hash.Available() {
85-
return "", ErrHashUnavailable
79+
return nil, ErrHashUnavailable
8680
}
8781

8882
hasher := hmac.New(m.Hash.New, keyBytes)
8983
hasher.Write([]byte(signingString))
9084

91-
return EncodeSegment(hasher.Sum(nil)), nil
85+
return hasher.Sum(nil), nil
9286
}
9387

94-
return "", ErrInvalidKeyType
88+
return nil, ErrInvalidKeyType
9589
}

hmac_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package jwt_test
22

33
import (
44
"os"
5+
"reflect"
56
"strings"
67
"testing"
78

@@ -53,7 +54,7 @@ func TestHMACVerify(t *testing.T) {
5354
parts := strings.Split(data.tokenString, ".")
5455

5556
method := jwt.GetSigningMethod(data.alg)
56-
err := method.Verify(strings.Join(parts[0:2], "."), parts[2], hmacTestKey)
57+
err := method.Verify(strings.Join(parts[0:2], "."), decodeSegment(t, parts[2]), hmacTestKey)
5758
if data.valid && err != nil {
5859
t.Errorf("[%v] Error while verifying key: %v", data.name, err)
5960
}
@@ -72,7 +73,7 @@ func TestHMACSign(t *testing.T) {
7273
if err != nil {
7374
t.Errorf("[%v] Error signing token: %v", data.name, err)
7475
}
75-
if sig != parts[2] {
76+
if !reflect.DeepEqual(sig, decodeSegment(t, parts[2])) {
7677
t.Errorf("[%v] Incorrect signature.\nwas:\n%v\nexpecting:\n%v", data.name, sig, parts[2])
7778
}
7879
}

none.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ func (m *signingMethodNone) Alg() string {
2525
}
2626

2727
// Only allow 'none' alg type if UnsafeAllowNoneSignatureType is specified as the key
28-
func (m *signingMethodNone) Verify(signingString, signature string, key interface{}) (err error) {
28+
func (m *signingMethodNone) Verify(signingString string, sig []byte, key interface{}) (err error) {
2929
// Key must be UnsafeAllowNoneSignatureType to prevent accidentally
3030
// accepting 'none' signing method
3131
if _, ok := key.(unsafeNoneMagicConstant); !ok {
3232
return NoneSignatureTypeDisallowedError
3333
}
3434
// If signing method is none, signature must be an empty string
35-
if signature != "" {
35+
if string(sig) != "" {
3636
return newError("'none' signing method with non-empty signature", ErrTokenUnverifiable)
3737
}
3838

@@ -41,9 +41,10 @@ func (m *signingMethodNone) Verify(signingString, signature string, key interfac
4141
}
4242

4343
// Only allow 'none' signing if UnsafeAllowNoneSignatureType is specified as the key
44-
func (m *signingMethodNone) Sign(signingString string, key interface{}) (string, error) {
44+
func (m *signingMethodNone) Sign(signingString string, key interface{}) ([]byte, error) {
4545
if _, ok := key.(unsafeNoneMagicConstant); ok {
46-
return "", nil
46+
return []byte{}, nil
4747
}
48-
return "", NoneSignatureTypeDisallowedError
48+
49+
return nil, NoneSignatureTypeDisallowedError
4950
}

none_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package jwt_test
22

33
import (
4+
"reflect"
45
"strings"
56
"testing"
67

@@ -46,7 +47,7 @@ func TestNoneVerify(t *testing.T) {
4647
parts := strings.Split(data.tokenString, ".")
4748

4849
method := jwt.GetSigningMethod(data.alg)
49-
err := method.Verify(strings.Join(parts[0:2], "."), parts[2], data.key)
50+
err := method.Verify(strings.Join(parts[0:2], "."), decodeSegment(t, parts[2]), data.key)
5051
if data.valid && err != nil {
5152
t.Errorf("[%v] Error while verifying key: %v", data.name, err)
5253
}
@@ -65,7 +66,7 @@ func TestNoneSign(t *testing.T) {
6566
if err != nil {
6667
t.Errorf("[%v] Error signing token: %v", data.name, err)
6768
}
68-
if sig != parts[2] {
69+
if !reflect.DeepEqual(sig, decodeSegment(t, parts[2])) {
6970
t.Errorf("[%v] Incorrect signature.\nwas:\n%v\nexpecting:\n%v", data.name, sig, parts[2])
7071
}
7172
}

0 commit comments

Comments
 (0)