This is an automated email from the ASF dual-hosted git repository.

twolf pushed a commit to branch dev_3.0
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git

commit 44654f2735a8342b8875e382c0e9edb5b094d40a
Author: Thomas Wolf <tw...@apache.org>
AuthorDate: Sat Sep 20 21:53:13 2025 +0200

    GH-502: Do not load built-in registrars reflectively
    
    Instantiate them directly instead; after all the classes are right
    here in the same bundle.
---
 CHANGES.md                                         |  3 ++
 .../sshd/common/util/security/SecurityUtils.java   | 50 ++++++++++++++++------
 2 files changed, 39 insertions(+), 14 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 9af65f2b9..8a84b3012 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -21,6 +21,9 @@ Complete refactoring of the SSH transport protocol. New 
feature: support for cli
 
 ## Bug Fixes
 
+* [GH-502](https://github.com/apache/mina-sshd/issues/502) Don't load security 
provider classes reflectively
+  for Bouncy Castle and `net.isp.crypto:eddsa:0.3.0`.
+
 ## Major Code Re-factoring
 
 * The classes dealing with serializing or de-serializing public and private 
keys have been de-generified,
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java
index b3f621ae9..512c09066 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java
@@ -49,6 +49,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Predicate;
+import java.util.function.Supplier;
 
 import javax.crypto.Cipher;
 import javax.crypto.KeyAgreement;
@@ -74,6 +75,8 @@ import 
org.apache.sshd.common.util.security.bouncycastle.BouncyCastleEncryptedPr
 import 
org.apache.sshd.common.util.security.bouncycastle.BouncyCastleGeneratorHostKeyProvider;
 import 
org.apache.sshd.common.util.security.bouncycastle.BouncyCastleKeyPairResourceParser;
 import 
org.apache.sshd.common.util.security.bouncycastle.BouncyCastleRandomFactory;
+import 
org.apache.sshd.common.util.security.bouncycastle.BouncyCastleSecurityProviderRegistrar;
+import 
org.apache.sshd.common.util.security.eddsa.EdDSASecurityProviderRegistrar;
 import org.apache.sshd.common.util.security.eddsa.generic.EdDSAUtils;
 import 
org.apache.sshd.common.util.security.eddsa.generic.OpenSSHEd25519PrivateKeyEntryDecoder;
 import org.apache.sshd.common.util.security.eddsa.jce.JcePublicKeyFactory;
@@ -155,6 +158,8 @@ public final class SecurityUtils {
     private static final AtomicInteger MIN_DHG_KEY_SIZE_HOLDER = new 
AtomicInteger(0);
     private static final AtomicInteger MAX_DHG_KEY_SIZE_HOLDER = new 
AtomicInteger(0);
 
+    private static final Map<String, Supplier<SecurityProviderRegistrar>> 
REGISTRAR_FACTORIES = buildRegistrarsMap();
+
     /*
      * NOTE: we use a LinkedHashMap in order to preserve registration order in 
case several providers support the same
      * security entity
@@ -176,6 +181,19 @@ public final class SecurityUtils {
         throw new UnsupportedOperationException("No instance");
     }
 
+    private static Map<String, Supplier<SecurityProviderRegistrar>> 
buildRegistrarsMap() {
+        Map<String, Supplier<SecurityProviderRegistrar>> result = new 
HashMap<>();
+        
result.put("org.apache.sshd.common.util.security.SunJCESecurityProviderRegistrar",
+                SunJCESecurityProviderRegistrar::new);
+        
result.put("org.apache.sshd.common.util.security.SunECSecurityProviderRegistrar",
 //
+                SunECSecurityProviderRegistrar::new);
+        
result.put("org.apache.sshd.common.util.security.eddsa.EdDSASecurityProviderRegistrar",
+                EdDSASecurityProviderRegistrar::new);
+        
result.put("org.apache.sshd.common.util.security.bouncycastle.BouncyCastleSecurityProviderRegistrar",
+                BouncyCastleSecurityProviderRegistrar::new);
+        return Collections.unmodifiableMap(result);
+    }
+
     /**
      * Unconditionally set FIPS mode, overriding the {@link #FIPS_ENABLED} 
system property.
      *
@@ -423,22 +441,26 @@ public final class SecurityUtils {
                 boolean debugEnabled = logger.isDebugEnabled();
                 for (String registrarClass : classes) {
                     SecurityProviderRegistrar r;
-                    try {
-                        r = 
ThreadUtils.createDefaultInstance(SecurityUtils.class, 
SecurityProviderRegistrar.class,
-                                registrarClass);
-                    } catch (ReflectiveOperationException t) {
-                        Throwable e = ExceptionUtils.peelException(t);
-                        logger.error("Failed ({}) to create default {} 
registrar instance: {}",
-                                e.getClass().getSimpleName(), registrarClass, 
e.getMessage());
-                        if (e instanceof RuntimeException) {
-                            throw (RuntimeException) e;
-                        } else if (e instanceof Error) {
-                            throw (Error) e;
-                        } else {
-                            throw new IllegalStateException(e);
+                    Supplier<SecurityProviderRegistrar> factory = 
REGISTRAR_FACTORIES.get(registrarClass);
+                    if (factory != null) {
+                        r = factory.get();
+                    } else {
+                        try {
+                            r = 
ThreadUtils.createDefaultInstance(SecurityUtils.class, 
SecurityProviderRegistrar.class,
+                                    registrarClass);
+                        } catch (ReflectiveOperationException t) {
+                            Throwable e = ExceptionUtils.peelException(t);
+                            logger.error("Failed ({}) to create default {} 
registrar instance: {}",
+                                    e.getClass().getSimpleName(), 
registrarClass, e.getMessage());
+                            if (e instanceof RuntimeException) {
+                                throw (RuntimeException) e;
+                            } else if (e instanceof Error) {
+                                throw (Error) e;
+                            } else {
+                                throw new IllegalStateException(e);
+                            }
                         }
                     }
-
                     String name = r.getName();
                     SecurityProviderRegistrar registeredInstance = 
registerSecurityProvider(r);
                     if (registeredInstance == null) {

Reply via email to