Skip to content

Commit 44654f2

Browse files
committed
GH-502: Do not load built-in registrars reflectively
Instantiate them directly instead; after all the classes are right here in the same bundle.
1 parent 49ddb23 commit 44654f2

2 files changed

Lines changed: 39 additions & 14 deletions

File tree

CHANGES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ Complete refactoring of the SSH transport protocol. New feature: support for cli
2121

2222
## Bug Fixes
2323

24+
* [GH-502](https://github.com/apache/mina-sshd/issues/502) Don't load security provider classes reflectively
25+
for Bouncy Castle and `net.isp.crypto:eddsa:0.3.0`.
26+
2427
## Major Code Re-factoring
2528

2629
* The classes dealing with serializing or de-serializing public and private keys have been de-generified,

sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import java.util.concurrent.atomic.AtomicInteger;
5050
import java.util.concurrent.atomic.AtomicReference;
5151
import java.util.function.Predicate;
52+
import java.util.function.Supplier;
5253

5354
import javax.crypto.Cipher;
5455
import javax.crypto.KeyAgreement;
@@ -74,6 +75,8 @@
7475
import org.apache.sshd.common.util.security.bouncycastle.BouncyCastleGeneratorHostKeyProvider;
7576
import org.apache.sshd.common.util.security.bouncycastle.BouncyCastleKeyPairResourceParser;
7677
import org.apache.sshd.common.util.security.bouncycastle.BouncyCastleRandomFactory;
78+
import org.apache.sshd.common.util.security.bouncycastle.BouncyCastleSecurityProviderRegistrar;
79+
import org.apache.sshd.common.util.security.eddsa.EdDSASecurityProviderRegistrar;
7780
import org.apache.sshd.common.util.security.eddsa.generic.EdDSAUtils;
7881
import org.apache.sshd.common.util.security.eddsa.generic.OpenSSHEd25519PrivateKeyEntryDecoder;
7982
import org.apache.sshd.common.util.security.eddsa.jce.JcePublicKeyFactory;
@@ -155,6 +158,8 @@ public final class SecurityUtils {
155158
private static final AtomicInteger MIN_DHG_KEY_SIZE_HOLDER = new AtomicInteger(0);
156159
private static final AtomicInteger MAX_DHG_KEY_SIZE_HOLDER = new AtomicInteger(0);
157160

161+
private static final Map<String, Supplier<SecurityProviderRegistrar>> REGISTRAR_FACTORIES = buildRegistrarsMap();
162+
158163
/*
159164
* NOTE: we use a LinkedHashMap in order to preserve registration order in case several providers support the same
160165
* security entity
@@ -176,6 +181,19 @@ private SecurityUtils() {
176181
throw new UnsupportedOperationException("No instance");
177182
}
178183

184+
private static Map<String, Supplier<SecurityProviderRegistrar>> buildRegistrarsMap() {
185+
Map<String, Supplier<SecurityProviderRegistrar>> result = new HashMap<>();
186+
result.put("org.apache.sshd.common.util.security.SunJCESecurityProviderRegistrar",
187+
SunJCESecurityProviderRegistrar::new);
188+
result.put("org.apache.sshd.common.util.security.SunECSecurityProviderRegistrar", //
189+
SunECSecurityProviderRegistrar::new);
190+
result.put("org.apache.sshd.common.util.security.eddsa.EdDSASecurityProviderRegistrar",
191+
EdDSASecurityProviderRegistrar::new);
192+
result.put("org.apache.sshd.common.util.security.bouncycastle.BouncyCastleSecurityProviderRegistrar",
193+
BouncyCastleSecurityProviderRegistrar::new);
194+
return Collections.unmodifiableMap(result);
195+
}
196+
179197
/**
180198
* Unconditionally set FIPS mode, overriding the {@link #FIPS_ENABLED} system property.
181199
*
@@ -423,22 +441,26 @@ private static void register() {
423441
boolean debugEnabled = logger.isDebugEnabled();
424442
for (String registrarClass : classes) {
425443
SecurityProviderRegistrar r;
426-
try {
427-
r = ThreadUtils.createDefaultInstance(SecurityUtils.class, SecurityProviderRegistrar.class,
428-
registrarClass);
429-
} catch (ReflectiveOperationException t) {
430-
Throwable e = ExceptionUtils.peelException(t);
431-
logger.error("Failed ({}) to create default {} registrar instance: {}",
432-
e.getClass().getSimpleName(), registrarClass, e.getMessage());
433-
if (e instanceof RuntimeException) {
434-
throw (RuntimeException) e;
435-
} else if (e instanceof Error) {
436-
throw (Error) e;
437-
} else {
438-
throw new IllegalStateException(e);
444+
Supplier<SecurityProviderRegistrar> factory = REGISTRAR_FACTORIES.get(registrarClass);
445+
if (factory != null) {
446+
r = factory.get();
447+
} else {
448+
try {
449+
r = ThreadUtils.createDefaultInstance(SecurityUtils.class, SecurityProviderRegistrar.class,
450+
registrarClass);
451+
} catch (ReflectiveOperationException t) {
452+
Throwable e = ExceptionUtils.peelException(t);
453+
logger.error("Failed ({}) to create default {} registrar instance: {}",
454+
e.getClass().getSimpleName(), registrarClass, e.getMessage());
455+
if (e instanceof RuntimeException) {
456+
throw (RuntimeException) e;
457+
} else if (e instanceof Error) {
458+
throw (Error) e;
459+
} else {
460+
throw new IllegalStateException(e);
461+
}
439462
}
440463
}
441-
442464
String name = r.getName();
443465
SecurityProviderRegistrar registeredInstance = registerSecurityProvider(r);
444466
if (registeredInstance == null) {

0 commit comments

Comments
 (0)