diff --git a/evp.go b/evp.go index ff07f5f..e1f0409 100644 --- a/evp.go +++ b/evp.go @@ -45,6 +45,14 @@ func hashToMD(h hash.Hash) C.GO_EVP_MD_PTR { return nil } +func evp_md5_sha1() C.GO_EVP_MD_PTR { + if vMajor == 1 && vMinor == 0 { + return C.go_openssl_EVP_md5_sha1_backport() + } else { + return C.go_openssl_EVP_md5_sha1() + } +} + // cryptoHashToMD converts a crypto.Hash to a GO_EVP_MD_PTR. func cryptoHashToMD(ch crypto.Hash) (md C.GO_EVP_MD_PTR) { if v, ok := cacheMD.Load(ch); ok { @@ -76,17 +84,9 @@ func cryptoHashToMD(ch crypto.Hash) (md C.GO_EVP_MD_PTR) { } cacheMD.Store(ch, md) }() - // SupportsHash returns false for MD5SHA1 because we don't - // provide a hash.Hash implementation for it. Yet, it can - // still be used when signing/verifying with an RSA key. - if ch == crypto.MD5SHA1 { - if vMajor == 1 && vMinor == 0 { - return C.go_openssl_EVP_md5_sha1_backport() - } else { - return C.go_openssl_EVP_md5_sha1() - } - } switch ch { + case crypto.MD5SHA1: + return evp_md5_sha1() case crypto.MD4: return C.go_openssl_EVP_md4() case crypto.MD5: @@ -265,7 +265,14 @@ func setupEVP(withKey withKeyFunc, padding C.int, // We support unhashed messages. md := cryptoHashToMD(ch) if md == nil { - return nil, errors.New("crypto/rsa: unsupported hash function") + if ch == crypto.MD5SHA1 { + // Most providers will special-case MD5SHA1 to support it in RSA PKCS1 signatures, + // as it is used in TLS 1.0 and 1.1. Try to use it even if EVP_MD_fetch says it is not supported. + // Worst case, user will see the EVP_PKEY_CTX_ctrl error message instead of the one just below. + md = evp_md5_sha1() + } else { + return nil, errors.New("crypto/rsa: unsupported hash function") + } } if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, -1, -1, C.GO_EVP_PKEY_CTRL_MD, 0, unsafe.Pointer(md)) != 1 { return nil, newOpenSSLError("EVP_PKEY_CTX_ctrl failed") diff --git a/rsa_test.go b/rsa_test.go index c926e9c..f4b98b4 100644 --- a/rsa_test.go +++ b/rsa_test.go @@ -147,6 +147,28 @@ func TestSignVerifyPKCS1v15(t *testing.T) { } } +func TestSignVerifyPKCS1v15_MD5SHA1(t *testing.T) { + priv, pub := newRSAKey(t, 2048) + + // Construct a fake MD5+SHA1 hash. + hashed := make([]byte, crypto.MD5.Size()+crypto.SHA1.Size()) + hashed[0] = 0x30 + + signed, err := openssl.SignRSAPKCS1v15(priv, crypto.MD5SHA1, hashed) + if err != nil { + if openssl.FIPS() { + // This test is not supported in FIPS mode, but at least we + // can check that we don't panic (which we did before when using SOOSSL). + t.Skip("skipping test in FIPS mode") + } + t.Fatal(err) + } + err = openssl.VerifyRSAPKCS1v15(pub, crypto.MD5SHA1, hashed, signed) + if err != nil { + t.Fatal(err) + } +} + func TestSignVerifyPKCS1v15_Unhashed(t *testing.T) { msg := []byte("hi!") priv, pub := newRSAKey(t, 2048)