From 5e8787847fa13ceecd9a7b51058f7621b51f25ec Mon Sep 17 00:00:00 2001 From: Mattias Reichel Date: Thu, 29 Oct 2026 15:08:02 +0100 Subject: [PATCH] [fix] clear BouncyCastle's thread properties on load CryptoServicesRegistrar's static initializer also stores its default DSA and DH parameters in a thread-local of the thread that initializes it (bcgit/bc-java#2536). That thread then kept BouncyCastle's class loader alive, and with it the class loader of an embedded JRuby. Lookups fall back to the global values, so clear the thread's copies. --- src/main/java/org/jruby/ext/openssl/OpenSSL.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/org/jruby/ext/openssl/OpenSSL.java b/src/main/java/org/jruby/ext/openssl/OpenSSL.java index deda814d..9fc6cf33 100644 --- a/src/main/java/org/jruby/ext/openssl/OpenSSL.java +++ b/src/main/java/org/jruby/ext/openssl/OpenSSL.java @@ -27,6 +27,7 @@ import java.security.SecureRandom; import java.util.Map; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.util.Arrays; import org.jruby.*; import org.jruby.anno.JRubyMethod; @@ -72,11 +73,23 @@ static void doLoad(final Ruby runtime, final boolean fipsGem) { SecurityHelper.setFipsVariant(fipsGem); SecurityHelper.checkAndRegisterProviderOnce(); LoggingSupport.silenceBouncyCastleLoggers(); + clearBouncyCastleThreadProperties(); createOpenSSL(runtime); loaded = true; } + /** + * BouncyCastle's {@code CryptoServicesRegistrar} sets its default DSA and DH parameters globally, and in a + * thread-local for the thread that initializes it (bcgit/bc-java#2536). That thread then keeps BouncyCastle's class + * loader alive for as long as it lives, and with it the class loader of an embedded JRuby. Lookups fall back to the + * global values, so the thread's copies can go. This also initializes the registrar on this thread, if needed. + */ + private static void clearBouncyCastleThreadProperties() { + CryptoServicesRegistrar.clearThreadProperty(CryptoServicesRegistrar.Property.DSA_DEFAULT_PARAMS); + CryptoServicesRegistrar.clearThreadProperty(CryptoServicesRegistrar.Property.DH_DEFAULT_PARAMS); + } + public static boolean isLoaded() { return loaded; }