]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Fix] cryptobox: bypass RHEL/CentOS 10 crypto-policies for SHA-1 DKIM verification
authorVsevolod Stakhov <vsevolod@rspamd.com>
Thu, 29 Jan 2026 10:41:15 +0000 (10:41 +0000)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Thu, 29 Jan 2026 10:41:15 +0000 (10:41 +0000)
RHEL/CentOS 10+ crypto-policies disable SHA-1 for signatures by default,
causing rsa-sha1 DKIM verification to fail. This is problematic as many
legitimate emails still use rsa-sha1 DKIM signatures.

For OpenSSL 3.0+, create a dedicated OSSL_LIB_CTX that bypasses system
crypto-policies specifically for SHA-1 DKIM signature verification.
SHA-256/SHA-512 verifications continue using the normal system context.

The legacy context is lazily initialized only when SHA-1 verification
is needed, avoiding overhead for modern rsa-sha256 signatures.

src/libcryptobox/cryptobox.c

index ab7d35c7a9ef708de6fc32ed64e7f953b676c3e4..086a7eedcb25b6f9e200e631b8e05a933f400a7f 100644 (file)
 #include <openssl/evp.h>
 #include <openssl/rsa.h>
 #include <openssl/err.h>
+#include <openssl/obj_mac.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/provider.h>
+#endif
 #endif
 
 #include <signal.h>
@@ -53,6 +57,17 @@ unsigned cpu_config = 0;
 
 static gboolean cryptobox_loaded = FALSE;
 
+#if defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x30000000L
+/*
+ * Dedicated OpenSSL library context for DKIM SHA-1 signature verification.
+ * RHEL/CentOS 10+ crypto-policies disable SHA-1 for signatures by default,
+ * but DKIM signatures using rsa-sha1 are still common in the wild.
+ * This context bypasses system restrictions for legacy digest verification only.
+ */
+static OSSL_LIB_CTX *rspamd_legacy_ssl_ctx = NULL;
+static OSSL_PROVIDER *rspamd_legacy_ssl_provider = NULL;
+#endif
+
 static const unsigned char n0[16] = {0};
 
 #define CRYPTOBOX_ALIGNMENT 16
@@ -367,6 +382,18 @@ void rspamd_cryptobox_deinit(struct rspamd_cryptobox_library_ctx *ctx)
                g_free(ctx->cpu_extensions);
                g_free(ctx);
                cryptobox_loaded = FALSE;
+
+#if defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x30000000L
+               /* Cleanup legacy SSL context used for SHA-1 DKIM verification */
+               if (rspamd_legacy_ssl_provider != NULL) {
+                       OSSL_PROVIDER_unload(rspamd_legacy_ssl_provider);
+                       rspamd_legacy_ssl_provider = NULL;
+               }
+               if (rspamd_legacy_ssl_ctx != NULL) {
+                       OSSL_LIB_CTX_free(rspamd_legacy_ssl_ctx);
+                       rspamd_legacy_ssl_ctx = NULL;
+               }
+#endif
        }
 }
 
@@ -462,11 +489,45 @@ bool rspamd_cryptobox_verify_evp_rsa(int nid,
                                                                         GError **err)
 {
        bool ret = false, r;
+       EVP_PKEY_CTX *pctx;
+       const EVP_MD *md;
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+       /*
+        * For SHA-1 signatures, use a dedicated library context that bypasses
+        * system crypto-policies (RHEL/CentOS 10+ disable SHA-1 for signatures).
+        * For SHA-256/SHA-512, use the normal system context.
+        */
+       if (nid == NID_sha1) {
+               /* Lazy initialization of legacy context for SHA-1 */
+               if (rspamd_legacy_ssl_ctx == NULL) {
+                       rspamd_legacy_ssl_ctx = OSSL_LIB_CTX_new();
+                       if (rspamd_legacy_ssl_ctx != NULL) {
+                               rspamd_legacy_ssl_provider = OSSL_PROVIDER_load(rspamd_legacy_ssl_ctx, "default");
+                       }
+               }
+
+               if (rspamd_legacy_ssl_ctx != NULL) {
+                       pctx = EVP_PKEY_CTX_new_from_pkey(rspamd_legacy_ssl_ctx, pub_key, NULL);
+                       md = EVP_MD_fetch(rspamd_legacy_ssl_ctx, "SHA1", NULL);
+               }
+               else {
+                       /* Fallback if context creation failed */
+                       pctx = EVP_PKEY_CTX_new(pub_key, NULL);
+                       md = EVP_get_digestbynid(nid);
+               }
+       }
+       else {
+               pctx = EVP_PKEY_CTX_new(pub_key, NULL);
+               md = EVP_get_digestbynid(nid);
+       }
+#else
+       pctx = EVP_PKEY_CTX_new(pub_key, NULL);
+       md = EVP_get_digestbynid(nid);
+#endif
 
-       EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pub_key, NULL);
        g_assert(pctx != NULL);
        EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
-       const EVP_MD *md = EVP_get_digestbynid(nid);
 
        g_assert(EVP_PKEY_verify_init(pctx) == 1);
        g_assert(EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) == 1);
@@ -479,7 +540,11 @@ bool rspamd_cryptobox_verify_evp_rsa(int nid,
                                        ERR_lib_error_string(ERR_get_error()));
                EVP_PKEY_CTX_free(pctx);
                EVP_MD_CTX_free(mdctx);
-
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+               if (nid == NID_sha1 && md != NULL) {
+                       EVP_MD_free((EVP_MD *) md);
+               }
+#endif
                return false;
        }
 
@@ -487,6 +552,11 @@ bool rspamd_cryptobox_verify_evp_rsa(int nid,
 
        EVP_PKEY_CTX_free(pctx);
        EVP_MD_CTX_free(mdctx);
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+       if (nid == NID_sha1 && md != NULL) {
+               EVP_MD_free((EVP_MD *) md);
+       }
+#endif
 
        return ret;
 }