]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/rsa: support unpadded signatures.
authorAdam Langley <agl@golang.org>
Mon, 6 Jan 2014 21:11:58 +0000 (16:11 -0500)
committerAdam Langley <agl@golang.org>
Mon, 6 Jan 2014 21:11:58 +0000 (16:11 -0500)
Usually when a message is signed it's first hashed because RSA has low
limits on the size of messages that it can sign. However, some
protocols sign short messages directly. This isn't a great idea because
the messages that can be signed suddenly depend on the size of the RSA
key, but several people on golang-nuts have requested support for
this and it's very easy to do.

R=golang-codereviews, rsc
CC=golang-codereviews
https://golang.org/cl/44400043

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

index 1a055a3d623c251e24f24a056d2ede50b0c7ae20..cf174b6a21dbe8d4bd6b2e92bebc3d25f68158d8 100644 (file)
@@ -176,7 +176,8 @@ var hashPrefixes = map[crypto.Hash][]byte{
 
 // SignPKCS1v15 calculates the signature of hashed using RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5.
 // Note that hashed must be the result of hashing the input message using the
-// given hash function.
+// given hash function. If hash is zero, hashed is signed directly. This isn't
+// advisable except for interoperability.
 func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err error) {
        hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
        if err != nil {
@@ -212,7 +213,8 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b
 // VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature.
 // hashed is the result of hashing the input message using the given hash
 // function and sig is the signature. A valid signature is indicated by
-// returning a nil error.
+// returning a nil error. If hash is zero then hashed is used directly. This
+// isn't advisable except for interopability.
 func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err error) {
        hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
        if err != nil {
@@ -249,6 +251,12 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte)
 }
 
 func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err error) {
+       // Special case: crypto.Hash(0) is used to indicate that the data is
+       // signed directly.
+       if hash == 0 {
+               return inLen, nil, nil
+       }
+
        hashLen = hash.Size()
        if inLen != hashLen {
                return 0, nil, errors.New("crypto/rsa: input must be hashed message")
index 70bb2288996907b7034746d181050f663ddd950e..37c14d1d949b471e4a66cecfb65b2b38bbaa9c57 100644 (file)
@@ -205,6 +205,28 @@ func TestOverlongMessagePKCS1v15(t *testing.T) {
        }
 }
 
+func TestUnpaddedSignature(t *testing.T) {
+       msg := []byte("Thu Dec 19 18:06:16 EST 2013\n")
+       // This base64 value was generated with:
+       // % echo Thu Dec 19 18:06:16 EST 2013 > /tmp/msg
+       // % openssl rsautl -sign -inkey key -out /tmp/sig -in /tmp/msg
+       //
+       // Where "key" contains the RSA private key given at the bottom of this
+       // file.
+       expectedSig := decodeBase64("pX4DR8azytjdQ1rtUiC040FjkepuQut5q2ZFX1pTjBrOVKNjgsCDyiJDGZTCNoh9qpXYbhl7iEym30BWWwuiZg==")
+
+       sig, err := SignPKCS1v15(nil, rsaPrivateKey, crypto.Hash(0), msg)
+       if err != nil {
+               t.Fatalf("SignPKCS1v15 failed: %s", err)
+       }
+       if !bytes.Equal(sig, expectedSig) {
+               t.Fatalf("signature is not expected value: got %x, want %x", sig, expectedSig)
+       }
+       if err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.Hash(0), msg, sig); err != nil {
+               t.Fatalf("signature failed to verify: %s", err)
+       }
+}
+
 // In order to generate new test vectors you'll need the PEM form of this key:
 // -----BEGIN RSA PRIVATE KEY-----
 // MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0