]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/rsa: add a test walking through every key size
authorFilippo Valsorda <filippo@golang.org>
Sat, 15 Oct 2022 10:06:48 +0000 (12:06 +0200)
committerGopher Robot <gobot@golang.org>
Tue, 15 Nov 2022 17:33:41 +0000 (17:33 +0000)
We already had some tests for special cases such as PSS with 513 bit
keys. The upcoming backend rewrite also happened to crash at 63 and 504
bits for different reasons. Might as well be systematic about it.

Also, make sure SignPSS returns ErrMessageTooLong like SignPKCS1v15 when
the key is too small, instead of panicking or returning an unnamed error.

-all takes a couple minutes on my M1.

Change-Id: I656239a00d0831fa7d187a6d3bb30341d41602f7
Reviewed-on: https://go-review.googlesource.com/c/go/+/443195
Reviewed-by: Roland Shoemaker <roland@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Joedian Reid <joedian@golang.org>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/crypto/rsa/pss.go
src/crypto/rsa/rsa.go
src/crypto/rsa/rsa_test.go

index a3e9bfc83ba29fe41f7d1c1af8c6637a01d2a3fa..fd9fc2ef587aee6ba01c6ecacff07f410079b215 100644 (file)
@@ -49,7 +49,7 @@ func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byt
        // 3.  If emLen < hLen + sLen + 2, output "encoding error" and stop.
 
        if emLen < hLen+sLen+2 {
-               return nil, errors.New("crypto/rsa: key size too small for PSS signature")
+               return nil, ErrMessageTooLong
        }
 
        em := make([]byte, emLen)
index 9c57595dd1abdf683e126153251d30db2fec440b..34218e5511b21d54a3c2437ed2d419775d12464d 100644 (file)
@@ -424,9 +424,10 @@ func mgf1XOR(out []byte, hash hash.Hash, seed []byte) {
        }
 }
 
-// ErrMessageTooLong is returned when attempting to encrypt a message which is
-// too large for the size of the public key.
-var ErrMessageTooLong = errors.New("crypto/rsa: message too long for RSA public key size")
+// ErrMessageTooLong is returned when attempting to encrypt or sign a message
+// which is too large for the size of the key. When using SignPSS, this can also
+// be returned if the size of the salt is too large.
+var ErrMessageTooLong = errors.New("crypto/rsa: message too long for RSA key size")
 
 func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int {
        boring.Unreachable()
index 400f40a031b1ed2b453dfe17e0f3e352f7475c25..0b1c8fb320b0a6e6bfb37c746e354bb38cb50cd2 100644 (file)
@@ -14,6 +14,7 @@ import (
        "crypto/sha256"
        "crypto/x509"
        "encoding/pem"
+       "flag"
        "fmt"
        "math/big"
        "strings"
@@ -135,6 +136,154 @@ func testKeyBasics(t *testing.T, priv *PrivateKey) {
        }
 }
 
+var allFlag = flag.Bool("all", false, "test all key sizes up to 2048")
+
+func TestEverything(t *testing.T) {
+       min := 32
+       max := 560 // any smaller than this and not all tests will run
+       if testing.Short() {
+               min = max
+       }
+       if *allFlag {
+               max = 2048
+       }
+       for size := min; size <= max; size++ {
+               t.Run(fmt.Sprintf("%d", size), func(t *testing.T) {
+                       t.Parallel()
+                       priv, err := GenerateKey(rand.Reader, size)
+                       if err != nil {
+                               t.Errorf("GenerateKey(%d): %v", size, err)
+                       }
+                       if bits := priv.N.BitLen(); bits != size {
+                               t.Errorf("key too short (%d vs %d)", bits, size)
+                       }
+                       testEverything(t, priv)
+               })
+       }
+}
+
+func testEverything(t *testing.T, priv *PrivateKey) {
+       if err := priv.Validate(); err != nil {
+               t.Errorf("Validate() failed: %s", err)
+       }
+
+       msg := []byte("test")
+       enc, err := EncryptPKCS1v15(rand.Reader, &priv.PublicKey, msg)
+       if err == ErrMessageTooLong {
+               t.Log("key too small for EncryptPKCS1v15")
+       } else if err != nil {
+               t.Errorf("EncryptPKCS1v15: %v", err)
+       }
+       if err == nil {
+               dec, err := DecryptPKCS1v15(nil, priv, enc)
+               if err != nil {
+                       t.Errorf("DecryptPKCS1v15: %v", err)
+               }
+               err = DecryptPKCS1v15SessionKey(nil, priv, enc, make([]byte, 4))
+               if err != nil {
+                       t.Errorf("DecryptPKCS1v15SessionKey: %v", err)
+               }
+               if !bytes.Equal(dec, msg) {
+                       t.Errorf("got:%x want:%x (%+v)", dec, msg, priv)
+               }
+       }
+
+       label := []byte("label")
+       enc, err = EncryptOAEP(sha256.New(), rand.Reader, &priv.PublicKey, msg, label)
+       if err == ErrMessageTooLong {
+               t.Log("key too small for EncryptOAEP")
+       } else if err != nil {
+               t.Errorf("EncryptOAEP: %v", err)
+       }
+       if err == nil {
+               dec, err := DecryptOAEP(sha256.New(), nil, priv, enc, label)
+               if err != nil {
+                       t.Errorf("DecryptOAEP: %v", err)
+               }
+               if !bytes.Equal(dec, msg) {
+                       t.Errorf("got:%x want:%x (%+v)", dec, msg, priv)
+               }
+       }
+
+       hash := sha256.Sum256(msg)
+       sig, err := SignPKCS1v15(nil, priv, crypto.SHA256, hash[:])
+       if err == ErrMessageTooLong {
+               t.Log("key too small for SignPKCS1v15")
+       } else if err != nil {
+               t.Errorf("SignPKCS1v15: %v", err)
+       }
+       if err == nil {
+               err = VerifyPKCS1v15(&priv.PublicKey, crypto.SHA256, hash[:], sig)
+               if err != nil {
+                       t.Errorf("VerifyPKCS1v15: %v", err)
+               }
+               sig[1] ^= 0x80
+               err = VerifyPKCS1v15(&priv.PublicKey, crypto.SHA256, hash[:], sig)
+               if err == nil {
+                       t.Errorf("VerifyPKCS1v15 success for tampered signature")
+               }
+               sig[1] ^= 0x80
+               hash[1] ^= 0x80
+               err = VerifyPKCS1v15(&priv.PublicKey, crypto.SHA256, hash[:], sig)
+               if err == nil {
+                       t.Errorf("VerifyPKCS1v15 success for tampered message")
+               }
+               hash[1] ^= 0x80
+       }
+
+       opts := &PSSOptions{SaltLength: PSSSaltLengthAuto}
+       sig, err = SignPSS(rand.Reader, priv, crypto.SHA256, hash[:], opts)
+       if err == ErrMessageTooLong {
+               t.Log("key too small for SignPSS with PSSSaltLengthAuto")
+       } else if err != nil {
+               t.Errorf("SignPSS: %v", err)
+       }
+       if err == nil {
+               err = VerifyPSS(&priv.PublicKey, crypto.SHA256, hash[:], sig, opts)
+               if err != nil {
+                       t.Errorf("VerifyPSS: %v", err)
+               }
+               sig[1] ^= 0x80
+               err = VerifyPSS(&priv.PublicKey, crypto.SHA256, hash[:], sig, opts)
+               if err == nil {
+                       t.Errorf("VerifyPSS success for tampered signature")
+               }
+               sig[1] ^= 0x80
+               hash[1] ^= 0x80
+               err = VerifyPSS(&priv.PublicKey, crypto.SHA256, hash[:], sig, opts)
+               if err == nil {
+                       t.Errorf("VerifyPSS success for tampered message")
+               }
+               hash[1] ^= 0x80
+       }
+
+       opts.SaltLength = PSSSaltLengthEqualsHash
+       sig, err = SignPSS(rand.Reader, priv, crypto.SHA256, hash[:], opts)
+       if err == ErrMessageTooLong {
+               t.Log("key too small for SignPSS with PSSSaltLengthEqualsHash")
+       } else if err != nil {
+               t.Errorf("SignPSS: %v", err)
+       }
+       if err == nil {
+               err = VerifyPSS(&priv.PublicKey, crypto.SHA256, hash[:], sig, opts)
+               if err != nil {
+                       t.Errorf("VerifyPSS: %v", err)
+               }
+               sig[1] ^= 0x80
+               err = VerifyPSS(&priv.PublicKey, crypto.SHA256, hash[:], sig, opts)
+               if err == nil {
+                       t.Errorf("VerifyPSS success for tampered signature")
+               }
+               sig[1] ^= 0x80
+               hash[1] ^= 0x80
+               err = VerifyPSS(&priv.PublicKey, crypto.SHA256, hash[:], sig, opts)
+               if err == nil {
+                       t.Errorf("VerifyPSS success for tampered message")
+               }
+               hash[1] ^= 0x80
+       }
+}
+
 func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") }
 
 func parseKey(s string) *PrivateKey {