Repository: mina-sshd
Updated Branches:
  refs/heads/master 8cf57bc08 -> ab72900ff


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ab72900f/sshd-core/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java
 
b/sshd-core/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java
index 9ea871d..62b9e3b 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java
@@ -32,20 +32,25 @@ import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
 import java.security.PrivateKey;
-import java.security.Provider;
 import java.security.PublicKey;
 import java.security.Signature;
 import java.security.cert.CertificateFactory;
 import java.security.spec.InvalidKeySpecException;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.TreeSet;
-import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Predicate;
 
 import javax.crypto.Cipher;
 import javax.crypto.KeyAgreement;
@@ -63,7 +68,6 @@ import org.apache.sshd.common.keyprovider.KeyPairProvider;
 import org.apache.sshd.common.random.JceRandomFactory;
 import org.apache.sshd.common.random.RandomFactory;
 import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.ReflectionUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.buffer.Buffer;
 import 
org.apache.sshd.common.util.security.bouncycastle.BouncyCastleGeneratorHostKeyProvider;
@@ -72,7 +76,6 @@ import 
org.apache.sshd.common.util.security.bouncycastle.BouncyCastleRandomFacto
 import org.apache.sshd.common.util.security.eddsa.EdDSASecurityProvider;
 import org.apache.sshd.common.util.threads.ThreadUtils;
 import org.apache.sshd.server.keyprovider.AbstractGeneratorHostKeyProvider;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -92,6 +95,9 @@ public final class SecurityUtils {
      */
     public static final String EDDSA = "EdDSA";
 
+    // A copy-paste from the original, but we don't want to drag the classes 
into the classpath
+    public static final String CURVE_ED25519_SHA512 = "ed25519-sha-512";
+
     /**
      * System property used to configure the value for the maximum supported 
Diffie-Hellman
      * Group Exchange key size. If not set, then an internal auto-discovery 
mechanism is employed.
@@ -114,9 +120,23 @@ public final class SecurityUtils {
     public static final int MAX_DHGEX_KEY_SIZE = 8192;
 
     /**
+     * Comma separated list of fully qualified {@link 
SecurityProviderRegistrar}s
+     * to automatically register
+     */
+    public static final String SECURITY_PROVIDER_REGISTRARS = 
"org.apache.sshd.security.registrars";
+    public static final List<String> DEFAULT_SECURITY_PROVIDER_REGISTRARS =
+            Collections.unmodifiableList(
+                    Arrays.asList(
+                            
"org.apache.sshd.common.util.security.bouncycastle.BouncyCastleSecurityProviderRegistrar",
+                            
"org.apache.sshd.common.util.security.eddsa.EdDSASecurityProviderRegistrar"));
+
+
+    /**
      * System property used to control whether to automatically register the
      * {@code Bouncyastle} JCE provider
+     * @deprecated Please use 
&quot;org.apache.sshd.security.provider.BC.enabled&quot;
      */
+    @Deprecated
     public static final String REGISTER_BOUNCY_CASTLE_PROP = 
"org.apache.sshd.registerBouncyCastle";
 
     /**
@@ -131,29 +151,82 @@ public final class SecurityUtils {
      * (in addition or even in spite of {@link #isEDDSACurveSupported()}). If 
not
      * set or set to {@code true}, then the existence of the optional support 
classes
      * determines the support.
+     * @deprecated Please use 
&quot;org.apache.sshd.security.provider.EdDSA.enabled&qupt;
      */
+    @Deprecated
     public static final String EDDSA_SUPPORTED_PROP = 
"org.apache.sshd.eddsaSupport";
 
+    public static final String PROP_DEFAULT_SECURITY_PROVIDER = 
"org.apache.sshd.security.defaultProvider";
+
     private static final AtomicInteger MAX_DHG_KEY_SIZE_HOLDER = new 
AtomicInteger(0);
 
-    private static final Map<String, Provider> REGISTERED_PROVIDERS = new 
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+    /*
+     * NOTE: we use a LinkedHashMap in order to preserve registration order
+     * in case several providers support the same security entity
+     */
+    private static final Map<String, SecurityProviderRegistrar> 
REGISTERED_PROVIDERS = new LinkedHashMap<>();
     private static final AtomicReference<KeyPairResourceParser> 
KEYPAIRS_PARSER_HODLER = new AtomicReference<>();
+    // If an entry already exists for the named provider, then it overrides 
its SecurityProviderRegistrar#isEnabled()
+    private static final Set<String> APRIORI_DISABLED_PROVIDERS = new 
TreeSet<>();
+    private static final AtomicBoolean REGISTRATION_STATE_HOLDER = new 
AtomicBoolean(false);
+    private static final Map<Class<?>, Map<String, SecurityEntityFactory<?>>> 
SECURITY_ENTITY_FACTORIES = new HashMap<>();
+
+    private static final AtomicReference<SecurityProviderChoice> 
DEFAULT_PROVIDER_HOLDER = new AtomicReference<>();
 
-    private static String defaultProvider;
-    private static Boolean registerBouncyCastle;
-    private static boolean registrationDone;
     private static Boolean hasEcc;
-    private static Boolean eddsaSupported;
 
     private SecurityUtils() {
         throw new UnsupportedOperationException("No instance");
     }
 
     /**
+     * @param name The provider's name - never {@code null}/empty
+     * @return {@code true} if the provider is marked as disabled a-priori
+     * @see #setAPrioriDisabledProvider(String, boolean)
+     */
+    public static boolean isAPrioriDisabledProvider(String name) {
+        ValidateUtils.checkNotNullAndNotEmpty(name, "No provider name 
specified");
+        synchronized (APRIORI_DISABLED_PROVIDERS) {
+            return APRIORI_DISABLED_PROVIDERS.contains(name);
+        }
+    }
+
+    /**
+     * Marks a provider's registrar as &quot;a-priori&quot; 
<U>programatically</U>
+     * so that when its {@link SecurityProviderRegistrar#isEnabled()} is 
eventually
+     * consulted it will return {@code false} regardless of the configured 
value for
+     * the specific provider registrar instance. <B>Note:</B> has no effect if 
the
+     * provider has already been registered.
+     *
+     * @param name The provider's name - never {@code null}/empty
+     * @param disabled {@code true} whether to disable it a-priori
+     * @see #isAPrioriDisabledProvider(String)
+     */
+    public static void setAPrioriDisabledProvider(String name, boolean 
disabled) {
+        ValidateUtils.checkNotNullAndNotEmpty(name, "No provider name 
specified");
+        synchronized (APRIORI_DISABLED_PROVIDERS) {
+            if (disabled) {
+                APRIORI_DISABLED_PROVIDERS.add(name);
+            } else {
+                APRIORI_DISABLED_PROVIDERS.remove(name);
+            }
+        }
+    }
+
+    /**
+     * @return A <U>copy</U> if the current a-priori disabled providers names
+     */
+    public static Set<String> getAPrioriDisabledProviders() {
+        synchronized (APRIORI_DISABLED_PROVIDERS) {
+            return new TreeSet<>(APRIORI_DISABLED_PROVIDERS);
+        }
+    }
+
+    /**
      * @return {@code true} if Elliptic Curve Cryptography is supported
      * @see #ECC_SUPPORTED_PROP
      */
-    public static boolean hasEcc() {
+    public static boolean isECCSupported() {
         if (hasEcc == null) {
             String propValue = System.getProperty(ECC_SUPPORTED_PROP);
             if (GenericUtils.isEmpty(propValue)) {
@@ -253,121 +326,144 @@ public final class SecurityUtils {
         }
     }
 
-    public static synchronized void setRegisterBouncyCastle(boolean 
registerBouncyCastle) {
-        SecurityUtils.registerBouncyCastle = registerBouncyCastle;
-        registrationDone = false;
-    }
+    public static SecurityProviderChoice getDefaultProviderChoice() {
+        SecurityProviderChoice choice;
+        synchronized (DEFAULT_PROVIDER_HOLDER) {
+            choice = DEFAULT_PROVIDER_HOLDER.get();
+            if (choice != null) {
+                return choice;
+            }
 
-    public static synchronized String getDefaultProvider() {
-        return defaultProvider;
+            String name = System.getProperty(PROP_DEFAULT_SECURITY_PROVIDER);
+            choice = (GenericUtils.isEmpty(name) || 
"none".equalsIgnoreCase(name))
+                    ? SecurityProviderChoice.EMPTY
+                    : SecurityProviderChoice.toSecurityProviderChoice(name);
+            DEFAULT_PROVIDER_HOLDER.set(choice);
+        }
+
+        return choice;
     }
 
-    public static synchronized void setDefaultProvider(String provider) {
-        defaultProvider = provider;
-        registrationDone = false;
+    public static void setDefaultProviderChoice(SecurityProviderChoice choice) 
{
+        DEFAULT_PROVIDER_HOLDER.set(choice);
     }
 
     /**
      * @return A <U>copy</U> of the currently registered security providers
      */
-    public static synchronized Set<String> getRegisteredProviders() {
-        register();
-
+    public static Set<String> getRegisteredProviders() {
         // returns a COPY of the providers in order to avoid modifications
         synchronized (REGISTERED_PROVIDERS) {
             return new TreeSet<>(REGISTERED_PROVIDERS.keySet());
         }
     }
 
-    public static synchronized boolean isBouncyCastleRegistered() {
+    public static boolean isBouncyCastleRegistered() {
         register();
-        return isBouncyCastleListed();
-    }
-
-    private static boolean isBouncyCastleListed() {
         return isProviderRegistered(BOUNCY_CASTLE);
     }
 
-    private static boolean isEDDSAListed() {
-        return isProviderRegistered(EDDSA);
+    public static boolean isProviderRegistered(String provider) {
+        return getRegisteredProvider(provider) != null;
     }
 
-    private static boolean isProviderRegistered(String provider) {
-        Objects.requireNonNull(provider, "No provider name specified");
+    public static SecurityProviderRegistrar getRegisteredProvider(String 
provider) {
+        ValidateUtils.checkNotNullAndNotEmpty(provider, "No provider name 
specified");
         synchronized (REGISTERED_PROVIDERS) {
-            return REGISTERED_PROVIDERS.containsKey(provider);
+            return REGISTERED_PROVIDERS.get(provider);
         }
     }
 
-    @SuppressWarnings("synthetic-access")
+    public static boolean isRegistrationCompleted() {
+        return REGISTRATION_STATE_HOLDER.get();
+    }
+
     private static void register() {
-        if (!registrationDone) {
-            if (registerBouncyCastle == null) {
-                String propValue = 
System.getProperty(REGISTER_BOUNCY_CASTLE_PROP);
-                if (!GenericUtils.isEmpty(propValue)) {
-                    Logger logger = 
LoggerFactory.getLogger(SecurityUtils.class);
-                    logger.info("Override BouncyCastle registration value: " + 
propValue);
-                    registerBouncyCastle = Boolean.valueOf(propValue);
-                }
+        synchronized (REGISTRATION_STATE_HOLDER) {
+            if (REGISTRATION_STATE_HOLDER.get()) {
+                return;
             }
 
-            if ((defaultProvider == null) && (!isBouncyCastleListed()) && 
((registerBouncyCastle == null) || registerBouncyCastle)) {
-                // Use an inner class to avoid a strong dependency from 
SshServer on BouncyCastle
-                try {
-                    new BouncyCastleRegistration().call();
-                    defaultProvider = BOUNCY_CASTLE;
-                } catch (Throwable t) {
-                    Logger logger = 
LoggerFactory.getLogger(SecurityUtils.class);
-                    if (registerBouncyCastle == null) {
-                        logger.info("BouncyCastle not registered, using the 
default JCE provider");
-                    } else {
-                        logger.error("Failed {} to register BouncyCastle as a 
JCE provider: {}", t.getClass().getSimpleName(), t.getMessage());
-                        throw new RuntimeException("Failed to register 
BouncyCastle as a JCE provider", t);
+            String regsList = System.getProperty(SECURITY_PROVIDER_REGISTRARS,
+                    GenericUtils.join(DEFAULT_SECURITY_PROVIDER_REGISTRARS, 
','));
+            boolean bouncyCastleRegistered = false;
+            if ((GenericUtils.length(regsList) > 0) && 
(!"none".equalsIgnoreCase(regsList))) {
+                String[] classes = GenericUtils.split(regsList, ',');
+                Logger logger = LoggerFactory.getLogger(SecurityUtils.class);
+                ClassLoader cl = 
ThreadUtils.resolveDefaultClassLoader(SecurityUtils.class);
+                for (String registrarClass : classes) {
+                    SecurityProviderRegistrar r;
+                    try {
+                        r = ThreadUtils.createDefaultInstance(cl, 
SecurityProviderRegistrar.class, registrarClass);
+                    } catch (ReflectiveOperationException t) {
+                        Throwable e = GenericUtils.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 RuntimeException(e);
+                        }
+                    }
+
+                    String name = r.getName();
+                    SecurityProviderRegistrar registeredInstance = 
registerSecurityProvider(r);
+                    if (registeredInstance == null) {
+                        if (logger.isDebugEnabled()) {
+                            logger.debug("register({}) not registered - 
enabled={}, supported={}",
+                                         name, r.isEnabled(), r.isSupported());
+                        }
+                        continue;   // provider not registered - e.g., 
disabled, not supported
+                    }
+
+                    if (BOUNCY_CASTLE.equalsIgnoreCase(name)) {
+                        bouncyCastleRegistered = true;
                     }
                 }
             }
 
-            if ((!isEDDSAListed()) && isEDDSACurveSupported()) {
-                try {
-                    new EdDSARegistration().call();
-                } catch (Throwable t) {
-                    Logger logger = 
LoggerFactory.getLogger(SecurityUtils.class);
-                    logger.error("Failed {} to register " + EDDSA + " as a JCE 
provider: {}", t.getClass().getSimpleName(), t.getMessage());
-                    throw new RuntimeException("Failed to register " + EDDSA + 
" as a JCE provider", t);
-                }
+            SecurityProviderChoice choice = getDefaultProviderChoice();
+            if (((choice == null) || (choice == SecurityProviderChoice.EMPTY)) 
&& bouncyCastleRegistered) {
+                
setDefaultProviderChoice(SecurityProviderChoice.toSecurityProviderChoice(BOUNCY_CASTLE));
             }
 
-            registrationDone = true;
+            REGISTRATION_STATE_HOLDER.set(true);
         }
     }
 
-    ///////////////// Bouncycastle specific implementations //////////////////
-
-    private static class BouncyCastleRegistration implements Callable<Void> {
-        @SuppressWarnings("synthetic-access")
-        @Override
-        public Void call() throws Exception {
-            // no need for a logger specific to this class since this is a 
one-time call
-            Logger logger = LoggerFactory.getLogger(SecurityUtils.class);
-            Provider p = java.security.Security.getProvider(BOUNCY_CASTLE);
-            if (p == null) {
-                logger.info("Trying to register BouncyCastle as a JCE 
provider");
-                p = new BouncyCastleProvider();
-                java.security.Security.addProvider(p);
-                MessageDigest.getInstance("MD5", BOUNCY_CASTLE);
-                KeyAgreement.getInstance("DH", BOUNCY_CASTLE);
-                logger.info("Registration succeeded");
-            } else {
-                logger.info("BouncyCastle already registered as a JCE 
provider");
-            }
+    /**
+     * @param registrar The registrar instance to register
+     * @return The registered instance - may be different than required
+     * if already registered. Returns {@code null} if not already registered
+     * and not enabled or not supported registrar.
+     */
+    public static SecurityProviderRegistrar 
registerSecurityProvider(SecurityProviderRegistrar registrar) {
+        Objects.requireNonNull(registrar, "No registrar instance to register");
+        String name = registrar.getName();
+        SecurityProviderRegistrar registeredInstance = 
getRegisteredProvider(name);
+        if ((registeredInstance == null) && registrar.isEnabled() && 
registrar.isSupported()) {
+            try {
+                SecurityProviderRegistrar.registerSecurityProvider(registrar);
+                synchronized (REGISTERED_PROVIDERS) {
+                    REGISTERED_PROVIDERS.put(name, registrar);
+                }
 
-            synchronized (REGISTERED_PROVIDERS) {
-                REGISTERED_PROVIDERS.put(BOUNCY_CASTLE, p);
+                return registrar;
+            } catch (Throwable t) {
+                Logger logger = LoggerFactory.getLogger(SecurityUtils.class);
+                logger.error("Failed {} to register {} as a JCE provider: {}",
+                             t.getClass().getSimpleName(), name, 
t.getMessage());
+                throw new RuntimeException("Failed to register " + name + " as 
a JCE provider", t);
             }
-            return null;
         }
+
+        return registeredInstance;
     }
 
+    ///////////////// Bouncycastle specific implementations //////////////////
+
     /* -------------------------------------------------------------------- */
 
     /**
@@ -429,51 +525,11 @@ public final class SecurityUtils {
     /**
      * @return {@code true} if EDDSA curves (e.g., {@code ed25519}) are 
supported
      */
-    public static synchronized boolean isEDDSACurveSupported() {
-        if (eddsaSupported == null) {
-            String propValue = System.getProperty(EDDSA_SUPPORTED_PROP);
-            if (GenericUtils.isEmpty(propValue) || "true".equals(propValue)) {
-                ClassLoader cl = 
ThreadUtils.resolveDefaultClassLoader(SecurityUtils.class);
-                eddsaSupported = ReflectionUtils.isClassAvailable(cl, 
"net.i2p.crypto.eddsa.EdDSAKey");
-            } else {
-                eddsaSupported = Boolean.FALSE;
-                Logger logger = LoggerFactory.getLogger(SecurityUtils.class);
-                logger.info("Override EDDSA support value: " + propValue);
-            }
-        }
-
-        return eddsaSupported;
-    }
-
-    /* -------------------------------------------------------------------- */
-
-    private static class EdDSARegistration implements Callable<Void> {
-        EdDSARegistration() {
-            super();
-        }
-
-        @SuppressWarnings("synthetic-access")
-        @Override
-        public Void call() throws Exception {
-            // no need for a logger specific to this class since this is a 
one-time call
-            Logger logger = LoggerFactory.getLogger(SecurityUtils.class);
-            Provider p = java.security.Security.getProvider(EDDSA);
-            if (p == null) {
-                logger.info("Trying to register " + EDDSA + " as a JCE 
provider");
-                p = new EdDSASecurityProvider();
-                java.security.Security.addProvider(p);
-                KeyFactory.getInstance(EDDSA, EDDSA);
-                logger.info("Registration succeeded");
-            } else {
-                logger.info(EDDSA + " already registered as a JCE provider");
-            }
-
-            synchronized (REGISTERED_PROVIDERS) {
-                REGISTERED_PROVIDERS.put(EDDSA, p);
-            }
+    public static boolean isEDDSACurveSupported() {
+        register();
 
-            return null;
-        }
+        SecurityProviderRegistrar r = getRegisteredProvider(EDDSA);
+        return (r != null) && r.isEnabled() && r.isSupported();
     }
 
     /* -------------------------------------------------------------------- */
@@ -604,103 +660,99 @@ public final class SecurityUtils {
         }
     }
 
-    public static synchronized KeyFactory getKeyFactory(String algorithm) 
throws GeneralSecurityException {
-        register();
+    //////////////////////////// Security entities factories 
/////////////////////////////
 
-        String providerName = getDefaultProvider();
-        if (isEDDSACurveSupported() && 
EdDSASecurityProvider.isEDDSAKeyFactoryAlgorithm(algorithm)) {
-            providerName = EDDSA;
+    @SuppressWarnings("unchecked")
+    public static <T> SecurityEntityFactory<T> resolveSecurityEntityFactory(
+            Class<T> entityType, String algorithm, Predicate<? super 
SecurityProviderRegistrar> entitySelector) {
+        Map<String, SecurityEntityFactory<?>> factoriesMap;
+        synchronized (SECURITY_ENTITY_FACTORIES) {
+            factoriesMap =
+                    SECURITY_ENTITY_FACTORIES.computeIfAbsent(
+                            entityType, k -> new 
TreeMap<>(String.CASE_INSENSITIVE_ORDER));
         }
 
-        if (GenericUtils.isEmpty(providerName)) {
-            return KeyFactory.getInstance(algorithm);
-        } else {
-            return KeyFactory.getInstance(algorithm, providerName);
+        String effectiveName = 
SecurityProviderRegistrar.getEffectiveSecurityEntityName(entityType, algorithm);
+        SecurityEntityFactory<?> factoryEntry;
+        synchronized (factoriesMap) {
+            factoryEntry =
+                    factoriesMap.computeIfAbsent(
+                            effectiveName, k -> 
createSecurityEntityFactory(entityType, entitySelector));
         }
-    }
-
-    public static synchronized Cipher getCipher(String transformation) throws 
GeneralSecurityException {
-        register();
 
-        String providerName = getDefaultProvider();
-        if (GenericUtils.isEmpty(providerName)) {
-            return Cipher.getInstance(transformation);
-        } else {
-            return Cipher.getInstance(transformation, providerName);
-        }
+        return (SecurityEntityFactory<T>) factoryEntry;
     }
 
-    public static synchronized MessageDigest getMessageDigest(String 
algorithm) throws GeneralSecurityException {
+    public static <T> SecurityEntityFactory<T> createSecurityEntityFactory(
+            Class<T> entityType, Predicate<? super SecurityProviderRegistrar> 
entitySelector) {
         register();
 
-        String providerName = getDefaultProvider();
-        if (GenericUtils.isEmpty(providerName)) {
-            return MessageDigest.getInstance(algorithm);
-        } else {
-            return MessageDigest.getInstance(algorithm, providerName);
-        }
-    }
-
-    public static synchronized KeyPairGenerator getKeyPairGenerator(String 
algorithm) throws GeneralSecurityException {
-        register();
-
-        String providerName = getDefaultProvider();
-        if (isEDDSACurveSupported() && 
EdDSASecurityProvider.isEDDSAKeyPairGeneratorAlgorithm(algorithm)) {
-            providerName = EDDSA;
+        SecurityProviderRegistrar registrar;
+        synchronized (REGISTERED_PROVIDERS) {
+            registrar =
+                 
SecurityProviderRegistrar.findSecurityProviderRegistrarBySecurityEntity(
+                         entitySelector, REGISTERED_PROVIDERS.values());
         }
 
-        if (GenericUtils.isEmpty(providerName)) {
-            return KeyPairGenerator.getInstance(algorithm);
-        } else {
-            return KeyPairGenerator.getInstance(algorithm, providerName);
+        try {
+            return SecurityEntityFactory.toFactory(entityType, registrar, 
getDefaultProviderChoice());
+        } catch (ReflectiveOperationException t) {
+            Throwable e = GenericUtils.peelException(t);
+            if (e instanceof RuntimeException) {
+                throw (RuntimeException) e;
+            } else if (e instanceof Error) {
+                throw (Error) e;
+            } else {
+                throw new RuntimeException(e);
+            }
         }
     }
 
-    public static synchronized KeyAgreement getKeyAgreement(String algorithm) 
throws GeneralSecurityException {
-        register();
-
-        String providerName = getDefaultProvider();
-        if (GenericUtils.isEmpty(providerName)) {
-            return KeyAgreement.getInstance(algorithm);
-        } else {
-            return KeyAgreement.getInstance(algorithm, providerName);
-        }
+    public static KeyFactory getKeyFactory(String algorithm) throws 
GeneralSecurityException {
+        SecurityEntityFactory<KeyFactory> factory =
+                resolveSecurityEntityFactory(KeyFactory.class, algorithm, r -> 
r.isKeyFactorySupported(algorithm));
+        return factory.getInstance(algorithm);
     }
 
-    public static synchronized Mac getMac(String algorithm) throws 
GeneralSecurityException {
-        register();
+    public static Cipher getCipher(String transformation) throws 
GeneralSecurityException {
+        SecurityEntityFactory<Cipher> factory =
+                resolveSecurityEntityFactory(Cipher.class, transformation, r 
-> r.isCipherSupported(transformation));
+        return factory.getInstance(transformation);
+    }
 
-        String providerName = getDefaultProvider();
-        if (GenericUtils.isEmpty(providerName)) {
-            return Mac.getInstance(algorithm);
-        } else {
-            return Mac.getInstance(algorithm, providerName);
-        }
+    public static MessageDigest getMessageDigest(String algorithm) throws 
GeneralSecurityException {
+        SecurityEntityFactory<MessageDigest> factory =
+                resolveSecurityEntityFactory(MessageDigest.class, algorithm, r 
-> r.isMessageDigestSupported(algorithm));
+        return factory.getInstance(algorithm);
     }
 
-    public static synchronized Signature getSignature(String algorithm) throws 
GeneralSecurityException {
-        register();
+    public static KeyPairGenerator getKeyPairGenerator(String algorithm) 
throws GeneralSecurityException {
+        SecurityEntityFactory<KeyPairGenerator> factory =
+                resolveSecurityEntityFactory(KeyPairGenerator.class, 
algorithm, r -> r.isKeyPairGeneratorSupported(algorithm));
+        return factory.getInstance(algorithm);
+    }
 
-        String providerName = getDefaultProvider();
-        if (isEDDSACurveSupported() && 
EdDSASecurityProvider.isEDDSASignatureAlgorithm(algorithm)) {
-            providerName = EDDSA;
-        }
+    public static KeyAgreement getKeyAgreement(String algorithm) throws 
GeneralSecurityException {
+        SecurityEntityFactory<KeyAgreement> factory =
+                resolveSecurityEntityFactory(KeyAgreement.class, algorithm, r 
-> r.isKeyAgreementSupported(algorithm));
+        return factory.getInstance(algorithm);
+    }
 
-        if (GenericUtils.isEmpty(providerName)) {
-            return Signature.getInstance(algorithm);
-        } else {
-            return Signature.getInstance(algorithm, providerName);
-        }
+    public static Mac getMac(String algorithm) throws GeneralSecurityException 
{
+        SecurityEntityFactory<Mac> factory =
+                resolveSecurityEntityFactory(Mac.class, algorithm, r -> 
r.isMacSupported(algorithm));
+        return factory.getInstance(algorithm);
     }
 
-    public static synchronized CertificateFactory getCertificateFactory(String 
type) throws GeneralSecurityException {
-        register();
+    public static Signature getSignature(String algorithm) throws 
GeneralSecurityException {
+        SecurityEntityFactory<Signature> factory =
+                resolveSecurityEntityFactory(Signature.class, algorithm, r -> 
r.isSignatureSupported(algorithm));
+        return factory.getInstance(algorithm);
+    }
 
-        String providerName = getDefaultProvider();
-        if (GenericUtils.isEmpty(providerName)) {
-            return CertificateFactory.getInstance(type);
-        } else {
-            return CertificateFactory.getInstance(type, providerName);
-        }
+    public static CertificateFactory getCertificateFactory(String type) throws 
GeneralSecurityException {
+        SecurityEntityFactory<CertificateFactory> factory =
+                resolveSecurityEntityFactory(CertificateFactory.class, type, r 
-> r.isCertificateFactorySupported(type));
+        return factory.getInstance(type);
     }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ab72900f/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleKeyPairResourceParser.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleKeyPairResourceParser.java
 
b/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleKeyPairResourceParser.java
index 467720f..4c8722a 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleKeyPairResourceParser.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleKeyPairResourceParser.java
@@ -26,6 +26,7 @@ import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
 import java.security.GeneralSecurityException;
 import java.security.KeyPair;
+import java.security.NoSuchProviderException;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -35,6 +36,7 @@ import 
org.apache.sshd.common.config.keys.FilePasswordProvider;
 import org.apache.sshd.common.config.keys.loader.AbstractKeyPairResourceParser;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.common.util.security.SecurityProviderRegistrar;
 import org.apache.sshd.common.util.security.SecurityUtils;
 import org.bouncycastle.openssl.PEMDecryptorProvider;
 import org.bouncycastle.openssl.PEMEncryptedKeyPair;
@@ -96,8 +98,17 @@ public class BouncyCastleKeyPairResourceParser extends 
AbstractKeyPairResourcePa
         try (PEMParser r = new PEMParser(new InputStreamReader(inputStream, 
StandardCharsets.UTF_8))) {
             Object o = r.readObject();
 
+            SecurityProviderRegistrar registrar = 
SecurityUtils.getRegisteredProvider(SecurityUtils.BOUNCY_CASTLE);
+            if (registrar == null) {
+                throw new NoSuchProviderException(SecurityUtils.BOUNCY_CASTLE 
+ " registrar not available");
+            }
+
             JcaPEMKeyConverter pemConverter = new JcaPEMKeyConverter();
-            pemConverter.setProvider(SecurityUtils.BOUNCY_CASTLE);
+            if (registrar.isNamedProviderUsed()) {
+                pemConverter.setProvider(registrar.getName());
+            } else {
+                pemConverter.setProvider(registrar.getSecurityProvider());
+            }
             if (o instanceof PEMEncryptedKeyPair) {
                 ValidateUtils.checkNotNull(provider, "No password provider for 
resource=%s", resourceKey);
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ab72900f/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleSecurityProviderRegistrar.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleSecurityProviderRegistrar.java
 
b/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleSecurityProviderRegistrar.java
new file mode 100644
index 0000000..87744a1
--- /dev/null
+++ 
b/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleSecurityProviderRegistrar.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.util.security.bouncycastle;
+
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.Provider;
+import java.security.Signature;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.sshd.common.PropertyResolverUtils;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ReflectionUtils;
+import org.apache.sshd.common.util.security.AbstractSecurityProviderRegistrar;
+import org.apache.sshd.common.util.security.SecurityUtils;
+import org.apache.sshd.common.util.threads.ThreadUtils;
+
+/**
+ * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
+ */
+public class BouncyCastleSecurityProviderRegistrar extends 
AbstractSecurityProviderRegistrar {
+    // We want to use reflection API so as not to require BouncyCastle to be 
present in the classpath
+    public static final String PROVIDER_CLASS = 
"org.bouncycastle.jce.provider.BouncyCastleProvider";
+    // Do not define a static registrar instance to minimize class loading 
issues
+    private final AtomicReference<Boolean> supportHolder = new 
AtomicReference<>(null);
+
+    public BouncyCastleSecurityProviderRegistrar() {
+        super(SecurityUtils.BOUNCY_CASTLE);
+    }
+
+    @Override
+    public boolean isEnabled() {
+        if (!super.isEnabled()) {
+            return false;
+        }
+
+        // For backward compatibility
+        return PropertyResolverUtils.getBooleanProperty(this, 
SecurityUtils.REGISTER_BOUNCY_CASTLE_PROP, true);
+    }
+
+    @Override
+    public Provider getSecurityProvider() {
+        try {
+            return getOrCreateProvider(PROVIDER_CLASS);
+        } catch (ReflectiveOperationException t) {
+            Throwable e = GenericUtils.peelException(t);
+            log.error("getSecurityProvider({}) failed ({}) to instantiate {}: 
{}",
+                      getName(), e.getClass().getSimpleName(), PROVIDER_CLASS, 
e.getMessage());
+            if (e instanceof RuntimeException) {
+                throw (RuntimeException) e;
+            }
+
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public String getDefaultSecurityEntitySupportValue(Class<?> entityType) {
+        return ALL_OPTIONS_VALUE;
+    }
+
+    @Override
+    public boolean isSecurityEntitySupported(Class<?> entityType, String name) 
{
+        if (!isSupported()) {
+            return false;
+        }
+
+        // Some known values it does not support
+        if (KeyPairGenerator.class.isAssignableFrom(entityType)
+                || KeyFactory.class.isAssignableFrom(entityType)) {
+            if (Objects.compare(name, SecurityUtils.EDDSA, 
String.CASE_INSENSITIVE_ORDER) == 0) {
+                return false;
+            }
+        } else if (Signature.class.isAssignableFrom(entityType)) {
+            if (Objects.compare(name, SecurityUtils.CURVE_ED25519_SHA512, 
String.CASE_INSENSITIVE_ORDER) == 0) {
+                return false;
+            }
+        }
+
+        return super.isSecurityEntitySupported(entityType, name);
+    }
+
+    @Override
+    public boolean isSupported() {
+        Boolean supported;
+        synchronized (supportHolder) {
+            supported = supportHolder.get();
+            if (supported != null) {
+                return supported.booleanValue();
+            }
+
+            ClassLoader cl = ThreadUtils.resolveDefaultClassLoader(getClass());
+            supported = ReflectionUtils.isClassAvailable(cl, PROVIDER_CLASS);
+            supportHolder.set(supported);
+        }
+
+        return supported.booleanValue();
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ab72900f/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderRegistrar.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderRegistrar.java
 
b/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderRegistrar.java
new file mode 100644
index 0000000..b463d27
--- /dev/null
+++ 
b/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderRegistrar.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.util.security.eddsa;
+
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.Provider;
+import java.security.Signature;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.sshd.common.PropertyResolverUtils;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ReflectionUtils;
+import org.apache.sshd.common.util.security.AbstractSecurityProviderRegistrar;
+import org.apache.sshd.common.util.security.SecurityUtils;
+import org.apache.sshd.common.util.threads.ThreadUtils;
+
+/**
+ * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
+ */
+public class EdDSASecurityProviderRegistrar extends 
AbstractSecurityProviderRegistrar {
+    public static final String PROVIDER_CLASS = 
"org.apache.sshd.common.util.security.eddsa.EdDSASecurityProvider";
+    // Do not define a static registrar instance to minimize class loading 
issues
+    private final AtomicReference<Boolean> supportHolder = new 
AtomicReference<>(null);
+
+    public EdDSASecurityProviderRegistrar() {
+        super(SecurityUtils.EDDSA);
+    }
+
+    @Override
+    public boolean isEnabled() {
+        if (!super.isEnabled()) {
+            return false;
+        }
+
+        // For backward compatibility
+        return PropertyResolverUtils.getBooleanProperty(this, 
SecurityUtils.EDDSA_SUPPORTED_PROP, true);
+    }
+
+    @Override
+    public Provider getSecurityProvider() {
+        try {
+            return getOrCreateProvider(PROVIDER_CLASS);
+        } catch (ReflectiveOperationException t) {
+            Throwable e = GenericUtils.peelException(t);
+            log.error("getSecurityProvider({}) failed ({}) to instantiate {}: 
{}",
+                      getName(), e.getClass().getSimpleName(), PROVIDER_CLASS, 
e.getMessage());
+            if (e instanceof RuntimeException) {
+                throw (RuntimeException) e;
+            }
+
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public boolean isSecurityEntitySupported(Class<?> entityType, String name) 
{
+        if (!isSupported()) {
+            return false;
+        }
+
+        if (KeyPairGenerator.class.isAssignableFrom(entityType)
+                || KeyFactory.class.isAssignableFrom(entityType)) {
+            return Objects.compare(name, getName(), 
String.CASE_INSENSITIVE_ORDER) == 0;
+        } else if (Signature.class.isAssignableFrom(entityType)) {
+            return Objects.compare(SecurityUtils.CURVE_ED25519_SHA512, name, 
String.CASE_INSENSITIVE_ORDER) == 0;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public boolean isSupported() {
+        Boolean supported;
+        synchronized (supportHolder) {
+            supported = supportHolder.get();
+            if (supported != null) {
+                return supported.booleanValue();
+            }
+
+            ClassLoader cl = ThreadUtils.resolveDefaultClassLoader(getClass());
+            supported = ReflectionUtils.isClassAvailable(cl, 
"net.i2p.crypto.eddsa.EdDSAKey");
+            supportHolder.set(supported);
+        }
+
+        return supported.booleanValue();
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ab72900f/sshd-core/src/main/java/org/apache/sshd/common/util/threads/ThreadUtils.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/util/threads/ThreadUtils.java 
b/sshd-core/src/main/java/org/apache/sshd/common/util/threads/ThreadUtils.java
index de16f41..0c003ba 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/common/util/threads/ThreadUtils.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/common/util/threads/ThreadUtils.java
@@ -96,6 +96,18 @@ public final class ThreadUtils {
         return resolveDefaultClassLoader(anchor == null ? null : 
anchor.getClass());
     }
 
+    public static <T> T createDefaultInstance(Class<?> anchor, Class<T> 
targetType, String className)
+            throws ReflectiveOperationException {
+        return createDefaultInstance(resolveDefaultClassLoader(anchor), 
targetType, className);
+    }
+
+    public static <T> T createDefaultInstance(ClassLoader cl, Class<T> 
targetType, String className)
+            throws ReflectiveOperationException {
+        Class<?> instanceType = cl.loadClass(className);
+        Object instance = instanceType.newInstance();
+        return targetType.cast(instance);
+    }
+
     /**
      * <P>Attempts to find the most suitable {@link ClassLoader} as 
follows:</P>
      * <UL>

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ab72900f/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java 
b/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
index a08fb30..68531ed 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
@@ -46,13 +46,13 @@ public interface ServerFactoryManager
     /**
      * Key used to retrieve any extra lines to be sent during
      * initial protocol handshake <U>before</U> the identification.
-     * The configured string value should use {@link 
#SERVER_EXTRA_IDENT_LINES_SEPARATOR}
+     * The configured string value should use {@value 
#SERVER_EXTRA_IDENT_LINES_SEPARATOR}
      * character to denote line breaks
      */
     String SERVER_EXTRA_IDENTIFICATION_LINES = 
"server-extra-identification-lines";
 
     /**
-     * Separator used in the {@link #SERVER_EXTRA_IDENTIFICATION_LINES} 
configuration
+     * Separator used in the {@value #SERVER_EXTRA_IDENTIFICATION_LINES} 
configuration
      * string to indicate new line break
      */
     char SERVER_EXTRA_IDENT_LINES_SEPARATOR = '|';
@@ -75,7 +75,7 @@ public interface ServerFactoryManager
     String COMMAND_EXIT_TIMEOUT = "command-exit-timeout";
 
     /**
-     * Default {@link #COMMAND_EXIT_TIMEOUT} if not set
+     * Default {@value #COMMAND_EXIT_TIMEOUT} if not set
      */
     long DEFAULT_COMMAND_EXIT_TIMEOUT = TimeUnit.SECONDS.toMillis(5L);
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ab72900f/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
 
b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
index 8175520..120f0c0 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
@@ -187,6 +187,7 @@ public class SftpSubsystem
      * @see #DEFAULT_SUPPORTED_CLIENT_EXTENSIONS
      */
     public static final String CLIENT_EXTENSIONS_PROP = 
"sftp-client-extensions";
+
     /**
      * The default reported supported client extensions
      */

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ab72900f/sshd-core/src/main/java/org/apache/sshd/server/x11/X11ForwardSupport.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/x11/X11ForwardSupport.java 
b/sshd-core/src/main/java/org/apache/sshd/server/x11/X11ForwardSupport.java
index c4eb337..512d21e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/x11/X11ForwardSupport.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/x11/X11ForwardSupport.java
@@ -32,7 +32,7 @@ import org.apache.sshd.common.util.net.SshdSocketAddress;
 public interface X11ForwardSupport extends Closeable, IoHandler {
     /**
      * Configuration value on the {@link FactoryManager} to control the
-     * channel open timeout. If not specified then {@link 
#DEFAULT_CHANNEL_OPEN_TIMEOUT}
+     * channel open timeout. If not specified then {@value 
#DEFAULT_CHANNEL_OPEN_TIMEOUT}
      * value is used
      */
     String CHANNEL_OPEN_TIMEOUT_PROP = "x11-fwd-open-timeout";
@@ -40,7 +40,7 @@ public interface X11ForwardSupport extends Closeable, 
IoHandler {
 
     /**
      * Configuration value to control from which X11 display number to start
-     * looking for a free value. If not specified, then {@link 
#DEFAULT_X11_DISPLAY_OFFSET}
+     * looking for a free value. If not specified, then {@value 
#DEFAULT_X11_DISPLAY_OFFSET}
      * is used
      */
     String X11_DISPLAY_OFFSET = "x11-fwd-display-offset";
@@ -48,7 +48,7 @@ public interface X11ForwardSupport extends Closeable, 
IoHandler {
 
     /**
      * Configuration value to control up to which (but not including) X11 
display number
-     * to look or a free value. If not specified, then {@link 
#DEFAULT_X11_MAX_DISPLAYS}
+     * to look or a free value. If not specified, then {@value 
#DEFAULT_X11_MAX_DISPLAYS}
      * is used
      */
     String X11_MAX_DISPLAYS = "x11-fwd-max-display";
@@ -56,7 +56,7 @@ public interface X11ForwardSupport extends Closeable, 
IoHandler {
 
     /**
      * Configuration value to control the base port number for the X11 display
-     * number socket binding. If not specified then {@link 
#DEFAULT_X11_BASE_PORT}
+     * number socket binding. If not specified then {@value 
#DEFAULT_X11_BASE_PORT}
      * value is used
      */
     String X11_BASE_PORT = "x11-fwd-base-port";
@@ -64,7 +64,7 @@ public interface X11ForwardSupport extends Closeable, 
IoHandler {
 
     /**
      * Configuration value to control the host used to bind to for the X11 
display
-     * when looking for a free port. If not specified, then {@link 
#DEFAULT_X11_BIND_HOST}
+     * when looking for a free port. If not specified, then {@value 
#DEFAULT_X11_BIND_HOST}
      * is used
      */
     String X11_BIND_HOST = "x11-fwd-bind-host";

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ab72900f/sshd-core/src/test/java/org/apache/sshd/common/config/keys/AuthorizedKeysTestSupport.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/common/config/keys/AuthorizedKeysTestSupport.java
 
b/sshd-core/src/test/java/org/apache/sshd/common/config/keys/AuthorizedKeysTestSupport.java
index b85fb1e..6d580b8 100644
--- 
a/sshd-core/src/test/java/org/apache/sshd/common/config/keys/AuthorizedKeysTestSupport.java
+++ 
b/sshd-core/src/test/java/org/apache/sshd/common/config/keys/AuthorizedKeysTestSupport.java
@@ -97,7 +97,7 @@ public abstract class AuthorizedKeysTestSupport extends 
BaseTestSupport {
 
     public static List<String> loadSupportedKeys(BufferedReader rdr) throws 
IOException {
         List<String> keyLines = new ArrayList<>();
-        boolean eccSupported = SecurityUtils.hasEcc();
+        boolean eccSupported = SecurityUtils.isECCSupported();
         for (String l = rdr.readLine(); l != null; l = rdr.readLine()) {
             l = GenericUtils.trimToEmpty(l);
             // filter out empty and comment lines

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ab72900f/sshd-core/src/test/java/org/apache/sshd/common/config/keys/BuiltinIdentitiesTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/common/config/keys/BuiltinIdentitiesTest.java
 
b/sshd-core/src/test/java/org/apache/sshd/common/config/keys/BuiltinIdentitiesTest.java
index eec81c7..2fa299a 100644
--- 
a/sshd-core/src/test/java/org/apache/sshd/common/config/keys/BuiltinIdentitiesTest.java
+++ 
b/sshd-core/src/test/java/org/apache/sshd/common/config/keys/BuiltinIdentitiesTest.java
@@ -24,64 +24,38 @@ import java.lang.reflect.Modifier;
 import java.security.GeneralSecurityException;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
+import java.util.List;
 
 import org.apache.sshd.common.util.security.SecurityUtils;
 import org.apache.sshd.util.test.BaseTestSupport;
+import org.junit.Assume;
+import org.junit.BeforeClass;
 import org.junit.FixMethodOrder;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
 /**
  * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
  */
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RunWith(Parameterized.class)   // see 
https://github.com/junit-team/junit/wiki/Parameterized-tests
 public class BuiltinIdentitiesTest extends BaseTestSupport {
-    public BuiltinIdentitiesTest() {
-        super();
-    }
-
-    @Test
-    public void testFromName() {
-        for (BuiltinIdentities expected : BuiltinIdentities.VALUES) {
-            String name = expected.getName();
-            for (int index = 0; index < name.length(); index++) {
-                assertSame(name, expected, BuiltinIdentities.fromName(name));
-                name = shuffleCase(name);
-            }
-        }
-    }
+    private final BuiltinIdentities expected;
 
-    @Test
-    public void testFromAlgorithm() {
-        for (BuiltinIdentities expected : BuiltinIdentities.VALUES) {
-            String algorithm = expected.getAlgorithm();
-            for (int index = 0; index < algorithm.length(); index++) {
-                assertSame(algorithm, expected, 
BuiltinIdentities.fromAlgorithm(algorithm));
-                algorithm = shuffleCase(algorithm);
-            }
-        }
+    public BuiltinIdentitiesTest(BuiltinIdentities expected) {
+        this.expected = expected;
     }
 
-    @Test
-    public void testFromKey() throws GeneralSecurityException {
-        for (BuiltinIdentities expected : BuiltinIdentities.VALUES) {
-            String name = expected.getName();
-            if (!expected.isSupported()) {
-                System.out.println("Skip unsupported built-in identity: " + 
name);
-                continue;
-            }
-
-            KeyPairGenerator gen = 
SecurityUtils.getKeyPairGenerator(expected.getAlgorithm());
-            KeyPair kp = gen.generateKeyPair();
-            outputDebugMessage("Checking built-in identity: %s", name);
-            assertSame(name + "[pair]", expected, 
BuiltinIdentities.fromKeyPair(kp));
-            assertSame(name + "[public]", expected, 
BuiltinIdentities.fromKey(kp.getPublic()));
-            assertSame(name + "[private]", expected, 
BuiltinIdentities.fromKey(kp.getPrivate()));
-        }
+    @Parameters(name = "{0}")
+    public static List<Object[]> parameters() {
+        return parameterize(BuiltinIdentities.VALUES);
     }
 
-    @Test
-    public void testAllConstantsCovered() throws Exception {
+    @BeforeClass    // Dirty hack around the parameterized run
+    public static void testAllConstantsCovered() throws Exception {
         Field[] fields = BuiltinIdentities.Constants.class.getFields();
         for (Field f : fields) {
             int mods = f.getModifiers();
@@ -104,4 +78,33 @@ public class BuiltinIdentitiesTest extends BaseTestSupport {
             assertNotNull("No match found for field " + name + "=" + value, 
id);
         }
     }
+
+    @Test
+    public void testFromName() {
+        String name = expected.getName();
+        for (int index = 0, count = name.length(); index < count; index++) {
+            assertSame(name, expected, BuiltinIdentities.fromName(name));
+            name = shuffleCase(name);
+        }
+    }
+
+    @Test
+    public void testFromAlgorithm() {
+        String algorithm = expected.getAlgorithm();
+        for (int index = 0, count = algorithm.length(); index < count; 
index++) {
+            assertSame(algorithm, expected, 
BuiltinIdentities.fromAlgorithm(algorithm));
+            algorithm = shuffleCase(algorithm);
+        }
+    }
+
+    @Test
+    public void testFromKey() throws GeneralSecurityException {
+        Assume.assumeTrue("Unsupported built-in identity", 
expected.isSupported());
+        KeyPairGenerator gen = 
SecurityUtils.getKeyPairGenerator(expected.getAlgorithm());
+        KeyPair kp = gen.generateKeyPair();
+        outputDebugMessage("Checking built-in identity: %s", expected);
+        assertSame(expected + "[pair]", expected, 
BuiltinIdentities.fromKeyPair(kp));
+        assertSame(expected + "[public]", expected, 
BuiltinIdentities.fromKey(kp.getPublic()));
+        assertSame(expected + "[private]", expected, 
BuiltinIdentities.fromKey(kp.getPrivate()));
+    }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ab72900f/sshd-core/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsCloneTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsCloneTest.java
 
b/sshd-core/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsCloneTest.java
index 6185de2..b8b46d8 100644
--- 
a/sshd-core/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsCloneTest.java
+++ 
b/sshd-core/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsCloneTest.java
@@ -59,7 +59,7 @@ public class KeyUtilsCloneTest extends BaseTestSupport {
         List<Object[]> list = new ArrayList<>();
         addTests(list, KeyPairProvider.SSH_DSS, DSS_SIZES);
         addTests(list, KeyPairProvider.SSH_RSA, RSA_SIZES);
-        if (SecurityUtils.hasEcc()) {
+        if (SecurityUtils.isECCSupported()) {
             for (ECCurves curve : ECCurves.VALUES) {
                 if (!curve.isSupported()) {
                     continue;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ab72900f/sshd-core/src/test/java/org/apache/sshd/common/signature/SignatureFactoriesTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/common/signature/SignatureFactoriesTest.java
 
b/sshd-core/src/test/java/org/apache/sshd/common/signature/SignatureFactoriesTest.java
index deb29ec..9c21f33 100644
--- 
a/sshd-core/src/test/java/org/apache/sshd/common/signature/SignatureFactoriesTest.java
+++ 
b/sshd-core/src/test/java/org/apache/sshd/common/signature/SignatureFactoriesTest.java
@@ -93,7 +93,7 @@ public class SignatureFactoriesTest extends BaseTestSupport 
implements OptionalF
         addTests(list, KeyPairProvider.SSH_DSS, BuiltinSignatures.dsa, 
DSS_SIZES, DSSPublicKeyEntryDecoder.INSTANCE);
         addTests(list, KeyPairProvider.SSH_RSA, BuiltinSignatures.rsa, 
RSA_SIZES, RSAPublicKeyDecoder.INSTANCE);
 
-        if (SecurityUtils.hasEcc()) {
+        if (SecurityUtils.isECCSupported()) {
             for (ECCurves curve : ECCurves.VALUES) {
                 BuiltinSignatures factory = 
BuiltinSignatures.fromFactoryName(curve.getKeyType());
                 addTests(list, curve.getName(), factory,

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ab72900f/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java 
b/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java
index 1fa87ad..a3dec7a 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java
@@ -23,9 +23,7 @@ import java.io.IOException;
 import java.nio.file.Path;
 import java.security.GeneralSecurityException;
 import java.security.KeyPair;
-import java.security.KeyPairGenerator;
 import java.security.PrivateKey;
-import java.security.Provider;
 import java.security.PublicKey;
 import java.security.interfaces.DSAPrivateKey;
 import java.security.interfaces.DSAPublicKey;
@@ -45,9 +43,12 @@ import 
org.apache.sshd.common.config.keys.loader.KeyPairResourceLoader;
 import org.apache.sshd.common.keyprovider.AbstractResourceKeyPairProvider;
 import org.apache.sshd.common.keyprovider.ClassLoadableResourceKeyPairProvider;
 import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+import org.apache.sshd.common.util.security.SecurityProviderRegistrar;
 import org.apache.sshd.common.util.security.SecurityUtils;
 import org.apache.sshd.util.test.BaseTestSupport;
+import org.junit.AfterClass;
 import org.junit.Assume;
+import org.junit.BeforeClass;
 import org.junit.FixMethodOrder;
 import org.junit.Test;
 import org.junit.runners.MethodSorters;
@@ -57,6 +58,11 @@ import org.junit.runners.MethodSorters;
  */
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 public class SecurityUtilsTest extends BaseTestSupport {
+    public static final String BC_NAMED_USAGE_PROP =
+            SecurityProviderRegistrar.CONFIG_PROP_BASE
+          + "." + SecurityUtils.BOUNCY_CASTLE
+          + "." + SecurityProviderRegistrar.NAMED_PROVIDER_PROPERTY;
+
     private static final String DEFAULT_PASSWORD = "super secret passphrase";
     private static final FilePasswordProvider TEST_PASSWORD_PROVIDER = file -> 
DEFAULT_PASSWORD;
 
@@ -64,6 +70,17 @@ public class SecurityUtilsTest extends BaseTestSupport {
         super();
     }
 
+    // NOTE: Using the BouncyCastle provider instead of the name does not work 
as expected so we take no chances
+    @BeforeClass
+    public static void useNamedBouncyCastleProvider() {
+        System.setProperty(BC_NAMED_USAGE_PROP, Boolean.TRUE.toString());
+    }
+
+    @AfterClass
+    public static void unsetBouncyCastleProviderUsagePreference() {
+        System.clearProperty(BC_NAMED_USAGE_PROP);
+    }
+
     @Test
     public void testLoadEncryptedDESPrivateKey() throws Exception {
         testLoadEncryptedRSAPrivateKey("DES-EDE3");
@@ -107,7 +124,7 @@ public class SecurityUtilsTest extends BaseTestSupport {
 
     @Test
     public void testLoadUnencryptedECPrivateKey() throws Exception {
-        Assume.assumeTrue("EC not supported", SecurityUtils.hasEcc());
+        Assume.assumeTrue("EC not supported", SecurityUtils.isECCSupported());
         for (ECCurves c : ECCurves.VALUES) {
             if (!c.isSupported()) {
                 System.out.println("Skip unsupported curve: " + c.getName());
@@ -180,26 +197,6 @@ public class SecurityUtilsTest extends BaseTestSupport {
     }
 
     @Test
-    public void testBouncyCastleRegistrationSettings() {
-        Assume.assumeTrue("Bouncycastle not registered", 
SecurityUtils.isBouncyCastleRegistered());
-        assertTrue("DH Group Exchange not supported", 
SecurityUtils.isDHGroupExchangeSupported());
-        assertEquals("Mismatched max. DH group exchange key size", 
SecurityUtils.MAX_DHGEX_KEY_SIZE, SecurityUtils.getMaxDHGroupExchangeKeySize());
-        assertTrue("ECC not supported", SecurityUtils.hasEcc());
-    }
-
-    @Test
-    public void testBouncyCastleRegistrationProperty() throws 
GeneralSecurityException {
-        String propValue = 
System.getProperty(SecurityUtils.REGISTER_BOUNCY_CASTLE_PROP);
-        Assume.assumeFalse(SecurityUtils.REGISTER_BOUNCY_CASTLE_PROP + " 
property not set", GenericUtils.isEmpty(propValue));
-        Assume.assumeFalse(SecurityUtils.REGISTER_BOUNCY_CASTLE_PROP + " 
property is " + propValue, Boolean.parseBoolean(propValue));
-        assertFalse("Unexpected registration of provider", 
SecurityUtils.isBouncyCastleRegistered());
-
-        KeyPairGenerator kpg = 
SecurityUtils.getKeyPairGenerator(KeyUtils.RSA_ALGORITHM);
-        Provider provider = kpg.getProvider();
-        assertNotEquals("Unexpected used provider", 
SecurityUtils.BOUNCY_CASTLE, provider.getName());
-    }
-
-    @Test
     public void testSetMaxDHGroupExchangeKeySizeByProperty() {
         try {
             for (int expected = SecurityUtils.MIN_DHGEX_KEY_SIZE; expected <= 
SecurityUtils.MAX_DHGEX_KEY_SIZE; expected += 1024) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ab72900f/sshd-core/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarCipherNameTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarCipherNameTest.java
 
b/sshd-core/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarCipherNameTest.java
new file mode 100644
index 0000000..a256552
--- /dev/null
+++ 
b/sshd-core/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarCipherNameTest.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.util.security;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.crypto.Cipher;
+
+import org.apache.sshd.common.cipher.BuiltinCiphers;
+import org.apache.sshd.common.cipher.CipherInformation;
+import org.apache.sshd.util.test.BaseTestSupport;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RunWith(Parameterized.class)   // see 
https://github.com/junit-team/junit/wiki/Parameterized-tests
+public class SecurityProviderRegistrarCipherNameTest extends BaseTestSupport {
+    private final CipherInformation cipherInfo;
+
+    public SecurityProviderRegistrarCipherNameTest(CipherInformation 
cipherInfo) {
+        this.cipherInfo = cipherInfo;
+    }
+
+    @Parameters(name = "{0}")
+    public static List<Object[]> parameters() {
+        return Collections.unmodifiableList(
+                new ArrayList<Object[]>(BuiltinCiphers.VALUES.size()) {
+                    // Not serializing it
+                    private static final long serialVersionUID = 1L;
+
+                    {
+                        for (CipherInformation cipherInfo : 
BuiltinCiphers.VALUES) {
+                            String algorithm = cipherInfo.getAlgorithm();
+                            String xform = cipherInfo.getTransformation();
+                            if (!xform.startsWith(algorithm)) {
+                                continue;
+                            }
+
+                            add(new Object[]{cipherInfo});
+                        }
+                    }
+        });
+    }
+
+    @Test
+    public void testGetEffectiveSecurityEntityName() {
+        String expected = cipherInfo.getAlgorithm();
+        String actual = 
SecurityProviderRegistrar.getEffectiveSecurityEntityName(Cipher.class, 
cipherInfo.getTransformation());
+        assertEquals("Mismatched pure cipher name", expected, actual);
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ab72900f/sshd-core/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarTestSupport.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarTestSupport.java
 
b/sshd-core/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarTestSupport.java
new file mode 100644
index 0000000..cf955dc
--- /dev/null
+++ 
b/sshd-core/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarTestSupport.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.util.security;
+
+import java.security.Provider;
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.apache.sshd.util.test.BaseTestSupport;
+
+/**
+ * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
+ */
+public abstract class SecurityProviderRegistrarTestSupport extends 
BaseTestSupport {
+    protected SecurityProviderRegistrarTestSupport() {
+        super();
+    }
+
+    public static Provider testGetSecurityProviderCaching(String prefix, 
SecurityProviderRegistrar registrar) {
+        return testGetSecurityProviderCaching(prefix, registrar, 
registrar.getSecurityProvider());
+    }
+
+    public static <P extends Provider> P testGetSecurityProviderCaching(String 
prefix, SecurityProviderRegistrar registrar, P expected) {
+        for (int index = 1; index <= Byte.SIZE; index++) {
+            Provider actual = registrar.getSecurityProvider();
+            assertSame(prefix + ": Mismatched provider instance at invocation 
#" + index, expected, actual);
+        }
+
+        return expected;
+    }
+
+    public static void assertSecurityEntitySupportState(
+            String prefix, SecurityProviderRegistrar registrar, boolean 
expected, String name, Class<?> ... entities) {
+        assertSecurityEntitySupportState(prefix, registrar, expected, name, 
Arrays.asList(entities));
+    }
+
+    public static void assertSecurityEntitySupportState(
+            String prefix, SecurityProviderRegistrar registrar, boolean 
expected, String name, Collection<Class<?>> entities) {
+        for (Class<?> entity : entities) {
+            assertEquals(prefix + "[" + entity.getSimpleName() + "]", 
expected, registrar.isSecurityEntitySupported(entity, name));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ab72900f/sshd-core/src/test/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderRegistrarTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderRegistrarTest.java
 
b/sshd-core/src/test/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderRegistrarTest.java
new file mode 100644
index 0000000..9e12fab
--- /dev/null
+++ 
b/sshd-core/src/test/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderRegistrarTest.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.util.security.eddsa;
+
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.Provider;
+import java.security.Signature;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+
+import org.apache.sshd.common.util.security.SecurityProviderRegistrar;
+import 
org.apache.sshd.common.util.security.SecurityProviderRegistrarTestSupport;
+import org.apache.sshd.common.util.security.SecurityUtils;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class EdDSASecurityProviderRegistrarTest extends 
SecurityProviderRegistrarTestSupport {
+    private static SecurityProviderRegistrar registrarInstance;
+
+    public EdDSASecurityProviderRegistrarTest() {
+        super();
+    }
+
+    @BeforeClass
+    public static void checkEDDSASupported() {
+        Assume.assumeTrue(SecurityUtils.isEDDSACurveSupported());
+        registrarInstance = new EdDSASecurityProviderRegistrar();
+    }
+
+    @Test
+    public void testSupportedSecurityEntities() {
+        assertSecurityEntitySupportState(getCurrentTestName(), 
registrarInstance, true, registrarInstance.getName(),
+                KeyPairGenerator.class, KeyFactory.class);
+        assertSecurityEntitySupportState(getCurrentTestName(), 
registrarInstance, true,
+                SecurityUtils.CURVE_ED25519_SHA512, Signature.class);
+
+        Collection<Class<?>> supported = new 
HashSet<>(Arrays.asList(KeyPairGenerator.class, KeyFactory.class, 
Signature.class));
+        for (Class<?> entity : SecurityProviderRegistrar.SECURITY_ENTITIES) {
+            if (supported.contains(entity)) {
+                continue;
+            }
+            assertFalse("Unexpected support for " + entity.getSimpleName(), 
registrarInstance.isSecurityEntitySupported(entity, 
registrarInstance.getName()));
+        }
+    }
+
+    @Test
+    public void testGetSecurityProvider() {
+        Provider expected = registrarInstance.getSecurityProvider();
+        assertNotNull("No provider created", expected);
+        assertEquals("Mismatched provider name", registrarInstance.getName(), 
expected.getName());
+        assertObjectInstanceOf("Mismatched provider type", 
EdDSASecurityProvider.class, expected);
+    }
+
+    @Test
+    public void testGetSecurityProviderCaching() {
+        testGetSecurityProviderCaching(getCurrentTestName(), 
registrarInstance);
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ab72900f/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/PEMGeneratorHostKeyProviderTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/PEMGeneratorHostKeyProviderTest.java
 
b/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/PEMGeneratorHostKeyProviderTest.java
index 6f35a61..0619cab 100644
--- 
a/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/PEMGeneratorHostKeyProviderTest.java
+++ 
b/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/PEMGeneratorHostKeyProviderTest.java
@@ -62,7 +62,7 @@ public class PEMGeneratorHostKeyProviderTest extends 
BaseTestSupport {
     @Test
     public void testECnistp256() throws IOException {
         Assume.assumeTrue("BouncyCastle not registered", 
SecurityUtils.isBouncyCastleRegistered());
-        Assume.assumeTrue("ECC not supported", SecurityUtils.hasEcc());
+        Assume.assumeTrue("ECC not supported", SecurityUtils.isECCSupported());
         Assume.assumeTrue(ECCurves.nistp256 + " N/A", 
ECCurves.nistp256.isSupported());
         testPEMGeneratorHostKeyProvider(KeyUtils.EC_ALGORITHM, 
KeyPairProvider.ECDSA_SHA2_NISTP256, -1, new ECGenParameterSpec("prime256v1"));
     }
@@ -70,7 +70,7 @@ public class PEMGeneratorHostKeyProviderTest extends 
BaseTestSupport {
     @Test
     public void testECnistp384() throws IOException {
         Assume.assumeTrue("BouncyCastle not registered", 
SecurityUtils.isBouncyCastleRegistered());
-        Assume.assumeTrue("ECC not supported", SecurityUtils.hasEcc());
+        Assume.assumeTrue("ECC not supported", SecurityUtils.isECCSupported());
         Assume.assumeTrue(ECCurves.nistp384 + " N/A", 
ECCurves.nistp384.isSupported());
         testPEMGeneratorHostKeyProvider(KeyUtils.EC_ALGORITHM, 
KeyPairProvider.ECDSA_SHA2_NISTP384, -1, new ECGenParameterSpec("P-384"));
     }
@@ -78,7 +78,7 @@ public class PEMGeneratorHostKeyProviderTest extends 
BaseTestSupport {
     @Test
     public void testECnistp521() throws IOException {
         Assume.assumeTrue("BouncyCastle not registered", 
SecurityUtils.isBouncyCastleRegistered());
-        Assume.assumeTrue("ECC not supported", SecurityUtils.hasEcc());
+        Assume.assumeTrue("ECC not supported", SecurityUtils.isECCSupported());
         Assume.assumeTrue(ECCurves.nistp521 + " N/A", 
ECCurves.nistp521.isSupported());
         testPEMGeneratorHostKeyProvider(KeyUtils.EC_ALGORITHM, 
KeyPairProvider.ECDSA_SHA2_NISTP521, -1, new ECGenParameterSpec("P-521"));
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ab72900f/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProviderTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProviderTest.java
 
b/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProviderTest.java
index 2b8db21..4075f4e 100644
--- 
a/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProviderTest.java
+++ 
b/sshd-core/src/test/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProviderTest.java
@@ -60,7 +60,7 @@ public class SimpleGeneratorHostKeyProviderTest extends 
BaseTestSupport {
     @Test
     public void testECnistp256() throws IOException {
         Assume.assumeTrue("BouncyCastle not registered", 
SecurityUtils.isBouncyCastleRegistered());
-        Assume.assumeTrue("ECC not supported", SecurityUtils.hasEcc());
+        Assume.assumeTrue("ECC not supported", SecurityUtils.isECCSupported());
         Assume.assumeTrue(ECCurves.nistp256 + " N/A", 
ECCurves.nistp256.isSupported());
         testSimpleGeneratorHostKeyProvider(KeyUtils.EC_ALGORITHM, 
KeyPairProvider.ECDSA_SHA2_NISTP256, -1, new ECGenParameterSpec("prime256v1"));
     }
@@ -68,7 +68,7 @@ public class SimpleGeneratorHostKeyProviderTest extends 
BaseTestSupport {
     @Test
     public void testECnistp384() throws IOException {
         Assume.assumeTrue("BouncyCastle not registered", 
SecurityUtils.isBouncyCastleRegistered());
-        Assume.assumeTrue("ECC not supported", SecurityUtils.hasEcc());
+        Assume.assumeTrue("ECC not supported", SecurityUtils.isECCSupported());
         Assume.assumeTrue(ECCurves.nistp384 + " N/A", 
ECCurves.nistp384.isSupported());
         testSimpleGeneratorHostKeyProvider(KeyUtils.EC_ALGORITHM, 
KeyPairProvider.ECDSA_SHA2_NISTP384, -1, new ECGenParameterSpec("P-384"));
     }
@@ -76,7 +76,7 @@ public class SimpleGeneratorHostKeyProviderTest extends 
BaseTestSupport {
     @Test
     public void testECnistp521() throws IOException {
         Assume.assumeTrue("BouncyCastle not registered", 
SecurityUtils.isBouncyCastleRegistered());
-        Assume.assumeTrue("ECC not supported", SecurityUtils.hasEcc());
+        Assume.assumeTrue("ECC not supported", SecurityUtils.isECCSupported());
         Assume.assumeTrue(ECCurves.nistp521 + " N/A", 
ECCurves.nistp521.isSupported());
         testSimpleGeneratorHostKeyProvider(KeyUtils.EC_ALGORITHM, 
KeyPairProvider.ECDSA_SHA2_NISTP521, -1, new ECGenParameterSpec("P-521"));
     }

Reply via email to