1 package jwk
2
3 import (
4 "crypto"
5 "crypto/ecdsa"
6 "crypto/elliptic"
7 "fmt"
8 "math/big"
9
10 "github.com/lestrrat-go/blackmagic"
11 "github.com/lestrrat-go/jwx/internal/base64"
12 "github.com/lestrrat-go/jwx/internal/ecutil"
13 "github.com/lestrrat-go/jwx/jwa"
14 "github.com/pkg/errors"
15 )
16
17 func init() {
18 ecutil.RegisterCurve(elliptic.P256(), jwa.P256)
19 ecutil.RegisterCurve(elliptic.P384(), jwa.P384)
20 ecutil.RegisterCurve(elliptic.P521(), jwa.P521)
21 }
22
23 func (k *ecdsaPublicKey) FromRaw(rawKey *ecdsa.PublicKey) error {
24 k.mu.Lock()
25 defer k.mu.Unlock()
26
27 if rawKey.X == nil {
28 return errors.Errorf(`invalid ecdsa.PublicKey`)
29 }
30
31 if rawKey.Y == nil {
32 return errors.Errorf(`invalid ecdsa.PublicKey`)
33 }
34
35 xbuf := ecutil.AllocECPointBuffer(rawKey.X, rawKey.Curve)
36 ybuf := ecutil.AllocECPointBuffer(rawKey.Y, rawKey.Curve)
37 defer ecutil.ReleaseECPointBuffer(xbuf)
38 defer ecutil.ReleaseECPointBuffer(ybuf)
39
40 k.x = make([]byte, len(xbuf))
41 copy(k.x, xbuf)
42 k.y = make([]byte, len(ybuf))
43 copy(k.y, ybuf)
44
45 var crv jwa.EllipticCurveAlgorithm
46 if tmp, ok := ecutil.AlgorithmForCurve(rawKey.Curve); ok {
47 crv = tmp
48 } else {
49 return errors.Errorf(`invalid elliptic curve %s`, rawKey.Curve)
50 }
51 k.crv = &crv
52
53 return nil
54 }
55
56 func (k *ecdsaPrivateKey) FromRaw(rawKey *ecdsa.PrivateKey) error {
57 k.mu.Lock()
58 defer k.mu.Unlock()
59
60 if rawKey.PublicKey.X == nil {
61 return errors.Errorf(`invalid ecdsa.PrivateKey`)
62 }
63 if rawKey.PublicKey.Y == nil {
64 return errors.Errorf(`invalid ecdsa.PrivateKey`)
65 }
66 if rawKey.D == nil {
67 return errors.Errorf(`invalid ecdsa.PrivateKey`)
68 }
69
70 xbuf := ecutil.AllocECPointBuffer(rawKey.PublicKey.X, rawKey.Curve)
71 ybuf := ecutil.AllocECPointBuffer(rawKey.PublicKey.Y, rawKey.Curve)
72 dbuf := ecutil.AllocECPointBuffer(rawKey.D, rawKey.Curve)
73 defer ecutil.ReleaseECPointBuffer(xbuf)
74 defer ecutil.ReleaseECPointBuffer(ybuf)
75 defer ecutil.ReleaseECPointBuffer(dbuf)
76
77 k.x = make([]byte, len(xbuf))
78 copy(k.x, xbuf)
79 k.y = make([]byte, len(ybuf))
80 copy(k.y, ybuf)
81 k.d = make([]byte, len(dbuf))
82 copy(k.d, dbuf)
83
84 var crv jwa.EllipticCurveAlgorithm
85 if tmp, ok := ecutil.AlgorithmForCurve(rawKey.Curve); ok {
86 crv = tmp
87 } else {
88 return errors.Errorf(`invalid elliptic curve %s`, rawKey.Curve)
89 }
90 k.crv = &crv
91
92 return nil
93 }
94
95 func buildECDSAPublicKey(alg jwa.EllipticCurveAlgorithm, xbuf, ybuf []byte) (*ecdsa.PublicKey, error) {
96 var crv elliptic.Curve
97 if tmp, ok := ecutil.CurveForAlgorithm(alg); ok {
98 crv = tmp
99 } else {
100 return nil, errors.Errorf(`invalid curve algorithm %s`, alg)
101 }
102
103 var x, y big.Int
104 x.SetBytes(xbuf)
105 y.SetBytes(ybuf)
106
107 return &ecdsa.PublicKey{Curve: crv, X: &x, Y: &y}, nil
108 }
109
110
111 func (k *ecdsaPublicKey) Raw(v interface{}) error {
112 k.mu.RLock()
113 defer k.mu.RUnlock()
114
115 pubk, err := buildECDSAPublicKey(k.Crv(), k.x, k.y)
116 if err != nil {
117 return errors.Wrap(err, `failed to build public key`)
118 }
119
120 return blackmagic.AssignIfCompatible(v, pubk)
121 }
122
123 func (k *ecdsaPrivateKey) Raw(v interface{}) error {
124 k.mu.RLock()
125 defer k.mu.RUnlock()
126
127 pubk, err := buildECDSAPublicKey(k.Crv(), k.x, k.y)
128 if err != nil {
129 return errors.Wrap(err, `failed to build public key`)
130 }
131
132 var key ecdsa.PrivateKey
133 var d big.Int
134 d.SetBytes(k.d)
135 key.D = &d
136 key.PublicKey = *pubk
137
138 return blackmagic.AssignIfCompatible(v, &key)
139 }
140
141 func makeECDSAPublicKey(v interface {
142 makePairs() []*HeaderPair
143 }) (Key, error) {
144 newKey := NewECDSAPublicKey()
145
146
147 for _, pair := range v.makePairs() {
148 switch pair.Key {
149 case ECDSADKey:
150 continue
151 default:
152
153 key := pair.Key.(string)
154 if err := newKey.Set(key, pair.Value); err != nil {
155 return nil, errors.Wrapf(err, `failed to set field %q`, key)
156 }
157 }
158 }
159
160 return newKey, nil
161 }
162
163 func (k *ecdsaPrivateKey) PublicKey() (Key, error) {
164 return makeECDSAPublicKey(k)
165 }
166
167 func (k *ecdsaPublicKey) PublicKey() (Key, error) {
168 return makeECDSAPublicKey(k)
169 }
170
171 func ecdsaThumbprint(hash crypto.Hash, crv, x, y string) []byte {
172 h := hash.New()
173 fmt.Fprint(h, `{"crv":"`)
174 fmt.Fprint(h, crv)
175 fmt.Fprint(h, `","kty":"EC","x":"`)
176 fmt.Fprint(h, x)
177 fmt.Fprint(h, `","y":"`)
178 fmt.Fprint(h, y)
179 fmt.Fprint(h, `"}`)
180 return h.Sum(nil)
181 }
182
183
184
185 func (k ecdsaPublicKey) Thumbprint(hash crypto.Hash) ([]byte, error) {
186 k.mu.RLock()
187 defer k.mu.RUnlock()
188
189 var key ecdsa.PublicKey
190 if err := k.Raw(&key); err != nil {
191 return nil, errors.Wrap(err, `failed to materialize ecdsa.PublicKey for thumbprint generation`)
192 }
193
194 xbuf := ecutil.AllocECPointBuffer(key.X, key.Curve)
195 ybuf := ecutil.AllocECPointBuffer(key.Y, key.Curve)
196 defer ecutil.ReleaseECPointBuffer(xbuf)
197 defer ecutil.ReleaseECPointBuffer(ybuf)
198
199 return ecdsaThumbprint(
200 hash,
201 key.Curve.Params().Name,
202 base64.EncodeToString(xbuf),
203 base64.EncodeToString(ybuf),
204 ), nil
205 }
206
207
208
209 func (k ecdsaPrivateKey) Thumbprint(hash crypto.Hash) ([]byte, error) {
210 k.mu.RLock()
211 defer k.mu.RUnlock()
212
213 var key ecdsa.PrivateKey
214 if err := k.Raw(&key); err != nil {
215 return nil, errors.Wrap(err, `failed to materialize ecdsa.PrivateKey for thumbprint generation`)
216 }
217
218 xbuf := ecutil.AllocECPointBuffer(key.X, key.Curve)
219 ybuf := ecutil.AllocECPointBuffer(key.Y, key.Curve)
220 defer ecutil.ReleaseECPointBuffer(xbuf)
221 defer ecutil.ReleaseECPointBuffer(ybuf)
222
223 return ecdsaThumbprint(
224 hash,
225 key.Curve.Params().Name,
226 base64.EncodeToString(xbuf),
227 base64.EncodeToString(ybuf),
228 ), nil
229 }
230
View as plain text