123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593 |
- /*-
- * 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"
- josecipher "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: staticPublicKey(&JSONWebKey{
- Key: privateKey.Public(),
- }),
- 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: staticPublicKey(&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: staticPublicKey(&JSONWebKey{
- Key: privateKey.Public(),
- }),
- 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.PSSSaltLengthEqualsHash,
- })
- }
- 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 outputs (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
- }
|