...

Source file src/gopkg.in/square/go-jose.v2/asymmetric.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  	"crypto"
    21  	"crypto/aes"
    22  	"crypto/ecdsa"
    23  	"crypto/rand"
    24  	"crypto/rsa"
    25  	"crypto/sha1"
    26  	"crypto/sha256"
    27  	"errors"
    28  	"fmt"
    29  	"math/big"
    30  
    31  	"golang.org/x/crypto/ed25519"
    32  	josecipher "gopkg.in/square/go-jose.v2/cipher"
    33  	"gopkg.in/square/go-jose.v2/json"
    34  )
    35  
    36  // A generic RSA-based encrypter/verifier
    37  type rsaEncrypterVerifier struct {
    38  	publicKey *rsa.PublicKey
    39  }
    40  
    41  // A generic RSA-based decrypter/signer
    42  type rsaDecrypterSigner struct {
    43  	privateKey *rsa.PrivateKey
    44  }
    45  
    46  // A generic EC-based encrypter/verifier
    47  type ecEncrypterVerifier struct {
    48  	publicKey *ecdsa.PublicKey
    49  }
    50  
    51  type edEncrypterVerifier struct {
    52  	publicKey ed25519.PublicKey
    53  }
    54  
    55  // A key generator for ECDH-ES
    56  type ecKeyGenerator struct {
    57  	size      int
    58  	algID     string
    59  	publicKey *ecdsa.PublicKey
    60  }
    61  
    62  // A generic EC-based decrypter/signer
    63  type ecDecrypterSigner struct {
    64  	privateKey *ecdsa.PrivateKey
    65  }
    66  
    67  type edDecrypterSigner struct {
    68  	privateKey ed25519.PrivateKey
    69  }
    70  
    71  // newRSARecipient creates recipientKeyInfo based on the given key.
    72  func newRSARecipient(keyAlg KeyAlgorithm, publicKey *rsa.PublicKey) (recipientKeyInfo, error) {
    73  	// Verify that key management algorithm is supported by this encrypter
    74  	switch keyAlg {
    75  	case RSA1_5, RSA_OAEP, RSA_OAEP_256:
    76  	default:
    77  		return recipientKeyInfo{}, ErrUnsupportedAlgorithm
    78  	}
    79  
    80  	if publicKey == nil {
    81  		return recipientKeyInfo{}, errors.New("invalid public key")
    82  	}
    83  
    84  	return recipientKeyInfo{
    85  		keyAlg: keyAlg,
    86  		keyEncrypter: &rsaEncrypterVerifier{
    87  			publicKey: publicKey,
    88  		},
    89  	}, nil
    90  }
    91  
    92  // newRSASigner creates a recipientSigInfo based on the given key.
    93  func newRSASigner(sigAlg SignatureAlgorithm, privateKey *rsa.PrivateKey) (recipientSigInfo, error) {
    94  	// Verify that key management algorithm is supported by this encrypter
    95  	switch sigAlg {
    96  	case RS256, RS384, RS512, PS256, PS384, PS512:
    97  	default:
    98  		return recipientSigInfo{}, ErrUnsupportedAlgorithm
    99  	}
   100  
   101  	if privateKey == nil {
   102  		return recipientSigInfo{}, errors.New("invalid private key")
   103  	}
   104  
   105  	return recipientSigInfo{
   106  		sigAlg: sigAlg,
   107  		publicKey: staticPublicKey(&JSONWebKey{
   108  			Key: privateKey.Public(),
   109  		}),
   110  		signer: &rsaDecrypterSigner{
   111  			privateKey: privateKey,
   112  		},
   113  	}, nil
   114  }
   115  
   116  func newEd25519Signer(sigAlg SignatureAlgorithm, privateKey ed25519.PrivateKey) (recipientSigInfo, error) {
   117  	if sigAlg != EdDSA {
   118  		return recipientSigInfo{}, ErrUnsupportedAlgorithm
   119  	}
   120  
   121  	if privateKey == nil {
   122  		return recipientSigInfo{}, errors.New("invalid private key")
   123  	}
   124  	return recipientSigInfo{
   125  		sigAlg: sigAlg,
   126  		publicKey: staticPublicKey(&JSONWebKey{
   127  			Key: privateKey.Public(),
   128  		}),
   129  		signer: &edDecrypterSigner{
   130  			privateKey: privateKey,
   131  		},
   132  	}, nil
   133  }
   134  
   135  // newECDHRecipient creates recipientKeyInfo based on the given key.
   136  func newECDHRecipient(keyAlg KeyAlgorithm, publicKey *ecdsa.PublicKey) (recipientKeyInfo, error) {
   137  	// Verify that key management algorithm is supported by this encrypter
   138  	switch keyAlg {
   139  	case ECDH_ES, ECDH_ES_A128KW, ECDH_ES_A192KW, ECDH_ES_A256KW:
   140  	default:
   141  		return recipientKeyInfo{}, ErrUnsupportedAlgorithm
   142  	}
   143  
   144  	if publicKey == nil || !publicKey.Curve.IsOnCurve(publicKey.X, publicKey.Y) {
   145  		return recipientKeyInfo{}, errors.New("invalid public key")
   146  	}
   147  
   148  	return recipientKeyInfo{
   149  		keyAlg: keyAlg,
   150  		keyEncrypter: &ecEncrypterVerifier{
   151  			publicKey: publicKey,
   152  		},
   153  	}, nil
   154  }
   155  
   156  // newECDSASigner creates a recipientSigInfo based on the given key.
   157  func newECDSASigner(sigAlg SignatureAlgorithm, privateKey *ecdsa.PrivateKey) (recipientSigInfo, error) {
   158  	// Verify that key management algorithm is supported by this encrypter
   159  	switch sigAlg {
   160  	case ES256, ES384, ES512:
   161  	default:
   162  		return recipientSigInfo{}, ErrUnsupportedAlgorithm
   163  	}
   164  
   165  	if privateKey == nil {
   166  		return recipientSigInfo{}, errors.New("invalid private key")
   167  	}
   168  
   169  	return recipientSigInfo{
   170  		sigAlg: sigAlg,
   171  		publicKey: staticPublicKey(&JSONWebKey{
   172  			Key: privateKey.Public(),
   173  		}),
   174  		signer: &ecDecrypterSigner{
   175  			privateKey: privateKey,
   176  		},
   177  	}, nil
   178  }
   179  
   180  // Encrypt the given payload and update the object.
   181  func (ctx rsaEncrypterVerifier) encryptKey(cek []byte, alg KeyAlgorithm) (recipientInfo, error) {
   182  	encryptedKey, err := ctx.encrypt(cek, alg)
   183  	if err != nil {
   184  		return recipientInfo{}, err
   185  	}
   186  
   187  	return recipientInfo{
   188  		encryptedKey: encryptedKey,
   189  		header:       &rawHeader{},
   190  	}, nil
   191  }
   192  
   193  // Encrypt the given payload. Based on the key encryption algorithm,
   194  // this will either use RSA-PKCS1v1.5 or RSA-OAEP (with SHA-1 or SHA-256).
   195  func (ctx rsaEncrypterVerifier) encrypt(cek []byte, alg KeyAlgorithm) ([]byte, error) {
   196  	switch alg {
   197  	case RSA1_5:
   198  		return rsa.EncryptPKCS1v15(RandReader, ctx.publicKey, cek)
   199  	case RSA_OAEP:
   200  		return rsa.EncryptOAEP(sha1.New(), RandReader, ctx.publicKey, cek, []byte{})
   201  	case RSA_OAEP_256:
   202  		return rsa.EncryptOAEP(sha256.New(), RandReader, ctx.publicKey, cek, []byte{})
   203  	}
   204  
   205  	return nil, ErrUnsupportedAlgorithm
   206  }
   207  
   208  // Decrypt the given payload and return the content encryption key.
   209  func (ctx rsaDecrypterSigner) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) {
   210  	return ctx.decrypt(recipient.encryptedKey, headers.getAlgorithm(), generator)
   211  }
   212  
   213  // Decrypt the given payload. Based on the key encryption algorithm,
   214  // this will either use RSA-PKCS1v1.5 or RSA-OAEP (with SHA-1 or SHA-256).
   215  func (ctx rsaDecrypterSigner) decrypt(jek []byte, alg KeyAlgorithm, generator keyGenerator) ([]byte, error) {
   216  	// Note: The random reader on decrypt operations is only used for blinding,
   217  	// so stubbing is meanlingless (hence the direct use of rand.Reader).
   218  	switch alg {
   219  	case RSA1_5:
   220  		defer func() {
   221  			// DecryptPKCS1v15SessionKey sometimes panics on an invalid payload
   222  			// because of an index out of bounds error, which we want to ignore.
   223  			// This has been fixed in Go 1.3.1 (released 2014/08/13), the recover()
   224  			// only exists for preventing crashes with unpatched versions.
   225  			// See: https://groups.google.com/forum/#!topic/golang-dev/7ihX6Y6kx9k
   226  			// See: https://code.google.com/p/go/source/detail?r=58ee390ff31602edb66af41ed10901ec95904d33
   227  			_ = recover()
   228  		}()
   229  
   230  		// Perform some input validation.
   231  		keyBytes := ctx.privateKey.PublicKey.N.BitLen() / 8
   232  		if keyBytes != len(jek) {
   233  			// Input size is incorrect, the encrypted payload should always match
   234  			// the size of the public modulus (e.g. using a 2048 bit key will
   235  			// produce 256 bytes of output). Reject this since it's invalid input.
   236  			return nil, ErrCryptoFailure
   237  		}
   238  
   239  		cek, _, err := generator.genKey()
   240  		if err != nil {
   241  			return nil, ErrCryptoFailure
   242  		}
   243  
   244  		// When decrypting an RSA-PKCS1v1.5 payload, we must take precautions to
   245  		// prevent chosen-ciphertext attacks as described in RFC 3218, "Preventing
   246  		// the Million Message Attack on Cryptographic Message Syntax". We are
   247  		// therefore deliberately ignoring errors here.
   248  		_ = rsa.DecryptPKCS1v15SessionKey(rand.Reader, ctx.privateKey, jek, cek)
   249  
   250  		return cek, nil
   251  	case RSA_OAEP:
   252  		// Use rand.Reader for RSA blinding
   253  		return rsa.DecryptOAEP(sha1.New(), rand.Reader, ctx.privateKey, jek, []byte{})
   254  	case RSA_OAEP_256:
   255  		// Use rand.Reader for RSA blinding
   256  		return rsa.DecryptOAEP(sha256.New(), rand.Reader, ctx.privateKey, jek, []byte{})
   257  	}
   258  
   259  	return nil, ErrUnsupportedAlgorithm
   260  }
   261  
   262  // Sign the given payload
   263  func (ctx rsaDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) {
   264  	var hash crypto.Hash
   265  
   266  	switch alg {
   267  	case RS256, PS256:
   268  		hash = crypto.SHA256
   269  	case RS384, PS384:
   270  		hash = crypto.SHA384
   271  	case RS512, PS512:
   272  		hash = crypto.SHA512
   273  	default:
   274  		return Signature{}, ErrUnsupportedAlgorithm
   275  	}
   276  
   277  	hasher := hash.New()
   278  
   279  	// According to documentation, Write() on hash never fails
   280  	_, _ = hasher.Write(payload)
   281  	hashed := hasher.Sum(nil)
   282  
   283  	var out []byte
   284  	var err error
   285  
   286  	switch alg {
   287  	case RS256, RS384, RS512:
   288  		out, err = rsa.SignPKCS1v15(RandReader, ctx.privateKey, hash, hashed)
   289  	case PS256, PS384, PS512:
   290  		out, err = rsa.SignPSS(RandReader, ctx.privateKey, hash, hashed, &rsa.PSSOptions{
   291  			SaltLength: rsa.PSSSaltLengthEqualsHash,
   292  		})
   293  	}
   294  
   295  	if err != nil {
   296  		return Signature{}, err
   297  	}
   298  
   299  	return Signature{
   300  		Signature: out,
   301  		protected: &rawHeader{},
   302  	}, nil
   303  }
   304  
   305  // Verify the given payload
   306  func (ctx rsaEncrypterVerifier) verifyPayload(payload []byte, signature []byte, alg SignatureAlgorithm) error {
   307  	var hash crypto.Hash
   308  
   309  	switch alg {
   310  	case RS256, PS256:
   311  		hash = crypto.SHA256
   312  	case RS384, PS384:
   313  		hash = crypto.SHA384
   314  	case RS512, PS512:
   315  		hash = crypto.SHA512
   316  	default:
   317  		return ErrUnsupportedAlgorithm
   318  	}
   319  
   320  	hasher := hash.New()
   321  
   322  	// According to documentation, Write() on hash never fails
   323  	_, _ = hasher.Write(payload)
   324  	hashed := hasher.Sum(nil)
   325  
   326  	switch alg {
   327  	case RS256, RS384, RS512:
   328  		return rsa.VerifyPKCS1v15(ctx.publicKey, hash, hashed, signature)
   329  	case PS256, PS384, PS512:
   330  		return rsa.VerifyPSS(ctx.publicKey, hash, hashed, signature, nil)
   331  	}
   332  
   333  	return ErrUnsupportedAlgorithm
   334  }
   335  
   336  // Encrypt the given payload and update the object.
   337  func (ctx ecEncrypterVerifier) encryptKey(cek []byte, alg KeyAlgorithm) (recipientInfo, error) {
   338  	switch alg {
   339  	case ECDH_ES:
   340  		// ECDH-ES mode doesn't wrap a key, the shared secret is used directly as the key.
   341  		return recipientInfo{
   342  			header: &rawHeader{},
   343  		}, nil
   344  	case ECDH_ES_A128KW, ECDH_ES_A192KW, ECDH_ES_A256KW:
   345  	default:
   346  		return recipientInfo{}, ErrUnsupportedAlgorithm
   347  	}
   348  
   349  	generator := ecKeyGenerator{
   350  		algID:     string(alg),
   351  		publicKey: ctx.publicKey,
   352  	}
   353  
   354  	switch alg {
   355  	case ECDH_ES_A128KW:
   356  		generator.size = 16
   357  	case ECDH_ES_A192KW:
   358  		generator.size = 24
   359  	case ECDH_ES_A256KW:
   360  		generator.size = 32
   361  	}
   362  
   363  	kek, header, err := generator.genKey()
   364  	if err != nil {
   365  		return recipientInfo{}, err
   366  	}
   367  
   368  	block, err := aes.NewCipher(kek)
   369  	if err != nil {
   370  		return recipientInfo{}, err
   371  	}
   372  
   373  	jek, err := josecipher.KeyWrap(block, cek)
   374  	if err != nil {
   375  		return recipientInfo{}, err
   376  	}
   377  
   378  	return recipientInfo{
   379  		encryptedKey: jek,
   380  		header:       &header,
   381  	}, nil
   382  }
   383  
   384  // Get key size for EC key generator
   385  func (ctx ecKeyGenerator) keySize() int {
   386  	return ctx.size
   387  }
   388  
   389  // Get a content encryption key for ECDH-ES
   390  func (ctx ecKeyGenerator) genKey() ([]byte, rawHeader, error) {
   391  	priv, err := ecdsa.GenerateKey(ctx.publicKey.Curve, RandReader)
   392  	if err != nil {
   393  		return nil, rawHeader{}, err
   394  	}
   395  
   396  	out := josecipher.DeriveECDHES(ctx.algID, []byte{}, []byte{}, priv, ctx.publicKey, ctx.size)
   397  
   398  	b, err := json.Marshal(&JSONWebKey{
   399  		Key: &priv.PublicKey,
   400  	})
   401  	if err != nil {
   402  		return nil, nil, err
   403  	}
   404  
   405  	headers := rawHeader{
   406  		headerEPK: makeRawMessage(b),
   407  	}
   408  
   409  	return out, headers, nil
   410  }
   411  
   412  // Decrypt the given payload and return the content encryption key.
   413  func (ctx ecDecrypterSigner) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) {
   414  	epk, err := headers.getEPK()
   415  	if err != nil {
   416  		return nil, errors.New("square/go-jose: invalid epk header")
   417  	}
   418  	if epk == nil {
   419  		return nil, errors.New("square/go-jose: missing epk header")
   420  	}
   421  
   422  	publicKey, ok := epk.Key.(*ecdsa.PublicKey)
   423  	if publicKey == nil || !ok {
   424  		return nil, errors.New("square/go-jose: invalid epk header")
   425  	}
   426  
   427  	if !ctx.privateKey.Curve.IsOnCurve(publicKey.X, publicKey.Y) {
   428  		return nil, errors.New("square/go-jose: invalid public key in epk header")
   429  	}
   430  
   431  	apuData, err := headers.getAPU()
   432  	if err != nil {
   433  		return nil, errors.New("square/go-jose: invalid apu header")
   434  	}
   435  	apvData, err := headers.getAPV()
   436  	if err != nil {
   437  		return nil, errors.New("square/go-jose: invalid apv header")
   438  	}
   439  
   440  	deriveKey := func(algID string, size int) []byte {
   441  		return josecipher.DeriveECDHES(algID, apuData.bytes(), apvData.bytes(), ctx.privateKey, publicKey, size)
   442  	}
   443  
   444  	var keySize int
   445  
   446  	algorithm := headers.getAlgorithm()
   447  	switch algorithm {
   448  	case ECDH_ES:
   449  		// ECDH-ES uses direct key agreement, no key unwrapping necessary.
   450  		return deriveKey(string(headers.getEncryption()), generator.keySize()), nil
   451  	case ECDH_ES_A128KW:
   452  		keySize = 16
   453  	case ECDH_ES_A192KW:
   454  		keySize = 24
   455  	case ECDH_ES_A256KW:
   456  		keySize = 32
   457  	default:
   458  		return nil, ErrUnsupportedAlgorithm
   459  	}
   460  
   461  	key := deriveKey(string(algorithm), keySize)
   462  	block, err := aes.NewCipher(key)
   463  	if err != nil {
   464  		return nil, err
   465  	}
   466  
   467  	return josecipher.KeyUnwrap(block, recipient.encryptedKey)
   468  }
   469  
   470  func (ctx edDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) {
   471  	if alg != EdDSA {
   472  		return Signature{}, ErrUnsupportedAlgorithm
   473  	}
   474  
   475  	sig, err := ctx.privateKey.Sign(RandReader, payload, crypto.Hash(0))
   476  	if err != nil {
   477  		return Signature{}, err
   478  	}
   479  
   480  	return Signature{
   481  		Signature: sig,
   482  		protected: &rawHeader{},
   483  	}, nil
   484  }
   485  
   486  func (ctx edEncrypterVerifier) verifyPayload(payload []byte, signature []byte, alg SignatureAlgorithm) error {
   487  	if alg != EdDSA {
   488  		return ErrUnsupportedAlgorithm
   489  	}
   490  	ok := ed25519.Verify(ctx.publicKey, payload, signature)
   491  	if !ok {
   492  		return errors.New("square/go-jose: ed25519 signature failed to verify")
   493  	}
   494  	return nil
   495  }
   496  
   497  // Sign the given payload
   498  func (ctx ecDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) {
   499  	var expectedBitSize int
   500  	var hash crypto.Hash
   501  
   502  	switch alg {
   503  	case ES256:
   504  		expectedBitSize = 256
   505  		hash = crypto.SHA256
   506  	case ES384:
   507  		expectedBitSize = 384
   508  		hash = crypto.SHA384
   509  	case ES512:
   510  		expectedBitSize = 521
   511  		hash = crypto.SHA512
   512  	}
   513  
   514  	curveBits := ctx.privateKey.Curve.Params().BitSize
   515  	if expectedBitSize != curveBits {
   516  		return Signature{}, fmt.Errorf("square/go-jose: expected %d bit key, got %d bits instead", expectedBitSize, curveBits)
   517  	}
   518  
   519  	hasher := hash.New()
   520  
   521  	// According to documentation, Write() on hash never fails
   522  	_, _ = hasher.Write(payload)
   523  	hashed := hasher.Sum(nil)
   524  
   525  	r, s, err := ecdsa.Sign(RandReader, ctx.privateKey, hashed)
   526  	if err != nil {
   527  		return Signature{}, err
   528  	}
   529  
   530  	keyBytes := curveBits / 8
   531  	if curveBits%8 > 0 {
   532  		keyBytes++
   533  	}
   534  
   535  	// We serialize the outputs (r and s) into big-endian byte arrays and pad
   536  	// them with zeros on the left to make sure the sizes work out. Both arrays
   537  	// must be keyBytes long, and the output must be 2*keyBytes long.
   538  	rBytes := r.Bytes()
   539  	rBytesPadded := make([]byte, keyBytes)
   540  	copy(rBytesPadded[keyBytes-len(rBytes):], rBytes)
   541  
   542  	sBytes := s.Bytes()
   543  	sBytesPadded := make([]byte, keyBytes)
   544  	copy(sBytesPadded[keyBytes-len(sBytes):], sBytes)
   545  
   546  	out := append(rBytesPadded, sBytesPadded...)
   547  
   548  	return Signature{
   549  		Signature: out,
   550  		protected: &rawHeader{},
   551  	}, nil
   552  }
   553  
   554  // Verify the given payload
   555  func (ctx ecEncrypterVerifier) verifyPayload(payload []byte, signature []byte, alg SignatureAlgorithm) error {
   556  	var keySize int
   557  	var hash crypto.Hash
   558  
   559  	switch alg {
   560  	case ES256:
   561  		keySize = 32
   562  		hash = crypto.SHA256
   563  	case ES384:
   564  		keySize = 48
   565  		hash = crypto.SHA384
   566  	case ES512:
   567  		keySize = 66
   568  		hash = crypto.SHA512
   569  	default:
   570  		return ErrUnsupportedAlgorithm
   571  	}
   572  
   573  	if len(signature) != 2*keySize {
   574  		return fmt.Errorf("square/go-jose: invalid signature size, have %d bytes, wanted %d", len(signature), 2*keySize)
   575  	}
   576  
   577  	hasher := hash.New()
   578  
   579  	// According to documentation, Write() on hash never fails
   580  	_, _ = hasher.Write(payload)
   581  	hashed := hasher.Sum(nil)
   582  
   583  	r := big.NewInt(0).SetBytes(signature[:keySize])
   584  	s := big.NewInt(0).SetBytes(signature[keySize:])
   585  
   586  	match := ecdsa.Verify(ctx.publicKey, hashed, r, s)
   587  	if !match {
   588  		return errors.New("square/go-jose: ecdsa signature failed to verify")
   589  	}
   590  
   591  	return nil
   592  }
   593  

View as plain text