From a6db0fab63d2c5217bf1d0380c6c32fe7ccb1629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C5=8Dan?= Date: Fri, 3 Apr 2026 05:21:53 -0600 Subject: [PATCH] =?UTF-8?q?refactor:=20eliminate=20duplicate=20NID?= =?UTF-8?q?=E2=86=92name=20table=20in=20get=5Fmessage=5Fdigest()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On OpenSSL 3.x, get_message_digest() duplicated the NID→algorithm-name switch already present in get_md_bynid(). A new hash added to one table but not the other would cause sign/verify to silently diverge. Replace the 3.x switch in get_message_digest() with a call to get_md_bynid() + EVP_Digest(), making get_md_bynid() the single source of truth for NID→algorithm mapping. Pre-3.x path is unchanged. As a side effect, fixes whirlpool on OpenSSL 3.x: the old code fell through to WHIRLPOOL() (deprecated low-level API), now uses the correct EVP_MD_fetch() path via get_md_bynid(). Fixes https://github.com/cpan-authors/Crypt-OpenSSL-RSA/issues/153 Co-Authored-By: Claude Sonnet 4.6 --- RSA.xs | 37 +++++++++++-------------------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/RSA.xs b/RSA.xs index c6e80af..3d143b4 100644 --- a/RSA.xs +++ b/RSA.xs @@ -220,33 +220,18 @@ unsigned char* get_message_digest(SV* text_SV, int hash_method, unsigned char* m unsigned char* text; text = (unsigned char*) SvPV(text_SV, text_length); - switch(hash_method) - { #if OPENSSL_VERSION_NUMBER >= 0x30000000L - case NID_md5: - return EVP_Q_digest(NULL, "MD5", NULL, text, text_length, md, NULL) ? md : NULL; - break; - case NID_sha1: - return EVP_Q_digest(NULL, "SHA1", NULL, text, text_length, md, NULL) ? md : NULL; - break; -#ifdef SHA512_DIGEST_LENGTH - case NID_sha224: - return EVP_Q_digest(NULL, "SHA224", NULL, text, text_length, md, NULL) ? md : NULL; - break; - case NID_sha256: - return EVP_Q_digest(NULL, "SHA256", NULL, text, text_length, md, NULL) ? md : NULL; - break; - case NID_sha384: - return EVP_Q_digest(NULL, "SHA384", NULL, text, text_length, md, NULL) ? md : NULL; - break; - case NID_sha512: - return EVP_Q_digest(NULL, "SHA512", NULL, text, text_length, md, NULL) ? md : NULL; - break; -#endif - case NID_ripemd160: - return EVP_Q_digest(NULL, "RIPEMD160", NULL, text, text_length, md, NULL) ? md : NULL; - break; + /* Delegate NID→name lookup to get_md_bynid() — single source of truth. */ + { + EVP_MD *md_obj = get_md_bynid(hash_method); /* croak()s on unknown NID */ + unsigned int result_len; + int ok = EVP_Digest(text, text_length, md, &result_len, md_obj, NULL); + EVP_MD_free(md_obj); + return ok ? md : NULL; + } #else + switch(hash_method) + { case NID_md5: return MD5(text, text_length, md); break; @@ -270,7 +255,6 @@ unsigned char* get_message_digest(SV* text_SV, int hash_method, unsigned char* m case NID_ripemd160: return RIPEMD160(text, text_length, md); break; -#endif #ifdef WHIRLPOOL_DIGEST_LENGTH case NID_whirlpool: return WHIRLPOOL(text, text_length, md); @@ -280,6 +264,7 @@ unsigned char* get_message_digest(SV* text_SV, int hash_method, unsigned char* m croak("Unknown digest hash mode %u", hash_method); break; } +#endif } SV* cor_bn2sv(const BIGNUM* p_bn)