1 package jws
2
3 import (
4 "crypto"
5 "crypto/ecdsa"
6 "crypto/rand"
7 "encoding/asn1"
8 "fmt"
9 "math/big"
10
11 "github.com/lestrrat-go/jwx/internal/keyconv"
12 "github.com/lestrrat-go/jwx/internal/pool"
13 "github.com/lestrrat-go/jwx/jwa"
14 "github.com/pkg/errors"
15 )
16
17 var ecdsaSigners map[jwa.SignatureAlgorithm]*ecdsaSigner
18 var ecdsaVerifiers map[jwa.SignatureAlgorithm]*ecdsaVerifier
19
20 func init() {
21 algs := map[jwa.SignatureAlgorithm]crypto.Hash{
22 jwa.ES256: crypto.SHA256,
23 jwa.ES384: crypto.SHA384,
24 jwa.ES512: crypto.SHA512,
25 jwa.ES256K: crypto.SHA256,
26 }
27 ecdsaSigners = make(map[jwa.SignatureAlgorithm]*ecdsaSigner)
28 ecdsaVerifiers = make(map[jwa.SignatureAlgorithm]*ecdsaVerifier)
29
30 for alg, hash := range algs {
31 ecdsaSigners[alg] = &ecdsaSigner{
32 alg: alg,
33 hash: hash,
34 }
35 ecdsaVerifiers[alg] = &ecdsaVerifier{
36 alg: alg,
37 hash: hash,
38 }
39 }
40 }
41
42 func newECDSASigner(alg jwa.SignatureAlgorithm) Signer {
43 return ecdsaSigners[alg]
44 }
45
46
47 type ecdsaSigner struct {
48 alg jwa.SignatureAlgorithm
49 hash crypto.Hash
50 }
51
52 func (es ecdsaSigner) Algorithm() jwa.SignatureAlgorithm {
53 return es.alg
54 }
55
56 func (es *ecdsaSigner) Sign(payload []byte, key interface{}) ([]byte, error) {
57 if key == nil {
58 return nil, errors.New(`missing private key while signing payload`)
59 }
60
61 h := es.hash.New()
62 if _, err := h.Write(payload); err != nil {
63 return nil, errors.Wrap(err, "failed to write payload using ecdsa")
64 }
65
66 signer, ok := key.(crypto.Signer)
67 if ok {
68 switch key.(type) {
69 case ecdsa.PrivateKey, *ecdsa.PrivateKey:
70
71
72 ok = false
73 }
74 }
75
76 var r, s *big.Int
77 var curveBits int
78 if ok {
79 signed, err := signer.Sign(rand.Reader, h.Sum(nil), es.hash)
80 if err != nil {
81 return nil, err
82 }
83
84 var p struct {
85 R *big.Int
86 S *big.Int
87 }
88 if _, err := asn1.Unmarshal(signed, &p); err != nil {
89 return nil, errors.Wrap(err, `failed to unmarshal ASN1 encoded signature`)
90 }
91
92
93
94
95
96
97
98
99 cpub := signer.Public()
100 pubkey, ok := cpub.(*ecdsa.PublicKey)
101 if !ok {
102 return nil, fmt.Errorf(`expected *ecdsa.PublicKey, got %T`, pubkey)
103 }
104 curveBits = pubkey.Curve.Params().BitSize
105
106 r = p.R
107 s = p.S
108 } else {
109 var privkey ecdsa.PrivateKey
110 if err := keyconv.ECDSAPrivateKey(&privkey, key); err != nil {
111 return nil, errors.Wrapf(err, `failed to retrieve ecdsa.PrivateKey out of %T`, key)
112 }
113 curveBits = privkey.Curve.Params().BitSize
114 rtmp, stmp, err := ecdsa.Sign(rand.Reader, &privkey, h.Sum(nil))
115 if err != nil {
116 return nil, errors.Wrap(err, "failed to sign payload using ecdsa")
117 }
118 r = rtmp
119 s = stmp
120 }
121
122 keyBytes := curveBits / 8
123
124 if curveBits%8 > 0 {
125 keyBytes++
126 }
127
128 rBytes := r.Bytes()
129 rBytesPadded := make([]byte, keyBytes)
130 copy(rBytesPadded[keyBytes-len(rBytes):], rBytes)
131
132 sBytes := s.Bytes()
133 sBytesPadded := make([]byte, keyBytes)
134 copy(sBytesPadded[keyBytes-len(sBytes):], sBytes)
135
136 out := append(rBytesPadded, sBytesPadded...)
137 return out, nil
138 }
139
140
141 type ecdsaVerifier struct {
142 alg jwa.SignatureAlgorithm
143 hash crypto.Hash
144 }
145
146 func newECDSAVerifier(alg jwa.SignatureAlgorithm) Verifier {
147 return ecdsaVerifiers[alg]
148 }
149
150 func (v ecdsaVerifier) Algorithm() jwa.SignatureAlgorithm {
151 return v.alg
152 }
153
154 func (v *ecdsaVerifier) Verify(payload []byte, signature []byte, key interface{}) error {
155 if key == nil {
156 return errors.New(`missing public key while verifying payload`)
157 }
158
159 var pubkey ecdsa.PublicKey
160 if cs, ok := key.(crypto.Signer); ok {
161 cpub := cs.Public()
162 switch cpub := cpub.(type) {
163 case ecdsa.PublicKey:
164 pubkey = cpub
165 case *ecdsa.PublicKey:
166 pubkey = *cpub
167 default:
168 return errors.Errorf(`failed to retrieve ecdsa.PublicKey out of crypto.Signer %T`, key)
169 }
170 } else {
171 if err := keyconv.ECDSAPublicKey(&pubkey, key); err != nil {
172 return errors.Wrapf(err, `failed to retrieve ecdsa.PublicKey out of %T`, key)
173 }
174 }
175
176 r := pool.GetBigInt()
177 s := pool.GetBigInt()
178 defer pool.ReleaseBigInt(r)
179 defer pool.ReleaseBigInt(s)
180
181 n := len(signature) / 2
182 r.SetBytes(signature[:n])
183 s.SetBytes(signature[n:])
184
185 h := v.hash.New()
186 if _, err := h.Write(payload); err != nil {
187 return errors.Wrap(err, "failed to write payload using ecdsa")
188 }
189
190 if !ecdsa.Verify(&pubkey, h.Sum(nil), r, s) {
191 return errors.New(`failed to verify signature using ecdsa`)
192 }
193 return nil
194 }
195
View as plain text