...

Source file src/gopkg.in/square/go-jose.v2/jwk.go

Documentation: gopkg.in/square/go-jose.v2

     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  
    17  package jose
    18  
    19  import (
    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.
    43  type 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.
    72  type 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.
    93  func (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.
   165  func (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.
   314  type 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.
   322  func (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  
   333  const rsaThumbprintTemplate = `{"e":"%s","kty":"RSA","n":"%s"}`
   334  const ecThumbprintTemplate = `{"crv":"%s","kty":"EC","x":"%s","y":"%s"}`
   335  const edThumbprintTemplate = `{"crv":"%s","kty":"OKP","x":"%s"}`
   336  
   337  func 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  
   353  func 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  
   359  func 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.
   370  func (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).
   400  func (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.
   410  func (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.
   429  func (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  
   464  func (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  
   475  func fromEdPublicKey(pub ed25519.PublicKey) *rawJSONWebKey {
   476  	return &rawJSONWebKey{
   477  		Kty: "OKP",
   478  		Crv: "Ed25519",
   479  		X:   newBuffer(pub),
   480  	}
   481  }
   482  
   483  func 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  
   491  func (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  
   533  func 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  
   562  func (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  
   582  func (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  
   592  func (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  
   637  func 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  
   644  func 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  
   668  func (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  
   718  func 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
   738  func 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  
   748  func fromSymmetricKey(key []byte) (*rawJSONWebKey, error) {
   749  	return &rawJSONWebKey{
   750  		Kty: "oct",
   751  		K:   newBuffer(key),
   752  	}, nil
   753  }
   754  
   755  func (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  

View as plain text