You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by tw...@apache.org on 2025/09/21 10:52:20 UTC
(mina-sshd) 18/19: GH-502: Do not load built-in registrars reflectively
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) {