]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/rsa: reject PublicKey.E if it won't fit in a 32-bit int
authorRuss Cox <rsc@golang.org>
Thu, 13 Sep 2012 14:47:01 +0000 (10:47 -0400)
committerRuss Cox <rsc@golang.org>
Thu, 13 Sep 2012 14:47:01 +0000 (10:47 -0400)
Right now we only have 32-bit ints so that's a no-op.
Took the opportunity to check for some other invalid values too.
Suggestions for additions or modifications welcome.

R=agl
CC=golang-dev
https://golang.org/cl/6493112

src/pkg/crypto/rsa/pkcs1v15.go
src/pkg/crypto/rsa/rsa.go

index 53ded16c1ce42bd3e417046228b2e7a2eacba2fe..28ca5d73b39cfb715de8620c7dc8dcc3f6f5d32c 100644 (file)
@@ -19,6 +19,9 @@ import (
 // WARNING: use of this function to encrypt plaintexts other than session keys
 // is dangerous. Use RSA OAEP in new protocols.
 func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, err error) {
+       if err := checkPub(pub); err != nil {
+               return nil, err
+       }
        k := (pub.N.BitLen() + 7) / 8
        if len(msg) > k-11 {
                err = ErrMessageTooLong
@@ -47,6 +50,9 @@ func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, er
 // DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5.
 // If rand != nil, it uses RSA blinding to avoid timing side-channel attacks.
 func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out []byte, err error) {
+       if err := checkPub(&priv.PublicKey); err != nil {
+               return nil, err
+       }
        valid, out, err := decryptPKCS1v15(rand, priv, ciphertext)
        if err == nil && valid == 0 {
                err = ErrDecryption
@@ -69,6 +75,9 @@ func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out [
 // Encryption Standard PKCS #1'', Daniel Bleichenbacher, Advances in Cryptology
 // (Crypto '98).
 func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) (err error) {
+       if err := checkPub(&priv.PublicKey); err != nil {
+               return err
+       }
        k := (priv.N.BitLen() + 7) / 8
        if k-(len(key)+3+8) < 0 {
                err = ErrDecryption
index c041ca80333eb61cc71e342d2ff8b3f2c19c300b..7faae67430441771092cd5fc4d25e41c45bedfe7 100644 (file)
@@ -25,6 +25,30 @@ type PublicKey struct {
        E int      // public exponent
 }
 
+var (
+       errPublicModulus       = errors.New("crypto/rsa: missing public modulus")
+       errPublicExponentSmall = errors.New("crypto/rsa: public exponent too small")
+       errPublicExponentLarge = errors.New("crypto/rsa: public exponent too large")
+)
+
+// checkPub sanity checks the public key before we use it.
+// We require pub.E to fit into a 32-bit integer so that we
+// do not have different behavior depending on whether
+// int is 32 or 64 bits. See also
+// http://www.imperialviolet.org/2012/03/16/rsae.html.
+func checkPub(pub *PublicKey) error {
+       if pub.N == nil {
+               return errPublicModulus
+       }
+       if pub.E < 2 {
+               return errPublicExponentSmall
+       }
+       if pub.E > 1<<31-1 {
+               return errPublicExponentLarge
+       }
+       return nil
+}
+
 // A PrivateKey represents an RSA key
 type PrivateKey struct {
        PublicKey            // public part.
@@ -57,6 +81,10 @@ type CRTValue struct {
 // Validate performs basic sanity checks on the key.
 // It returns nil if the key is valid, or else an error describing a problem.
 func (priv *PrivateKey) Validate() error {
+       if err := checkPub(&priv.PublicKey); err != nil {
+               return err
+       }
+
        // Check that the prime factors are actually prime. Note that this is
        // just a sanity check. Since the random witnesses chosen by
        // ProbablyPrime are deterministic, given the candidate number, it's
@@ -216,6 +244,9 @@ func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int {
 // The message must be no longer than the length of the public modulus less
 // twice the hash length plus 2.
 func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err error) {
+       if err := checkPub(pub); err != nil {
+               return nil, err
+       }
        hash.Reset()
        k := (pub.N.BitLen() + 7) / 8
        if len(msg) > k-2*hash.Size()-2 {
@@ -402,6 +433,9 @@ func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err er
 // DecryptOAEP decrypts ciphertext using RSA-OAEP.
 // If random != nil, DecryptOAEP uses RSA blinding to avoid timing side-channel attacks.
 func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err error) {
+       if err := checkPub(&priv.PublicKey); err != nil {
+               return nil, err
+       }
        k := (priv.N.BitLen() + 7) / 8
        if len(ciphertext) > k ||
                k < hash.Size()*2+2 {