mirror of
				https://github.com/StackExchange/dnscontrol.git
				synced 2024-05-11 05:55:12 +00:00 
			
		
		
		
	
		
			
	
	
		
			592 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			592 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|  | /*-
 | ||
|  |  * Copyright 2014 Square Inc.
 | ||
|  |  *
 | ||
|  |  * Licensed under the Apache License, Version 2.0 (the "License");
 | ||
|  |  * you may not use this file except in compliance with the License.
 | ||
|  |  * You may obtain a copy of the License at
 | ||
|  |  *
 | ||
|  |  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||
|  |  *
 | ||
|  |  * Unless required by applicable law or agreed to in writing, software
 | ||
|  |  * distributed under the License is distributed on an "AS IS" BASIS,
 | ||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||
|  |  * See the License for the specific language governing permissions and
 | ||
|  |  * limitations under the License.
 | ||
|  |  */
 | ||
|  | 
 | ||
|  | package jose
 | ||
|  | 
 | ||
|  | import (
 | ||
|  | 	"crypto"
 | ||
|  | 	"crypto/aes"
 | ||
|  | 	"crypto/ecdsa"
 | ||
|  | 	"crypto/rand"
 | ||
|  | 	"crypto/rsa"
 | ||
|  | 	"crypto/sha1"
 | ||
|  | 	"crypto/sha256"
 | ||
|  | 	"errors"
 | ||
|  | 	"fmt"
 | ||
|  | 	"math/big"
 | ||
|  | 
 | ||
|  | 	"golang.org/x/crypto/ed25519"
 | ||
|  | 	"gopkg.in/square/go-jose.v2/cipher"
 | ||
|  | 	"gopkg.in/square/go-jose.v2/json"
 | ||
|  | )
 | ||
|  | 
 | ||
|  | // A generic RSA-based encrypter/verifier
 | ||
|  | type rsaEncrypterVerifier struct {
 | ||
|  | 	publicKey *rsa.PublicKey
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // A generic RSA-based decrypter/signer
 | ||
|  | type rsaDecrypterSigner struct {
 | ||
|  | 	privateKey *rsa.PrivateKey
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // A generic EC-based encrypter/verifier
 | ||
|  | type ecEncrypterVerifier struct {
 | ||
|  | 	publicKey *ecdsa.PublicKey
 | ||
|  | }
 | ||
|  | 
 | ||
|  | type edEncrypterVerifier struct {
 | ||
|  | 	publicKey ed25519.PublicKey
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // A key generator for ECDH-ES
 | ||
|  | type ecKeyGenerator struct {
 | ||
|  | 	size      int
 | ||
|  | 	algID     string
 | ||
|  | 	publicKey *ecdsa.PublicKey
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // A generic EC-based decrypter/signer
 | ||
|  | type ecDecrypterSigner struct {
 | ||
|  | 	privateKey *ecdsa.PrivateKey
 | ||
|  | }
 | ||
|  | 
 | ||
|  | type edDecrypterSigner struct {
 | ||
|  | 	privateKey ed25519.PrivateKey
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // newRSARecipient creates recipientKeyInfo based on the given key.
 | ||
|  | func newRSARecipient(keyAlg KeyAlgorithm, publicKey *rsa.PublicKey) (recipientKeyInfo, error) {
 | ||
|  | 	// Verify that key management algorithm is supported by this encrypter
 | ||
|  | 	switch keyAlg {
 | ||
|  | 	case RSA1_5, RSA_OAEP, RSA_OAEP_256:
 | ||
|  | 	default:
 | ||
|  | 		return recipientKeyInfo{}, ErrUnsupportedAlgorithm
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	if publicKey == nil {
 | ||
|  | 		return recipientKeyInfo{}, errors.New("invalid public key")
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	return recipientKeyInfo{
 | ||
|  | 		keyAlg: keyAlg,
 | ||
|  | 		keyEncrypter: &rsaEncrypterVerifier{
 | ||
|  | 			publicKey: publicKey,
 | ||
|  | 		},
 | ||
|  | 	}, nil
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // newRSASigner creates a recipientSigInfo based on the given key.
 | ||
|  | func newRSASigner(sigAlg SignatureAlgorithm, privateKey *rsa.PrivateKey) (recipientSigInfo, error) {
 | ||
|  | 	// Verify that key management algorithm is supported by this encrypter
 | ||
|  | 	switch sigAlg {
 | ||
|  | 	case RS256, RS384, RS512, PS256, PS384, PS512:
 | ||
|  | 	default:
 | ||
|  | 		return recipientSigInfo{}, ErrUnsupportedAlgorithm
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	if privateKey == nil {
 | ||
|  | 		return recipientSigInfo{}, errors.New("invalid private key")
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	return recipientSigInfo{
 | ||
|  | 		sigAlg: sigAlg,
 | ||
|  | 		publicKey: &JSONWebKey{
 | ||
|  | 			Key: &privateKey.PublicKey,
 | ||
|  | 		},
 | ||
|  | 		signer: &rsaDecrypterSigner{
 | ||
|  | 			privateKey: privateKey,
 | ||
|  | 		},
 | ||
|  | 	}, nil
 | ||
|  | }
 | ||
|  | 
 | ||
|  | func newEd25519Signer(sigAlg SignatureAlgorithm, privateKey ed25519.PrivateKey) (recipientSigInfo, error) {
 | ||
|  | 	if sigAlg != EdDSA {
 | ||
|  | 		return recipientSigInfo{}, ErrUnsupportedAlgorithm
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	if privateKey == nil {
 | ||
|  | 		return recipientSigInfo{}, errors.New("invalid private key")
 | ||
|  | 	}
 | ||
|  | 	return recipientSigInfo{
 | ||
|  | 		sigAlg: sigAlg,
 | ||
|  | 		publicKey: &JSONWebKey{
 | ||
|  | 			Key: privateKey.Public(),
 | ||
|  | 		},
 | ||
|  | 		signer: &edDecrypterSigner{
 | ||
|  | 			privateKey: privateKey,
 | ||
|  | 		},
 | ||
|  | 	}, nil
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // newECDHRecipient creates recipientKeyInfo based on the given key.
 | ||
|  | func newECDHRecipient(keyAlg KeyAlgorithm, publicKey *ecdsa.PublicKey) (recipientKeyInfo, error) {
 | ||
|  | 	// Verify that key management algorithm is supported by this encrypter
 | ||
|  | 	switch keyAlg {
 | ||
|  | 	case ECDH_ES, ECDH_ES_A128KW, ECDH_ES_A192KW, ECDH_ES_A256KW:
 | ||
|  | 	default:
 | ||
|  | 		return recipientKeyInfo{}, ErrUnsupportedAlgorithm
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	if publicKey == nil || !publicKey.Curve.IsOnCurve(publicKey.X, publicKey.Y) {
 | ||
|  | 		return recipientKeyInfo{}, errors.New("invalid public key")
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	return recipientKeyInfo{
 | ||
|  | 		keyAlg: keyAlg,
 | ||
|  | 		keyEncrypter: &ecEncrypterVerifier{
 | ||
|  | 			publicKey: publicKey,
 | ||
|  | 		},
 | ||
|  | 	}, nil
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // newECDSASigner creates a recipientSigInfo based on the given key.
 | ||
|  | func newECDSASigner(sigAlg SignatureAlgorithm, privateKey *ecdsa.PrivateKey) (recipientSigInfo, error) {
 | ||
|  | 	// Verify that key management algorithm is supported by this encrypter
 | ||
|  | 	switch sigAlg {
 | ||
|  | 	case ES256, ES384, ES512:
 | ||
|  | 	default:
 | ||
|  | 		return recipientSigInfo{}, ErrUnsupportedAlgorithm
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	if privateKey == nil {
 | ||
|  | 		return recipientSigInfo{}, errors.New("invalid private key")
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	return recipientSigInfo{
 | ||
|  | 		sigAlg: sigAlg,
 | ||
|  | 		publicKey: &JSONWebKey{
 | ||
|  | 			Key: &privateKey.PublicKey,
 | ||
|  | 		},
 | ||
|  | 		signer: &ecDecrypterSigner{
 | ||
|  | 			privateKey: privateKey,
 | ||
|  | 		},
 | ||
|  | 	}, nil
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // Encrypt the given payload and update the object.
 | ||
|  | func (ctx rsaEncrypterVerifier) encryptKey(cek []byte, alg KeyAlgorithm) (recipientInfo, error) {
 | ||
|  | 	encryptedKey, err := ctx.encrypt(cek, alg)
 | ||
|  | 	if err != nil {
 | ||
|  | 		return recipientInfo{}, err
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	return recipientInfo{
 | ||
|  | 		encryptedKey: encryptedKey,
 | ||
|  | 		header:       &rawHeader{},
 | ||
|  | 	}, nil
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // Encrypt the given payload. Based on the key encryption algorithm,
 | ||
|  | // this will either use RSA-PKCS1v1.5 or RSA-OAEP (with SHA-1 or SHA-256).
 | ||
|  | func (ctx rsaEncrypterVerifier) encrypt(cek []byte, alg KeyAlgorithm) ([]byte, error) {
 | ||
|  | 	switch alg {
 | ||
|  | 	case RSA1_5:
 | ||
|  | 		return rsa.EncryptPKCS1v15(randReader, ctx.publicKey, cek)
 | ||
|  | 	case RSA_OAEP:
 | ||
|  | 		return rsa.EncryptOAEP(sha1.New(), randReader, ctx.publicKey, cek, []byte{})
 | ||
|  | 	case RSA_OAEP_256:
 | ||
|  | 		return rsa.EncryptOAEP(sha256.New(), randReader, ctx.publicKey, cek, []byte{})
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	return nil, ErrUnsupportedAlgorithm
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // Decrypt the given payload and return the content encryption key.
 | ||
|  | func (ctx rsaDecrypterSigner) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) {
 | ||
|  | 	return ctx.decrypt(recipient.encryptedKey, headers.getAlgorithm(), generator)
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // Decrypt the given payload. Based on the key encryption algorithm,
 | ||
|  | // this will either use RSA-PKCS1v1.5 or RSA-OAEP (with SHA-1 or SHA-256).
 | ||
|  | func (ctx rsaDecrypterSigner) decrypt(jek []byte, alg KeyAlgorithm, generator keyGenerator) ([]byte, error) {
 | ||
|  | 	// Note: The random reader on decrypt operations is only used for blinding,
 | ||
|  | 	// so stubbing is meanlingless (hence the direct use of rand.Reader).
 | ||
|  | 	switch alg {
 | ||
|  | 	case RSA1_5:
 | ||
|  | 		defer func() {
 | ||
|  | 			// DecryptPKCS1v15SessionKey sometimes panics on an invalid payload
 | ||
|  | 			// because of an index out of bounds error, which we want to ignore.
 | ||
|  | 			// This has been fixed in Go 1.3.1 (released 2014/08/13), the recover()
 | ||
|  | 			// only exists for preventing crashes with unpatched versions.
 | ||
|  | 			// See: https://groups.google.com/forum/#!topic/golang-dev/7ihX6Y6kx9k
 | ||
|  | 			// See: https://code.google.com/p/go/source/detail?r=58ee390ff31602edb66af41ed10901ec95904d33
 | ||
|  | 			_ = recover()
 | ||
|  | 		}()
 | ||
|  | 
 | ||
|  | 		// Perform some input validation.
 | ||
|  | 		keyBytes := ctx.privateKey.PublicKey.N.BitLen() / 8
 | ||
|  | 		if keyBytes != len(jek) {
 | ||
|  | 			// Input size is incorrect, the encrypted payload should always match
 | ||
|  | 			// the size of the public modulus (e.g. using a 2048 bit key will
 | ||
|  | 			// produce 256 bytes of output). Reject this since it's invalid input.
 | ||
|  | 			return nil, ErrCryptoFailure
 | ||
|  | 		}
 | ||
|  | 
 | ||
|  | 		cek, _, err := generator.genKey()
 | ||
|  | 		if err != nil {
 | ||
|  | 			return nil, ErrCryptoFailure
 | ||
|  | 		}
 | ||
|  | 
 | ||
|  | 		// When decrypting an RSA-PKCS1v1.5 payload, we must take precautions to
 | ||
|  | 		// prevent chosen-ciphertext attacks as described in RFC 3218, "Preventing
 | ||
|  | 		// the Million Message Attack on Cryptographic Message Syntax". We are
 | ||
|  | 		// therefore deliberately ignoring errors here.
 | ||
|  | 		_ = rsa.DecryptPKCS1v15SessionKey(rand.Reader, ctx.privateKey, jek, cek)
 | ||
|  | 
 | ||
|  | 		return cek, nil
 | ||
|  | 	case RSA_OAEP:
 | ||
|  | 		// Use rand.Reader for RSA blinding
 | ||
|  | 		return rsa.DecryptOAEP(sha1.New(), rand.Reader, ctx.privateKey, jek, []byte{})
 | ||
|  | 	case RSA_OAEP_256:
 | ||
|  | 		// Use rand.Reader for RSA blinding
 | ||
|  | 		return rsa.DecryptOAEP(sha256.New(), rand.Reader, ctx.privateKey, jek, []byte{})
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	return nil, ErrUnsupportedAlgorithm
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // Sign the given payload
 | ||
|  | func (ctx rsaDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) {
 | ||
|  | 	var hash crypto.Hash
 | ||
|  | 
 | ||
|  | 	switch alg {
 | ||
|  | 	case RS256, PS256:
 | ||
|  | 		hash = crypto.SHA256
 | ||
|  | 	case RS384, PS384:
 | ||
|  | 		hash = crypto.SHA384
 | ||
|  | 	case RS512, PS512:
 | ||
|  | 		hash = crypto.SHA512
 | ||
|  | 	default:
 | ||
|  | 		return Signature{}, ErrUnsupportedAlgorithm
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	hasher := hash.New()
 | ||
|  | 
 | ||
|  | 	// According to documentation, Write() on hash never fails
 | ||
|  | 	_, _ = hasher.Write(payload)
 | ||
|  | 	hashed := hasher.Sum(nil)
 | ||
|  | 
 | ||
|  | 	var out []byte
 | ||
|  | 	var err error
 | ||
|  | 
 | ||
|  | 	switch alg {
 | ||
|  | 	case RS256, RS384, RS512:
 | ||
|  | 		out, err = rsa.SignPKCS1v15(randReader, ctx.privateKey, hash, hashed)
 | ||
|  | 	case PS256, PS384, PS512:
 | ||
|  | 		out, err = rsa.SignPSS(randReader, ctx.privateKey, hash, hashed, &rsa.PSSOptions{
 | ||
|  | 			SaltLength: rsa.PSSSaltLengthAuto,
 | ||
|  | 		})
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	if err != nil {
 | ||
|  | 		return Signature{}, err
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	return Signature{
 | ||
|  | 		Signature: out,
 | ||
|  | 		protected: &rawHeader{},
 | ||
|  | 	}, nil
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // Verify the given payload
 | ||
|  | func (ctx rsaEncrypterVerifier) verifyPayload(payload []byte, signature []byte, alg SignatureAlgorithm) error {
 | ||
|  | 	var hash crypto.Hash
 | ||
|  | 
 | ||
|  | 	switch alg {
 | ||
|  | 	case RS256, PS256:
 | ||
|  | 		hash = crypto.SHA256
 | ||
|  | 	case RS384, PS384:
 | ||
|  | 		hash = crypto.SHA384
 | ||
|  | 	case RS512, PS512:
 | ||
|  | 		hash = crypto.SHA512
 | ||
|  | 	default:
 | ||
|  | 		return ErrUnsupportedAlgorithm
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	hasher := hash.New()
 | ||
|  | 
 | ||
|  | 	// According to documentation, Write() on hash never fails
 | ||
|  | 	_, _ = hasher.Write(payload)
 | ||
|  | 	hashed := hasher.Sum(nil)
 | ||
|  | 
 | ||
|  | 	switch alg {
 | ||
|  | 	case RS256, RS384, RS512:
 | ||
|  | 		return rsa.VerifyPKCS1v15(ctx.publicKey, hash, hashed, signature)
 | ||
|  | 	case PS256, PS384, PS512:
 | ||
|  | 		return rsa.VerifyPSS(ctx.publicKey, hash, hashed, signature, nil)
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	return ErrUnsupportedAlgorithm
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // Encrypt the given payload and update the object.
 | ||
|  | func (ctx ecEncrypterVerifier) encryptKey(cek []byte, alg KeyAlgorithm) (recipientInfo, error) {
 | ||
|  | 	switch alg {
 | ||
|  | 	case ECDH_ES:
 | ||
|  | 		// ECDH-ES mode doesn't wrap a key, the shared secret is used directly as the key.
 | ||
|  | 		return recipientInfo{
 | ||
|  | 			header: &rawHeader{},
 | ||
|  | 		}, nil
 | ||
|  | 	case ECDH_ES_A128KW, ECDH_ES_A192KW, ECDH_ES_A256KW:
 | ||
|  | 	default:
 | ||
|  | 		return recipientInfo{}, ErrUnsupportedAlgorithm
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	generator := ecKeyGenerator{
 | ||
|  | 		algID:     string(alg),
 | ||
|  | 		publicKey: ctx.publicKey,
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	switch alg {
 | ||
|  | 	case ECDH_ES_A128KW:
 | ||
|  | 		generator.size = 16
 | ||
|  | 	case ECDH_ES_A192KW:
 | ||
|  | 		generator.size = 24
 | ||
|  | 	case ECDH_ES_A256KW:
 | ||
|  | 		generator.size = 32
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	kek, header, err := generator.genKey()
 | ||
|  | 	if err != nil {
 | ||
|  | 		return recipientInfo{}, err
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	block, err := aes.NewCipher(kek)
 | ||
|  | 	if err != nil {
 | ||
|  | 		return recipientInfo{}, err
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	jek, err := josecipher.KeyWrap(block, cek)
 | ||
|  | 	if err != nil {
 | ||
|  | 		return recipientInfo{}, err
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	return recipientInfo{
 | ||
|  | 		encryptedKey: jek,
 | ||
|  | 		header:       &header,
 | ||
|  | 	}, nil
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // Get key size for EC key generator
 | ||
|  | func (ctx ecKeyGenerator) keySize() int {
 | ||
|  | 	return ctx.size
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // Get a content encryption key for ECDH-ES
 | ||
|  | func (ctx ecKeyGenerator) genKey() ([]byte, rawHeader, error) {
 | ||
|  | 	priv, err := ecdsa.GenerateKey(ctx.publicKey.Curve, randReader)
 | ||
|  | 	if err != nil {
 | ||
|  | 		return nil, rawHeader{}, err
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	out := josecipher.DeriveECDHES(ctx.algID, []byte{}, []byte{}, priv, ctx.publicKey, ctx.size)
 | ||
|  | 
 | ||
|  | 	b, err := json.Marshal(&JSONWebKey{
 | ||
|  | 		Key: &priv.PublicKey,
 | ||
|  | 	})
 | ||
|  | 	if err != nil {
 | ||
|  | 		return nil, nil, err
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	headers := rawHeader{
 | ||
|  | 		headerEPK: makeRawMessage(b),
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	return out, headers, nil
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // Decrypt the given payload and return the content encryption key.
 | ||
|  | func (ctx ecDecrypterSigner) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) {
 | ||
|  | 	epk, err := headers.getEPK()
 | ||
|  | 	if err != nil {
 | ||
|  | 		return nil, errors.New("square/go-jose: invalid epk header")
 | ||
|  | 	}
 | ||
|  | 	if epk == nil {
 | ||
|  | 		return nil, errors.New("square/go-jose: missing epk header")
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	publicKey, ok := epk.Key.(*ecdsa.PublicKey)
 | ||
|  | 	if publicKey == nil || !ok {
 | ||
|  | 		return nil, errors.New("square/go-jose: invalid epk header")
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	if !ctx.privateKey.Curve.IsOnCurve(publicKey.X, publicKey.Y) {
 | ||
|  | 		return nil, errors.New("square/go-jose: invalid public key in epk header")
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	apuData, err := headers.getAPU()
 | ||
|  | 	if err != nil {
 | ||
|  | 		return nil, errors.New("square/go-jose: invalid apu header")
 | ||
|  | 	}
 | ||
|  | 	apvData, err := headers.getAPV()
 | ||
|  | 	if err != nil {
 | ||
|  | 		return nil, errors.New("square/go-jose: invalid apv header")
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	deriveKey := func(algID string, size int) []byte {
 | ||
|  | 		return josecipher.DeriveECDHES(algID, apuData.bytes(), apvData.bytes(), ctx.privateKey, publicKey, size)
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	var keySize int
 | ||
|  | 
 | ||
|  | 	algorithm := headers.getAlgorithm()
 | ||
|  | 	switch algorithm {
 | ||
|  | 	case ECDH_ES:
 | ||
|  | 		// ECDH-ES uses direct key agreement, no key unwrapping necessary.
 | ||
|  | 		return deriveKey(string(headers.getEncryption()), generator.keySize()), nil
 | ||
|  | 	case ECDH_ES_A128KW:
 | ||
|  | 		keySize = 16
 | ||
|  | 	case ECDH_ES_A192KW:
 | ||
|  | 		keySize = 24
 | ||
|  | 	case ECDH_ES_A256KW:
 | ||
|  | 		keySize = 32
 | ||
|  | 	default:
 | ||
|  | 		return nil, ErrUnsupportedAlgorithm
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	key := deriveKey(string(algorithm), keySize)
 | ||
|  | 	block, err := aes.NewCipher(key)
 | ||
|  | 	if err != nil {
 | ||
|  | 		return nil, err
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	return josecipher.KeyUnwrap(block, recipient.encryptedKey)
 | ||
|  | }
 | ||
|  | func (ctx edDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) {
 | ||
|  | 	if alg != EdDSA {
 | ||
|  | 		return Signature{}, ErrUnsupportedAlgorithm
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	sig, err := ctx.privateKey.Sign(randReader, payload, crypto.Hash(0))
 | ||
|  | 	if err != nil {
 | ||
|  | 		return Signature{}, err
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	return Signature{
 | ||
|  | 		Signature: sig,
 | ||
|  | 		protected: &rawHeader{},
 | ||
|  | 	}, nil
 | ||
|  | }
 | ||
|  | 
 | ||
|  | func (ctx edEncrypterVerifier) verifyPayload(payload []byte, signature []byte, alg SignatureAlgorithm) error {
 | ||
|  | 	if alg != EdDSA {
 | ||
|  | 		return ErrUnsupportedAlgorithm
 | ||
|  | 	}
 | ||
|  | 	ok := ed25519.Verify(ctx.publicKey, payload, signature)
 | ||
|  | 	if !ok {
 | ||
|  | 		return errors.New("square/go-jose: ed25519 signature failed to verify")
 | ||
|  | 	}
 | ||
|  | 	return nil
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // Sign the given payload
 | ||
|  | func (ctx ecDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) {
 | ||
|  | 	var expectedBitSize int
 | ||
|  | 	var hash crypto.Hash
 | ||
|  | 
 | ||
|  | 	switch alg {
 | ||
|  | 	case ES256:
 | ||
|  | 		expectedBitSize = 256
 | ||
|  | 		hash = crypto.SHA256
 | ||
|  | 	case ES384:
 | ||
|  | 		expectedBitSize = 384
 | ||
|  | 		hash = crypto.SHA384
 | ||
|  | 	case ES512:
 | ||
|  | 		expectedBitSize = 521
 | ||
|  | 		hash = crypto.SHA512
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	curveBits := ctx.privateKey.Curve.Params().BitSize
 | ||
|  | 	if expectedBitSize != curveBits {
 | ||
|  | 		return Signature{}, fmt.Errorf("square/go-jose: expected %d bit key, got %d bits instead", expectedBitSize, curveBits)
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	hasher := hash.New()
 | ||
|  | 
 | ||
|  | 	// According to documentation, Write() on hash never fails
 | ||
|  | 	_, _ = hasher.Write(payload)
 | ||
|  | 	hashed := hasher.Sum(nil)
 | ||
|  | 
 | ||
|  | 	r, s, err := ecdsa.Sign(randReader, ctx.privateKey, hashed)
 | ||
|  | 	if err != nil {
 | ||
|  | 		return Signature{}, err
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	keyBytes := curveBits / 8
 | ||
|  | 	if curveBits%8 > 0 {
 | ||
|  | 		keyBytes++
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	// We serialize the outpus (r and s) into big-endian byte arrays and pad
 | ||
|  | 	// them with zeros on the left to make sure the sizes work out. Both arrays
 | ||
|  | 	// must be keyBytes long, and the output must be 2*keyBytes long.
 | ||
|  | 	rBytes := r.Bytes()
 | ||
|  | 	rBytesPadded := make([]byte, keyBytes)
 | ||
|  | 	copy(rBytesPadded[keyBytes-len(rBytes):], rBytes)
 | ||
|  | 
 | ||
|  | 	sBytes := s.Bytes()
 | ||
|  | 	sBytesPadded := make([]byte, keyBytes)
 | ||
|  | 	copy(sBytesPadded[keyBytes-len(sBytes):], sBytes)
 | ||
|  | 
 | ||
|  | 	out := append(rBytesPadded, sBytesPadded...)
 | ||
|  | 
 | ||
|  | 	return Signature{
 | ||
|  | 		Signature: out,
 | ||
|  | 		protected: &rawHeader{},
 | ||
|  | 	}, nil
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // Verify the given payload
 | ||
|  | func (ctx ecEncrypterVerifier) verifyPayload(payload []byte, signature []byte, alg SignatureAlgorithm) error {
 | ||
|  | 	var keySize int
 | ||
|  | 	var hash crypto.Hash
 | ||
|  | 
 | ||
|  | 	switch alg {
 | ||
|  | 	case ES256:
 | ||
|  | 		keySize = 32
 | ||
|  | 		hash = crypto.SHA256
 | ||
|  | 	case ES384:
 | ||
|  | 		keySize = 48
 | ||
|  | 		hash = crypto.SHA384
 | ||
|  | 	case ES512:
 | ||
|  | 		keySize = 66
 | ||
|  | 		hash = crypto.SHA512
 | ||
|  | 	default:
 | ||
|  | 		return ErrUnsupportedAlgorithm
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	if len(signature) != 2*keySize {
 | ||
|  | 		return fmt.Errorf("square/go-jose: invalid signature size, have %d bytes, wanted %d", len(signature), 2*keySize)
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	hasher := hash.New()
 | ||
|  | 
 | ||
|  | 	// According to documentation, Write() on hash never fails
 | ||
|  | 	_, _ = hasher.Write(payload)
 | ||
|  | 	hashed := hasher.Sum(nil)
 | ||
|  | 
 | ||
|  | 	r := big.NewInt(0).SetBytes(signature[:keySize])
 | ||
|  | 	s := big.NewInt(0).SetBytes(signature[keySize:])
 | ||
|  | 
 | ||
|  | 	match := ecdsa.Verify(ctx.publicKey, hashed, r, s)
 | ||
|  | 	if !match {
 | ||
|  | 		return errors.New("square/go-jose: ecdsa signature failed to verify")
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	return nil
 | ||
|  | }
 |