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	"bytes"
21	"crypto"
22	"crypto/ecdsa"
23	"crypto/elliptic"
24	"crypto/rsa"
25	"crypto/sha1"
26	"crypto/sha256"
27	"crypto/x509"
28	"encoding/base64"
29	"encoding/hex"
30	"errors"
31	"fmt"
32	"math/big"
33	"net/url"
34	"reflect"
35	"strings"
36
37	"golang.org/x/crypto/ed25519"
38
39	"gopkg.in/square/go-jose.v2/json"
40)
41
42// rawJSONWebKey represents a public or private key in JWK format, used for parsing/serializing.
43type rawJSONWebKey struct {
44	Use string      `json:"use,omitempty"`
45	Kty string      `json:"kty,omitempty"`
46	Kid string      `json:"kid,omitempty"`
47	Crv string      `json:"crv,omitempty"`
48	Alg string      `json:"alg,omitempty"`
49	K   *byteBuffer `json:"k,omitempty"`
50	X   *byteBuffer `json:"x,omitempty"`
51	Y   *byteBuffer `json:"y,omitempty"`
52	N   *byteBuffer `json:"n,omitempty"`
53	E   *byteBuffer `json:"e,omitempty"`
54	// -- Following fields are only used for private keys --
55	// RSA uses D, P and Q, while ECDSA uses only D. Fields Dp, Dq, and Qi are
56	// completely optional. Therefore for RSA/ECDSA, D != nil is a contract that
57	// we have a private key whereas D == nil means we have only a public key.
58	D  *byteBuffer `json:"d,omitempty"`
59	P  *byteBuffer `json:"p,omitempty"`
60	Q  *byteBuffer `json:"q,omitempty"`
61	Dp *byteBuffer `json:"dp,omitempty"`
62	Dq *byteBuffer `json:"dq,omitempty"`
63	Qi *byteBuffer `json:"qi,omitempty"`
64	// Certificates
65	X5c       []string `json:"x5c,omitempty"`
66	X5u       *url.URL `json:"x5u,omitempty"`
67	X5tSHA1   string   `json:"x5t,omitempty"`
68	X5tSHA256 string   `json:"x5t#S256,omitempty"`
69}
70
71// JSONWebKey represents a public or private key in JWK format.
72type JSONWebKey struct {
73	// Cryptographic key, can be a symmetric or asymmetric key.
74	Key interface{}
75	// Key identifier, parsed from `kid` header.
76	KeyID string
77	// Key algorithm, parsed from `alg` header.
78	Algorithm string
79	// Key use, parsed from `use` header.
80	Use string
81
82	// X.509 certificate chain, parsed from `x5c` header.
83	Certificates []*x509.Certificate
84	// X.509 certificate URL, parsed from `x5u` header.
85	CertificatesURL *url.URL
86	// X.509 certificate thumbprint (SHA-1), parsed from `x5t` header.
87	CertificateThumbprintSHA1 []byte
88	// X.509 certificate thumbprint (SHA-256), parsed from `x5t#S256` header.
89	CertificateThumbprintSHA256 []byte
90}
91
92// MarshalJSON serializes the given key to its JSON representation.
93func (k JSONWebKey) MarshalJSON() ([]byte, error) {
94	var raw *rawJSONWebKey
95	var err error
96
97	switch key := k.Key.(type) {
98	case ed25519.PublicKey:
99		raw = fromEdPublicKey(key)
100	case *ecdsa.PublicKey:
101		raw, err = fromEcPublicKey(key)
102	case *rsa.PublicKey:
103		raw = fromRsaPublicKey(key)
104	case ed25519.PrivateKey:
105		raw, err = fromEdPrivateKey(key)
106	case *ecdsa.PrivateKey:
107		raw, err = fromEcPrivateKey(key)
108	case *rsa.PrivateKey:
109		raw, err = fromRsaPrivateKey(key)
110	case []byte:
111		raw, err = fromSymmetricKey(key)
112	default:
113		return nil, fmt.Errorf("square/go-jose: unknown key type '%s'", reflect.TypeOf(key))
114	}
115
116	if err != nil {
117		return nil, err
118	}
119
120	raw.Kid = k.KeyID
121	raw.Alg = k.Algorithm
122	raw.Use = k.Use
123
124	for _, cert := range k.Certificates {
125		raw.X5c = append(raw.X5c, base64.StdEncoding.EncodeToString(cert.Raw))
126	}
127
128	x5tSHA1Len := len(k.CertificateThumbprintSHA1)
129	x5tSHA256Len := len(k.CertificateThumbprintSHA256)
130	if x5tSHA1Len > 0 {
131		if x5tSHA1Len != sha1.Size {
132			return nil, fmt.Errorf("square/go-jose: invalid SHA-1 thumbprint (must be %d bytes, not %d)", sha1.Size, x5tSHA1Len)
133		}
134		raw.X5tSHA1 = base64.RawURLEncoding.EncodeToString(k.CertificateThumbprintSHA1)
135	}
136	if x5tSHA256Len > 0 {
137		if x5tSHA256Len != sha256.Size {
138			return nil, fmt.Errorf("square/go-jose: invalid SHA-256 thumbprint (must be %d bytes, not %d)", sha256.Size, x5tSHA256Len)
139		}
140		raw.X5tSHA256 = base64.RawURLEncoding.EncodeToString(k.CertificateThumbprintSHA256)
141	}
142
143	// If cert chain is attached (as opposed to being behind a URL), check the
144	// keys thumbprints to make sure they match what is expected. This is to
145	// ensure we don't accidentally produce a JWK with semantically inconsistent
146	// data in the headers.
147	if len(k.Certificates) > 0 {
148		expectedSHA1 := sha1.Sum(k.Certificates[0].Raw)
149		expectedSHA256 := sha256.Sum256(k.Certificates[0].Raw)
150
151		if len(k.CertificateThumbprintSHA1) > 0 && !bytes.Equal(k.CertificateThumbprintSHA1, expectedSHA1[:]) {
152			return nil, errors.New("square/go-jose: invalid SHA-1 thumbprint, does not match cert chain")
153		}
154		if len(k.CertificateThumbprintSHA256) > 0 && !bytes.Equal(k.CertificateThumbprintSHA256, expectedSHA256[:]) {
155			return nil, errors.New("square/go-jose: invalid or SHA-256 thumbprint, does not match cert chain")
156		}
157	}
158
159	raw.X5u = k.CertificatesURL
160
161	return json.Marshal(raw)
162}
163
164// UnmarshalJSON reads a key from its JSON representation.
165func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
166	var raw rawJSONWebKey
167	err = json.Unmarshal(data, &raw)
168	if err != nil {
169		return err
170	}
171
172	certs, err := parseCertificateChain(raw.X5c)
173	if err != nil {
174		return fmt.Errorf("square/go-jose: failed to unmarshal x5c field: %s", err)
175	}
176
177	var key interface{}
178	var certPub interface{}
179	var keyPub interface{}
180
181	if len(certs) > 0 {
182		// We need to check that leaf public key matches the key embedded in this
183		// JWK, as required by the standard (see RFC 7517, Section 4.7). Otherwise
184		// the JWK parsed could be semantically invalid. Technically, should also
185		// check key usage fields and other extensions on the cert here, but the
186		// standard doesn't exactly explain how they're supposed to map from the
187		// JWK representation to the X.509 extensions.
188		certPub = certs[0].PublicKey
189	}
190
191	switch raw.Kty {
192	case "EC":
193		if raw.D != nil {
194			key, err = raw.ecPrivateKey()
195			if err == nil {
196				keyPub = key.(*ecdsa.PrivateKey).Public()
197			}
198		} else {
199			key, err = raw.ecPublicKey()
200			keyPub = key
201		}
202	case "RSA":
203		if raw.D != nil {
204			key, err = raw.rsaPrivateKey()
205			if err == nil {
206				keyPub = key.(*rsa.PrivateKey).Public()
207			}
208		} else {
209			key, err = raw.rsaPublicKey()
210			keyPub = key
211		}
212	case "oct":
213		if certPub != nil {
214			return errors.New("square/go-jose: invalid JWK, found 'oct' (symmetric) key with cert chain")
215		}
216		key, err = raw.symmetricKey()
217	case "OKP":
218		if raw.Crv == "Ed25519" && raw.X != nil {
219			if raw.D != nil {
220				key, err = raw.edPrivateKey()
221				if err == nil {
222					keyPub = key.(ed25519.PrivateKey).Public()
223				}
224			} else {
225				key, err = raw.edPublicKey()
226				keyPub = key
227			}
228		} else {
229			err = fmt.Errorf("square/go-jose: unknown curve %s'", raw.Crv)
230		}
231	default:
232		err = fmt.Errorf("square/go-jose: unknown json web key type '%s'", raw.Kty)
233	}
234
235	if err != nil {
236		return
237	}
238
239	if certPub != nil && keyPub != nil {
240		if !reflect.DeepEqual(certPub, keyPub) {
241			return errors.New("square/go-jose: invalid JWK, public keys in key and x5c fields do not match")
242		}
243	}
244
245	*k = JSONWebKey{Key: key, KeyID: raw.Kid, Algorithm: raw.Alg, Use: raw.Use, Certificates: certs}
246
247	k.CertificatesURL = raw.X5u
248
249	// x5t parameters are base64url-encoded SHA thumbprints
250	// See RFC 7517, Section 4.8, https://tools.ietf.org/html/rfc7517#section-4.8
251	x5tSHA1bytes, err := base64.RawURLEncoding.DecodeString(raw.X5tSHA1)
252	if err != nil {
253		return errors.New("square/go-jose: invalid JWK, x5t header has invalid encoding")
254	}
255
256	// RFC 7517, Section 4.8 is ambiguous as to whether the digest output should be byte or hex,
257	// for this reason, after base64 decoding, if the size is sha1.Size it's likely that the value is a byte encoded
258	// checksum so we skip this. Otherwise if the checksum was hex encoded we expect a 40 byte sized array so we'll
259	// try to hex decode it. When Marshalling this value we'll always use a base64 encoded version of byte format checksum.
260	if len(x5tSHA1bytes) == 2*sha1.Size {
261		hx, err := hex.DecodeString(string(x5tSHA1bytes))
262		if err != nil {
263			return fmt.Errorf("square/go-jose: invalid JWK, unable to hex decode x5t: %v", err)
264
265		}
266		x5tSHA1bytes = hx
267	}
268
269	k.CertificateThumbprintSHA1 = x5tSHA1bytes
270
271	x5tSHA256bytes, err := base64.RawURLEncoding.DecodeString(raw.X5tSHA256)
272	if err != nil {
273		return errors.New("square/go-jose: invalid JWK, x5t#S256 header has invalid encoding")
274	}
275
276	if len(x5tSHA256bytes) == 2*sha256.Size {
277		hx256, err := hex.DecodeString(string(x5tSHA256bytes))
278		if err != nil {
279			return fmt.Errorf("square/go-jose: invalid JWK, unable to hex decode x5t#S256: %v", err)
280		}
281		x5tSHA256bytes = hx256
282	}
283
284	k.CertificateThumbprintSHA256 = x5tSHA256bytes
285
286	x5tSHA1Len := len(k.CertificateThumbprintSHA1)
287	x5tSHA256Len := len(k.CertificateThumbprintSHA256)
288	if x5tSHA1Len > 0 && x5tSHA1Len != sha1.Size {
289		return errors.New("square/go-jose: invalid JWK, x5t header is of incorrect size")
290	}
291	if x5tSHA256Len > 0 && x5tSHA256Len != sha256.Size {
292		return errors.New("square/go-jose: invalid JWK, x5t#S256 header is of incorrect size")
293	}
294
295	// If certificate chain *and* thumbprints are set, verify correctness.
296	if len(k.Certificates) > 0 {
297		leaf := k.Certificates[0]
298		sha1sum := sha1.Sum(leaf.Raw)
299		sha256sum := sha256.Sum256(leaf.Raw)
300
301		if len(k.CertificateThumbprintSHA1) > 0 && !bytes.Equal(sha1sum[:], k.CertificateThumbprintSHA1) {
302			return errors.New("square/go-jose: invalid JWK, x5c thumbprint does not match x5t value")
303		}
304
305		if len(k.CertificateThumbprintSHA256) > 0 && !bytes.Equal(sha256sum[:], k.CertificateThumbprintSHA256) {
306			return errors.New("square/go-jose: invalid JWK, x5c thumbprint does not match x5t#S256 value")
307		}
308	}
309
310	return
311}
312
313// JSONWebKeySet represents a JWK Set object.
314type JSONWebKeySet struct {
315	Keys []JSONWebKey `json:"keys"`
316}
317
318// Key convenience method returns keys by key ID. Specification states
319// that a JWK Set "SHOULD" use distinct key IDs, but allows for some
320// cases where they are not distinct. Hence method returns a slice
321// of JSONWebKeys.
322func (s *JSONWebKeySet) Key(kid string) []JSONWebKey {
323	var keys []JSONWebKey
324	for _, key := range s.Keys {
325		if key.KeyID == kid {
326			keys = append(keys, key)
327		}
328	}
329
330	return keys
331}
332
333const rsaThumbprintTemplate = `{"e":"%s","kty":"RSA","n":"%s"}`
334const ecThumbprintTemplate = `{"crv":"%s","kty":"EC","x":"%s","y":"%s"}`
335const edThumbprintTemplate = `{"crv":"%s","kty":"OKP","x":"%s"}`
336
337func ecThumbprintInput(curve elliptic.Curve, x, y *big.Int) (string, error) {
338	coordLength := curveSize(curve)
339	crv, err := curveName(curve)
340	if err != nil {
341		return "", err
342	}
343
344	if len(x.Bytes()) > coordLength || len(y.Bytes()) > coordLength {
345		return "", errors.New("square/go-jose: invalid elliptic key (too large)")
346	}
347
348	return fmt.Sprintf(ecThumbprintTemplate, crv,
349		newFixedSizeBuffer(x.Bytes(), coordLength).base64(),
350		newFixedSizeBuffer(y.Bytes(), coordLength).base64()), nil
351}
352
353func rsaThumbprintInput(n *big.Int, e int) (string, error) {
354	return fmt.Sprintf(rsaThumbprintTemplate,
355		newBufferFromInt(uint64(e)).base64(),
356		newBuffer(n.Bytes()).base64()), nil
357}
358
359func edThumbprintInput(ed ed25519.PublicKey) (string, error) {
360	crv := "Ed25519"
361	if len(ed) > 32 {
362		return "", errors.New("square/go-jose: invalid elliptic key (too large)")
363	}
364	return fmt.Sprintf(edThumbprintTemplate, crv,
365		newFixedSizeBuffer(ed, 32).base64()), nil
366}
367
368// Thumbprint computes the JWK Thumbprint of a key using the
369// indicated hash algorithm.
370func (k *JSONWebKey) Thumbprint(hash crypto.Hash) ([]byte, error) {
371	var input string
372	var err error
373	switch key := k.Key.(type) {
374	case ed25519.PublicKey:
375		input, err = edThumbprintInput(key)
376	case *ecdsa.PublicKey:
377		input, err = ecThumbprintInput(key.Curve, key.X, key.Y)
378	case *ecdsa.PrivateKey:
379		input, err = ecThumbprintInput(key.Curve, key.X, key.Y)
380	case *rsa.PublicKey:
381		input, err = rsaThumbprintInput(key.N, key.E)
382	case *rsa.PrivateKey:
383		input, err = rsaThumbprintInput(key.N, key.E)
384	case ed25519.PrivateKey:
385		input, err = edThumbprintInput(ed25519.PublicKey(key[32:]))
386	default:
387		return nil, fmt.Errorf("square/go-jose: unknown key type '%s'", reflect.TypeOf(key))
388	}
389
390	if err != nil {
391		return nil, err
392	}
393
394	h := hash.New()
395	h.Write([]byte(input))
396	return h.Sum(nil), nil
397}
398
399// IsPublic returns true if the JWK represents a public key (not symmetric, not private).
400func (k *JSONWebKey) IsPublic() bool {
401	switch k.Key.(type) {
402	case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
403		return true
404	default:
405		return false
406	}
407}
408
409// Public creates JSONWebKey with corresponding public key if JWK represents asymmetric private key.
410func (k *JSONWebKey) Public() JSONWebKey {
411	if k.IsPublic() {
412		return *k
413	}
414	ret := *k
415	switch key := k.Key.(type) {
416	case *ecdsa.PrivateKey:
417		ret.Key = key.Public()
418	case *rsa.PrivateKey:
419		ret.Key = key.Public()
420	case ed25519.PrivateKey:
421		ret.Key = key.Public()
422	default:
423		return JSONWebKey{} // returning invalid key
424	}
425	return ret
426}
427
428// Valid checks that the key contains the expected parameters.
429func (k *JSONWebKey) Valid() bool {
430	if k.Key == nil {
431		return false
432	}
433	switch key := k.Key.(type) {
434	case *ecdsa.PublicKey:
435		if key.Curve == nil || key.X == nil || key.Y == nil {
436			return false
437		}
438	case *ecdsa.PrivateKey:
439		if key.Curve == nil || key.X == nil || key.Y == nil || key.D == nil {
440			return false
441		}
442	case *rsa.PublicKey:
443		if key.N == nil || key.E == 0 {
444			return false
445		}
446	case *rsa.PrivateKey:
447		if key.N == nil || key.E == 0 || key.D == nil || len(key.Primes) < 2 {
448			return false
449		}
450	case ed25519.PublicKey:
451		if len(key) != 32 {
452			return false
453		}
454	case ed25519.PrivateKey:
455		if len(key) != 64 {
456			return false
457		}
458	default:
459		return false
460	}
461	return true
462}
463
464func (key rawJSONWebKey) rsaPublicKey() (*rsa.PublicKey, error) {
465	if key.N == nil || key.E == nil {
466		return nil, fmt.Errorf("square/go-jose: invalid RSA key, missing n/e values")
467	}
468
469	return &rsa.PublicKey{
470		N: key.N.bigInt(),
471		E: key.E.toInt(),
472	}, nil
473}
474
475func fromEdPublicKey(pub ed25519.PublicKey) *rawJSONWebKey {
476	return &rawJSONWebKey{
477		Kty: "OKP",
478		Crv: "Ed25519",
479		X:   newBuffer(pub),
480	}
481}
482
483func fromRsaPublicKey(pub *rsa.PublicKey) *rawJSONWebKey {
484	return &rawJSONWebKey{
485		Kty: "RSA",
486		N:   newBuffer(pub.N.Bytes()),
487		E:   newBufferFromInt(uint64(pub.E)),
488	}
489}
490
491func (key rawJSONWebKey) ecPublicKey() (*ecdsa.PublicKey, error) {
492	var curve elliptic.Curve
493	switch key.Crv {
494	case "P-256":
495		curve = elliptic.P256()
496	case "P-384":
497		curve = elliptic.P384()
498	case "P-521":
499		curve = elliptic.P521()
500	default:
501		return nil, fmt.Errorf("square/go-jose: unsupported elliptic curve '%s'", key.Crv)
502	}
503
504	if key.X == nil || key.Y == nil {
505		return nil, errors.New("square/go-jose: invalid EC key, missing x/y values")
506	}
507
508	// The length of this octet string MUST be the full size of a coordinate for
509	// the curve specified in the "crv" parameter.
510	// https://tools.ietf.org/html/rfc7518#section-6.2.1.2
511	if curveSize(curve) != len(key.X.data) {
512		return nil, fmt.Errorf("square/go-jose: invalid EC public key, wrong length for x")
513	}
514
515	if curveSize(curve) != len(key.Y.data) {
516		return nil, fmt.Errorf("square/go-jose: invalid EC public key, wrong length for y")
517	}
518
519	x := key.X.bigInt()
520	y := key.Y.bigInt()
521
522	if !curve.IsOnCurve(x, y) {
523		return nil, errors.New("square/go-jose: invalid EC key, X/Y are not on declared curve")
524	}
525
526	return &ecdsa.PublicKey{
527		Curve: curve,
528		X:     x,
529		Y:     y,
530	}, nil
531}
532
533func fromEcPublicKey(pub *ecdsa.PublicKey) (*rawJSONWebKey, error) {
534	if pub == nil || pub.X == nil || pub.Y == nil {
535		return nil, fmt.Errorf("square/go-jose: invalid EC key (nil, or X/Y missing)")
536	}
537
538	name, err := curveName(pub.Curve)
539	if err != nil {
540		return nil, err
541	}
542
543	size := curveSize(pub.Curve)
544
545	xBytes := pub.X.Bytes()
546	yBytes := pub.Y.Bytes()
547
548	if len(xBytes) > size || len(yBytes) > size {
549		return nil, fmt.Errorf("square/go-jose: invalid EC key (X/Y too large)")
550	}
551
552	key := &rawJSONWebKey{
553		Kty: "EC",
554		Crv: name,
555		X:   newFixedSizeBuffer(xBytes, size),
556		Y:   newFixedSizeBuffer(yBytes, size),
557	}
558
559	return key, nil
560}
561
562func (key rawJSONWebKey) edPrivateKey() (ed25519.PrivateKey, error) {
563	var missing []string
564	switch {
565	case key.D == nil:
566		missing = append(missing, "D")
567	case key.X == nil:
568		missing = append(missing, "X")
569	}
570
571	if len(missing) > 0 {
572		return nil, fmt.Errorf("square/go-jose: invalid Ed25519 private key, missing %s value(s)", strings.Join(missing, ", "))
573	}
574
575	privateKey := make([]byte, ed25519.PrivateKeySize)
576	copy(privateKey[0:32], key.D.bytes())
577	copy(privateKey[32:], key.X.bytes())
578	rv := ed25519.PrivateKey(privateKey)
579	return rv, nil
580}
581
582func (key rawJSONWebKey) edPublicKey() (ed25519.PublicKey, error) {
583	if key.X == nil {
584		return nil, fmt.Errorf("square/go-jose: invalid Ed key, missing x value")
585	}
586	publicKey := make([]byte, ed25519.PublicKeySize)
587	copy(publicKey[0:32], key.X.bytes())
588	rv := ed25519.PublicKey(publicKey)
589	return rv, nil
590}
591
592func (key rawJSONWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) {
593	var missing []string
594	switch {
595	case key.N == nil:
596		missing = append(missing, "N")
597	case key.E == nil:
598		missing = append(missing, "E")
599	case key.D == nil:
600		missing = append(missing, "D")
601	case key.P == nil:
602		missing = append(missing, "P")
603	case key.Q == nil:
604		missing = append(missing, "Q")
605	}
606
607	if len(missing) > 0 {
608		return nil, fmt.Errorf("square/go-jose: invalid RSA private key, missing %s value(s)", strings.Join(missing, ", "))
609	}
610
611	rv := &rsa.PrivateKey{
612		PublicKey: rsa.PublicKey{
613			N: key.N.bigInt(),
614			E: key.E.toInt(),
615		},
616		D: key.D.bigInt(),
617		Primes: []*big.Int{
618			key.P.bigInt(),
619			key.Q.bigInt(),
620		},
621	}
622
623	if key.Dp != nil {
624		rv.Precomputed.Dp = key.Dp.bigInt()
625	}
626	if key.Dq != nil {
627		rv.Precomputed.Dq = key.Dq.bigInt()
628	}
629	if key.Qi != nil {
630		rv.Precomputed.Qinv = key.Qi.bigInt()
631	}
632
633	err := rv.Validate()
634	return rv, err
635}
636
637func fromEdPrivateKey(ed ed25519.PrivateKey) (*rawJSONWebKey, error) {
638	raw := fromEdPublicKey(ed25519.PublicKey(ed[32:]))
639
640	raw.D = newBuffer(ed[0:32])
641	return raw, nil
642}
643
644func fromRsaPrivateKey(rsa *rsa.PrivateKey) (*rawJSONWebKey, error) {
645	if len(rsa.Primes) != 2 {
646		return nil, ErrUnsupportedKeyType
647	}
648
649	raw := fromRsaPublicKey(&rsa.PublicKey)
650
651	raw.D = newBuffer(rsa.D.Bytes())
652	raw.P = newBuffer(rsa.Primes[0].Bytes())
653	raw.Q = newBuffer(rsa.Primes[1].Bytes())
654
655	if rsa.Precomputed.Dp != nil {
656		raw.Dp = newBuffer(rsa.Precomputed.Dp.Bytes())
657	}
658	if rsa.Precomputed.Dq != nil {
659		raw.Dq = newBuffer(rsa.Precomputed.Dq.Bytes())
660	}
661	if rsa.Precomputed.Qinv != nil {
662		raw.Qi = newBuffer(rsa.Precomputed.Qinv.Bytes())
663	}
664
665	return raw, nil
666}
667
668func (key rawJSONWebKey) ecPrivateKey() (*ecdsa.PrivateKey, error) {
669	var curve elliptic.Curve
670	switch key.Crv {
671	case "P-256":
672		curve = elliptic.P256()
673	case "P-384":
674		curve = elliptic.P384()
675	case "P-521":
676		curve = elliptic.P521()
677	default:
678		return nil, fmt.Errorf("square/go-jose: unsupported elliptic curve '%s'", key.Crv)
679	}
680
681	if key.X == nil || key.Y == nil || key.D == nil {
682		return nil, fmt.Errorf("square/go-jose: invalid EC private key, missing x/y/d values")
683	}
684
685	// The length of this octet string MUST be the full size of a coordinate for
686	// the curve specified in the "crv" parameter.
687	// https://tools.ietf.org/html/rfc7518#section-6.2.1.2
688	if curveSize(curve) != len(key.X.data) {
689		return nil, fmt.Errorf("square/go-jose: invalid EC private key, wrong length for x")
690	}
691
692	if curveSize(curve) != len(key.Y.data) {
693		return nil, fmt.Errorf("square/go-jose: invalid EC private key, wrong length for y")
694	}
695
696	// https://tools.ietf.org/html/rfc7518#section-6.2.2.1
697	if dSize(curve) != len(key.D.data) {
698		return nil, fmt.Errorf("square/go-jose: invalid EC private key, wrong length for d")
699	}
700
701	x := key.X.bigInt()
702	y := key.Y.bigInt()
703
704	if !curve.IsOnCurve(x, y) {
705		return nil, errors.New("square/go-jose: invalid EC key, X/Y are not on declared curve")
706	}
707
708	return &ecdsa.PrivateKey{
709		PublicKey: ecdsa.PublicKey{
710			Curve: curve,
711			X:     x,
712			Y:     y,
713		},
714		D: key.D.bigInt(),
715	}, nil
716}
717
718func fromEcPrivateKey(ec *ecdsa.PrivateKey) (*rawJSONWebKey, error) {
719	raw, err := fromEcPublicKey(&ec.PublicKey)
720	if err != nil {
721		return nil, err
722	}
723
724	if ec.D == nil {
725		return nil, fmt.Errorf("square/go-jose: invalid EC private key")
726	}
727
728	raw.D = newFixedSizeBuffer(ec.D.Bytes(), dSize(ec.PublicKey.Curve))
729
730	return raw, nil
731}
732
733// dSize returns the size in octets for the "d" member of an elliptic curve
734// private key.
735// The length of this octet string MUST be ceiling(log-base-2(n)/8)
736// octets (where n is the order of the curve).
737// https://tools.ietf.org/html/rfc7518#section-6.2.2.1
738func dSize(curve elliptic.Curve) int {
739	order := curve.Params().P
740	bitLen := order.BitLen()
741	size := bitLen / 8
742	if bitLen%8 != 0 {
743		size = size + 1
744	}
745	return size
746}
747
748func fromSymmetricKey(key []byte) (*rawJSONWebKey, error) {
749	return &rawJSONWebKey{
750		Kty: "oct",
751		K:   newBuffer(key),
752	}, nil
753}
754
755func (key rawJSONWebKey) symmetricKey() ([]byte, error) {
756	if key.K == nil {
757		return nil, fmt.Errorf("square/go-jose: invalid OCT (symmetric) key, missing k value")
758	}
759	return key.K.bytes(), nil
760}
761