1/*-
2 * Copyright 2014 Square Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package jose
18
19import (
20	"crypto"
21	"crypto/ecdsa"
22	"crypto/elliptic"
23	"crypto/rsa"
24	"crypto/x509"
25	"encoding/base64"
26	"errors"
27	"fmt"
28	"math/big"
29	"reflect"
30	"strings"
31
32	"golang.org/x/crypto/ed25519"
33
34	"gopkg.in/square/go-jose.v2/json"
35)
36
37// rawJSONWebKey represents a public or private key in JWK format, used for parsing/serializing.
38type rawJSONWebKey struct {
39	Use string      `json:"use,omitempty"`
40	Kty string      `json:"kty,omitempty"`
41	Kid string      `json:"kid,omitempty"`
42	Crv string      `json:"crv,omitempty"`
43	Alg string      `json:"alg,omitempty"`
44	K   *byteBuffer `json:"k,omitempty"`
45	X   *byteBuffer `json:"x,omitempty"`
46	Y   *byteBuffer `json:"y,omitempty"`
47	N   *byteBuffer `json:"n,omitempty"`
48	E   *byteBuffer `json:"e,omitempty"`
49	// -- Following fields are only used for private keys --
50	// RSA uses D, P and Q, while ECDSA uses only D. Fields Dp, Dq, and Qi are
51	// completely optional. Therefore for RSA/ECDSA, D != nil is a contract that
52	// we have a private key whereas D == nil means we have only a public key.
53	D  *byteBuffer `json:"d,omitempty"`
54	P  *byteBuffer `json:"p,omitempty"`
55	Q  *byteBuffer `json:"q,omitempty"`
56	Dp *byteBuffer `json:"dp,omitempty"`
57	Dq *byteBuffer `json:"dq,omitempty"`
58	Qi *byteBuffer `json:"qi,omitempty"`
59	// Certificates
60	X5c []string `json:"x5c,omitempty"`
61}
62
63// JSONWebKey represents a public or private key in JWK format.
64type JSONWebKey struct {
65	Key          interface{}
66	Certificates []*x509.Certificate
67	KeyID        string
68	Algorithm    string
69	Use          string
70}
71
72// MarshalJSON serializes the given key to its JSON representation.
73func (k JSONWebKey) MarshalJSON() ([]byte, error) {
74	var raw *rawJSONWebKey
75	var err error
76
77	switch key := k.Key.(type) {
78	case ed25519.PublicKey:
79		raw = fromEdPublicKey(key)
80	case *ecdsa.PublicKey:
81		raw, err = fromEcPublicKey(key)
82	case *rsa.PublicKey:
83		raw = fromRsaPublicKey(key)
84	case ed25519.PrivateKey:
85		raw, err = fromEdPrivateKey(key)
86	case *ecdsa.PrivateKey:
87		raw, err = fromEcPrivateKey(key)
88	case *rsa.PrivateKey:
89		raw, err = fromRsaPrivateKey(key)
90	case []byte:
91		raw, err = fromSymmetricKey(key)
92	default:
93		return nil, fmt.Errorf("square/go-jose: unknown key type '%s'", reflect.TypeOf(key))
94	}
95
96	if err != nil {
97		return nil, err
98	}
99
100	raw.Kid = k.KeyID
101	raw.Alg = k.Algorithm
102	raw.Use = k.Use
103
104	for _, cert := range k.Certificates {
105		raw.X5c = append(raw.X5c, base64.StdEncoding.EncodeToString(cert.Raw))
106	}
107
108	return json.Marshal(raw)
109}
110
111// UnmarshalJSON reads a key from its JSON representation.
112func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
113	var raw rawJSONWebKey
114	err = json.Unmarshal(data, &raw)
115	if err != nil {
116		return err
117	}
118
119	var key interface{}
120	switch raw.Kty {
121	case "EC":
122		if raw.D != nil {
123			key, err = raw.ecPrivateKey()
124		} else {
125			key, err = raw.ecPublicKey()
126		}
127	case "RSA":
128		if raw.D != nil {
129			key, err = raw.rsaPrivateKey()
130		} else {
131			key, err = raw.rsaPublicKey()
132		}
133	case "oct":
134		key, err = raw.symmetricKey()
135	case "OKP":
136		if raw.Crv == "Ed25519" && raw.X != nil {
137			if raw.D != nil {
138				key, err = raw.edPrivateKey()
139			} else {
140				key, err = raw.edPublicKey()
141			}
142		} else {
143			err = fmt.Errorf("square/go-jose: unknown curve %s'", raw.Crv)
144		}
145	default:
146		err = fmt.Errorf("square/go-jose: unknown json web key type '%s'", raw.Kty)
147	}
148
149	if err == nil {
150		*k = JSONWebKey{Key: key, KeyID: raw.Kid, Algorithm: raw.Alg, Use: raw.Use}
151
152		k.Certificates, err = parseCertificateChain(raw.X5c)
153		if err != nil {
154			return fmt.Errorf("failed to unmarshal x5c field: %s", err)
155		}
156	}
157
158	return
159}
160
161// JSONWebKeySet represents a JWK Set object.
162type JSONWebKeySet struct {
163	Keys []JSONWebKey `json:"keys"`
164}
165
166// Key convenience method returns keys by key ID. Specification states
167// that a JWK Set "SHOULD" use distinct key IDs, but allows for some
168// cases where they are not distinct. Hence method returns a slice
169// of JSONWebKeys.
170func (s *JSONWebKeySet) Key(kid string) []JSONWebKey {
171	var keys []JSONWebKey
172	for _, key := range s.Keys {
173		if key.KeyID == kid {
174			keys = append(keys, key)
175		}
176	}
177
178	return keys
179}
180
181const rsaThumbprintTemplate = `{"e":"%s","kty":"RSA","n":"%s"}`
182const ecThumbprintTemplate = `{"crv":"%s","kty":"EC","x":"%s","y":"%s"}`
183const edThumbprintTemplate = `{"crv":"%s","kty":"OKP",x":"%s"}`
184
185func ecThumbprintInput(curve elliptic.Curve, x, y *big.Int) (string, error) {
186	coordLength := curveSize(curve)
187	crv, err := curveName(curve)
188	if err != nil {
189		return "", err
190	}
191
192	if len(x.Bytes()) > coordLength || len(y.Bytes()) > coordLength {
193		return "", errors.New("square/go-jose: invalid elliptic key (too large)")
194	}
195
196	return fmt.Sprintf(ecThumbprintTemplate, crv,
197		newFixedSizeBuffer(x.Bytes(), coordLength).base64(),
198		newFixedSizeBuffer(y.Bytes(), coordLength).base64()), nil
199}
200
201func rsaThumbprintInput(n *big.Int, e int) (string, error) {
202	return fmt.Sprintf(rsaThumbprintTemplate,
203		newBufferFromInt(uint64(e)).base64(),
204		newBuffer(n.Bytes()).base64()), nil
205}
206
207func edThumbprintInput(ed ed25519.PublicKey) (string, error) {
208	crv := "Ed25519"
209	if len(ed) > 32 {
210		return "", errors.New("square/go-jose: invalid elliptic key (too large)")
211	}
212	return fmt.Sprintf(edThumbprintTemplate, crv,
213		newFixedSizeBuffer(ed, 32).base64()), nil
214}
215
216// Thumbprint computes the JWK Thumbprint of a key using the
217// indicated hash algorithm.
218func (k *JSONWebKey) Thumbprint(hash crypto.Hash) ([]byte, error) {
219	var input string
220	var err error
221	switch key := k.Key.(type) {
222	case ed25519.PublicKey:
223		input, err = edThumbprintInput(key)
224	case *ecdsa.PublicKey:
225		input, err = ecThumbprintInput(key.Curve, key.X, key.Y)
226	case *ecdsa.PrivateKey:
227		input, err = ecThumbprintInput(key.Curve, key.X, key.Y)
228	case *rsa.PublicKey:
229		input, err = rsaThumbprintInput(key.N, key.E)
230	case *rsa.PrivateKey:
231		input, err = rsaThumbprintInput(key.N, key.E)
232	case ed25519.PrivateKey:
233		input, err = edThumbprintInput(ed25519.PublicKey(key[32:]))
234	default:
235		return nil, fmt.Errorf("square/go-jose: unknown key type '%s'", reflect.TypeOf(key))
236	}
237
238	if err != nil {
239		return nil, err
240	}
241
242	h := hash.New()
243	h.Write([]byte(input))
244	return h.Sum(nil), nil
245}
246
247// IsPublic returns true if the JWK represents a public key (not symmetric, not private).
248func (k *JSONWebKey) IsPublic() bool {
249	switch k.Key.(type) {
250	case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
251		return true
252	default:
253		return false
254	}
255}
256
257// Public creates JSONWebKey with corresponding publik key if JWK represents asymmetric private key.
258func (k *JSONWebKey) Public() JSONWebKey {
259	if k.IsPublic() {
260		return *k
261	}
262	ret := *k
263	switch key := k.Key.(type) {
264	case *ecdsa.PrivateKey:
265		ret.Key = key.Public()
266	case *rsa.PrivateKey:
267		ret.Key = key.Public()
268	case ed25519.PrivateKey:
269		ret.Key = key.Public()
270	default:
271		return JSONWebKey{} // returning invalid key
272	}
273	return ret
274}
275
276// Valid checks that the key contains the expected parameters.
277func (k *JSONWebKey) Valid() bool {
278	if k.Key == nil {
279		return false
280	}
281	switch key := k.Key.(type) {
282	case *ecdsa.PublicKey:
283		if key.Curve == nil || key.X == nil || key.Y == nil {
284			return false
285		}
286	case *ecdsa.PrivateKey:
287		if key.Curve == nil || key.X == nil || key.Y == nil || key.D == nil {
288			return false
289		}
290	case *rsa.PublicKey:
291		if key.N == nil || key.E == 0 {
292			return false
293		}
294	case *rsa.PrivateKey:
295		if key.N == nil || key.E == 0 || key.D == nil || len(key.Primes) < 2 {
296			return false
297		}
298	case ed25519.PublicKey:
299		if len(key) != 32 {
300			return false
301		}
302	case ed25519.PrivateKey:
303		if len(key) != 64 {
304			return false
305		}
306	default:
307		return false
308	}
309	return true
310}
311
312func (key rawJSONWebKey) rsaPublicKey() (*rsa.PublicKey, error) {
313	if key.N == nil || key.E == nil {
314		return nil, fmt.Errorf("square/go-jose: invalid RSA key, missing n/e values")
315	}
316
317	return &rsa.PublicKey{
318		N: key.N.bigInt(),
319		E: key.E.toInt(),
320	}, nil
321}
322
323func fromEdPublicKey(pub ed25519.PublicKey) *rawJSONWebKey {
324	return &rawJSONWebKey{
325		Kty: "OKP",
326		Crv: "Ed25519",
327		X:   newBuffer(pub),
328	}
329}
330
331func fromRsaPublicKey(pub *rsa.PublicKey) *rawJSONWebKey {
332	return &rawJSONWebKey{
333		Kty: "RSA",
334		N:   newBuffer(pub.N.Bytes()),
335		E:   newBufferFromInt(uint64(pub.E)),
336	}
337}
338
339func (key rawJSONWebKey) ecPublicKey() (*ecdsa.PublicKey, error) {
340	var curve elliptic.Curve
341	switch key.Crv {
342	case "P-256":
343		curve = elliptic.P256()
344	case "P-384":
345		curve = elliptic.P384()
346	case "P-521":
347		curve = elliptic.P521()
348	default:
349		return nil, fmt.Errorf("square/go-jose: unsupported elliptic curve '%s'", key.Crv)
350	}
351
352	if key.X == nil || key.Y == nil {
353		return nil, errors.New("square/go-jose: invalid EC key, missing x/y values")
354	}
355
356	// The length of this octet string MUST be the full size of a coordinate for
357	// the curve specified in the "crv" parameter.
358	// https://tools.ietf.org/html/rfc7518#section-6.2.1.2
359	if curveSize(curve) != len(key.X.data) {
360		return nil, fmt.Errorf("square/go-jose: invalid EC private key, wrong length for x")
361	}
362
363	if curveSize(curve) != len(key.Y.data) {
364		return nil, fmt.Errorf("square/go-jose: invalid EC private key, wrong length for y")
365	}
366
367	x := key.X.bigInt()
368	y := key.Y.bigInt()
369
370	if !curve.IsOnCurve(x, y) {
371		return nil, errors.New("square/go-jose: invalid EC key, X/Y are not on declared curve")
372	}
373
374	return &ecdsa.PublicKey{
375		Curve: curve,
376		X:     x,
377		Y:     y,
378	}, nil
379}
380
381func fromEcPublicKey(pub *ecdsa.PublicKey) (*rawJSONWebKey, error) {
382	if pub == nil || pub.X == nil || pub.Y == nil {
383		return nil, fmt.Errorf("square/go-jose: invalid EC key (nil, or X/Y missing)")
384	}
385
386	name, err := curveName(pub.Curve)
387	if err != nil {
388		return nil, err
389	}
390
391	size := curveSize(pub.Curve)
392
393	xBytes := pub.X.Bytes()
394	yBytes := pub.Y.Bytes()
395
396	if len(xBytes) > size || len(yBytes) > size {
397		return nil, fmt.Errorf("square/go-jose: invalid EC key (X/Y too large)")
398	}
399
400	key := &rawJSONWebKey{
401		Kty: "EC",
402		Crv: name,
403		X:   newFixedSizeBuffer(xBytes, size),
404		Y:   newFixedSizeBuffer(yBytes, size),
405	}
406
407	return key, nil
408}
409
410func (key rawJSONWebKey) edPrivateKey() (ed25519.PrivateKey, error) {
411	var missing []string
412	switch {
413	case key.D == nil:
414		missing = append(missing, "D")
415	case key.X == nil:
416		missing = append(missing, "X")
417	}
418
419	if len(missing) > 0 {
420		return nil, fmt.Errorf("square/go-jose: invalid Ed25519 private key, missing %s value(s)", strings.Join(missing, ", "))
421	}
422
423	privateKey := make([]byte, ed25519.PrivateKeySize)
424	copy(privateKey[0:32], key.D.bytes())
425	copy(privateKey[32:], key.X.bytes())
426	rv := ed25519.PrivateKey(privateKey)
427	return rv, nil
428}
429
430func (key rawJSONWebKey) edPublicKey() (ed25519.PublicKey, error) {
431	if key.X == nil {
432		return nil, fmt.Errorf("square/go-jose: invalid Ed key, missing x value")
433	}
434	publicKey := make([]byte, ed25519.PublicKeySize)
435	copy(publicKey[0:32], key.X.bytes())
436	rv := ed25519.PublicKey(publicKey)
437	return rv, nil
438}
439
440func (key rawJSONWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) {
441	var missing []string
442	switch {
443	case key.N == nil:
444		missing = append(missing, "N")
445	case key.E == nil:
446		missing = append(missing, "E")
447	case key.D == nil:
448		missing = append(missing, "D")
449	case key.P == nil:
450		missing = append(missing, "P")
451	case key.Q == nil:
452		missing = append(missing, "Q")
453	}
454
455	if len(missing) > 0 {
456		return nil, fmt.Errorf("square/go-jose: invalid RSA private key, missing %s value(s)", strings.Join(missing, ", "))
457	}
458
459	rv := &rsa.PrivateKey{
460		PublicKey: rsa.PublicKey{
461			N: key.N.bigInt(),
462			E: key.E.toInt(),
463		},
464		D: key.D.bigInt(),
465		Primes: []*big.Int{
466			key.P.bigInt(),
467			key.Q.bigInt(),
468		},
469	}
470
471	if key.Dp != nil {
472		rv.Precomputed.Dp = key.Dp.bigInt()
473	}
474	if key.Dq != nil {
475		rv.Precomputed.Dq = key.Dq.bigInt()
476	}
477	if key.Qi != nil {
478		rv.Precomputed.Qinv = key.Qi.bigInt()
479	}
480
481	err := rv.Validate()
482	return rv, err
483}
484
485func fromEdPrivateKey(ed ed25519.PrivateKey) (*rawJSONWebKey, error) {
486	raw := fromEdPublicKey(ed25519.PublicKey(ed[32:]))
487
488	raw.D = newBuffer(ed[0:32])
489	return raw, nil
490}
491
492func fromRsaPrivateKey(rsa *rsa.PrivateKey) (*rawJSONWebKey, error) {
493	if len(rsa.Primes) != 2 {
494		return nil, ErrUnsupportedKeyType
495	}
496
497	raw := fromRsaPublicKey(&rsa.PublicKey)
498
499	raw.D = newBuffer(rsa.D.Bytes())
500	raw.P = newBuffer(rsa.Primes[0].Bytes())
501	raw.Q = newBuffer(rsa.Primes[1].Bytes())
502
503	if rsa.Precomputed.Dp != nil {
504		raw.Dp = newBuffer(rsa.Precomputed.Dp.Bytes())
505	}
506	if rsa.Precomputed.Dq != nil {
507		raw.Dq = newBuffer(rsa.Precomputed.Dq.Bytes())
508	}
509	if rsa.Precomputed.Qinv != nil {
510		raw.Qi = newBuffer(rsa.Precomputed.Qinv.Bytes())
511	}
512
513	return raw, nil
514}
515
516func (key rawJSONWebKey) ecPrivateKey() (*ecdsa.PrivateKey, error) {
517	var curve elliptic.Curve
518	switch key.Crv {
519	case "P-256":
520		curve = elliptic.P256()
521	case "P-384":
522		curve = elliptic.P384()
523	case "P-521":
524		curve = elliptic.P521()
525	default:
526		return nil, fmt.Errorf("square/go-jose: unsupported elliptic curve '%s'", key.Crv)
527	}
528
529	if key.X == nil || key.Y == nil || key.D == nil {
530		return nil, fmt.Errorf("square/go-jose: invalid EC private key, missing x/y/d values")
531	}
532
533	// The length of this octet string MUST be the full size of a coordinate for
534	// the curve specified in the "crv" parameter.
535	// https://tools.ietf.org/html/rfc7518#section-6.2.1.2
536	if curveSize(curve) != len(key.X.data) {
537		return nil, fmt.Errorf("square/go-jose: invalid EC private key, wrong length for x")
538	}
539
540	if curveSize(curve) != len(key.Y.data) {
541		return nil, fmt.Errorf("square/go-jose: invalid EC private key, wrong length for y")
542	}
543
544	// https://tools.ietf.org/html/rfc7518#section-6.2.2.1
545	if dSize(curve) != len(key.D.data) {
546		return nil, fmt.Errorf("square/go-jose: invalid EC private key, wrong length for d")
547	}
548
549	x := key.X.bigInt()
550	y := key.Y.bigInt()
551
552	if !curve.IsOnCurve(x, y) {
553		return nil, errors.New("square/go-jose: invalid EC key, X/Y are not on declared curve")
554	}
555
556	return &ecdsa.PrivateKey{
557		PublicKey: ecdsa.PublicKey{
558			Curve: curve,
559			X:     x,
560			Y:     y,
561		},
562		D: key.D.bigInt(),
563	}, nil
564}
565
566func fromEcPrivateKey(ec *ecdsa.PrivateKey) (*rawJSONWebKey, error) {
567	raw, err := fromEcPublicKey(&ec.PublicKey)
568	if err != nil {
569		return nil, err
570	}
571
572	if ec.D == nil {
573		return nil, fmt.Errorf("square/go-jose: invalid EC private key")
574	}
575
576	raw.D = newFixedSizeBuffer(ec.D.Bytes(), dSize(ec.PublicKey.Curve))
577
578	return raw, nil
579}
580
581// dSize returns the size in octets for the "d" member of an elliptic curve
582// private key.
583// The length of this octet string MUST be ceiling(log-base-2(n)/8)
584// octets (where n is the order of the curve).
585// https://tools.ietf.org/html/rfc7518#section-6.2.2.1
586func dSize(curve elliptic.Curve) int {
587	order := curve.Params().P
588	bitLen := order.BitLen()
589	size := bitLen / 8
590	if bitLen%8 != 0 {
591		size = size + 1
592	}
593	return size
594}
595
596func fromSymmetricKey(key []byte) (*rawJSONWebKey, error) {
597	return &rawJSONWebKey{
598		Kty: "oct",
599		K:   newBuffer(key),
600	}, nil
601}
602
603func (key rawJSONWebKey) symmetricKey() ([]byte, error) {
604	if key.K == nil {
605		return nil, fmt.Errorf("square/go-jose: invalid OCT (symmetric) key, missing k value")
606	}
607	return key.K.bytes(), nil
608}
609