From ec8b7ed51710d195b1a762ef3b052e0fa0c5da8b Mon Sep 17 00:00:00 2001 From: qmuntal Date: Tue, 26 Nov 2024 16:50:16 +0000 Subject: [PATCH] support MD5HA1 in PKCS1 v1.5 signatures --- evp.go | 29 ++++++++++++++++++----------- rsa_test.go | 22 ++++++++++++++++++++++ 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/evp.go b/evp.go index ff07f5f5..e1f0409c 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 1d2c2cab..4dc4f6ef 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) + + // Manually hash the message with MD5-SHA1. + md5, sha1 := openssl.NewMD5(), openssl.NewSHA1() + md5sha1 := make([]byte, md5.Size()+sha1.Size()) + msg := []byte("hi!") + md5.Write(msg) + sha1.Write(msg) + copy(md5sha1, md5.Sum(nil)) + copy(md5sha1[md5.Size():], sha1.Sum(nil)) + + signed, err := openssl.SignRSAPKCS1v15(priv, crypto.MD5SHA1, md5sha1) + if err != nil { + t.Fatal(err) + } + err = openssl.VerifyRSAPKCS1v15(pub, crypto.MD5SHA1, md5sha1, signed) + if err != nil { + t.Fatal(err) + } +} + func TestSignVerifyPKCS1v15_Unhashed(t *testing.T) { msg := []byte("hi!") priv, pub := newRSAKey(t, 2048)