[SSHD-757] Converted most of the key-pair identity loaders to return an 
Iterable<KeyPair> instead of single instance


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/3efd1edf
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/3efd1edf
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/3efd1edf

Branch: refs/heads/master
Commit: 3efd1edf63fbb406524bd9d0cfa563f3b2305789
Parents: 2f92fe5
Author: Lyor Goldstein <[email protected]>
Authored: Tue Nov 20 11:50:58 2018 +0200
Committer: Lyor Goldstein <[email protected]>
Committed: Thu Nov 22 07:05:16 2018 +0200

----------------------------------------------------------------------
 CHANGES.md                                      |  3 +
 README.md                                       |  2 +-
 .../java/org/apache/sshd/cli/CliSupport.java    |  2 +-
 .../apache/sshd/cli/client/ScpCommandMain.java  |  2 +-
 .../sshd/cli/client/SshClientCliSupport.java    | 20 ++---
 .../sshd/cli/server/SshServerCliSupport.java    | 26 +++++--
 .../apache/sshd/cli/client/ChannelExecMain.java |  2 +-
 .../apache/sshd/cli/server/SshFsMounter.java    |  2 +-
 .../config/keys/ClientIdentitiesWatcher.java    |  6 +-
 .../config/keys/ClientIdentityFileWatcher.java  | 43 +++++------
 .../config/keys/ClientIdentityLoader.java       |  6 +-
 .../config/keys/ClientIdentityProvider.java     | 13 ++--
 .../config/keys/LazyClientIdentityIterator.java | 20 +++--
 .../keys/LazyClientKeyIdentityProvider.java     | 16 +++-
 .../sshd/common/config/keys/IdentityUtils.java  | 23 ++++--
 .../AbstractResourceKeyPairProvider.java        | 54 +++++++-------
 .../common/keyprovider/FileKeyPairProvider.java |  4 +-
 .../common/keyprovider/KeyIdentityProvider.java | 18 +++++
 .../common/util/security/SecurityUtils.java     | 11 +--
 .../AbstractGeneratorHostKeyProvider.java       | 77 ++++++++++++--------
 .../SimpleGeneratorHostKeyProvider.java         |  8 +-
 .../BuiltinClientIdentitiesWatcherTest.java     |  6 +-
 .../keys/ClientIdentityFileWatcherTest.java     | 14 ++--
 .../pem/PKCS8PEMResourceKeyPairParserTest.java  | 11 ++-
 .../AbstractGeneratorHostKeyProviderTest.java   |  2 +-
 .../keys/LazyClientIdentityIteratorTest.java    |  7 +-
 .../hosts/HostConfigEntryResolverTest.java      |  8 +-
 .../sshd/common/auth/AuthenticationTest.java    |  5 +-
 28 files changed, 253 insertions(+), 158 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/CHANGES.md
----------------------------------------------------------------------
diff --git a/CHANGES.md b/CHANGES.md
index db1e874..0c59a22 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -68,6 +68,9 @@ accept also an `AttributeRepository` connection context 
argument (propagated fro
 
 * Removed API(s) that used string file paths to create `FileInputStream`-s - 
using only `java.nio.file.Path`-s
 
+* Converted most of the key-pair identity loaders (e.g., 
`ClientIdentityLoader`, `ClientIdentityProvider`, etc.)
+to return an `Iterable<KeyPair>` instead of single `KeyPair` instance.
+
 ## Behavioral changes and enhancements
 
 * [SSHD-757](https://issues.apache.org/jira/browse/SSHD-757) - Added hooks and 
some initial code to allow (limited) usage

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 811911d..6c8a1cb 100644
--- a/README.md
+++ b/README.md
@@ -1936,7 +1936,7 @@ This code relies on the 
[jpgpgj](https://github.com/justinludwig/jpgpj) support
 
 In order to be able to read `authorized_keys` files that may contain _OpenPGP_ 
keys references, one needs to register
 the relevant `PublicKeyEntryDataResolver`-s. This is done by calling 
`PGPPublicKeyEntryDataResolver#registerDefaultKeyEntryDataResolvers`
-once during the _main_ code setup. This will enable the code to read 
authorized keys entries having the format
+once during the _main_ code setup. This will enable the code to safely read 
authorized keys entries having the format
 specified in the [OpenSSH PGP 
configuration](https://www.red-bean.com/~nemo/openssh-gpg/):
 
 ```

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-cli/src/main/java/org/apache/sshd/cli/CliSupport.java
----------------------------------------------------------------------
diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/CliSupport.java 
b/sshd-cli/src/main/java/org/apache/sshd/cli/CliSupport.java
index 1ba94d2..8e59456 100644
--- a/sshd-cli/src/main/java/org/apache/sshd/cli/CliSupport.java
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/CliSupport.java
@@ -48,7 +48,7 @@ public abstract class CliSupport {
     }
 
     public static boolean showError(PrintStream stderr, String message) {
-        stderr.println(message);
+        stderr.append("ERROR: ").println(message);
         return true;
     }
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-cli/src/main/java/org/apache/sshd/cli/client/ScpCommandMain.java
----------------------------------------------------------------------
diff --git 
a/sshd-cli/src/main/java/org/apache/sshd/cli/client/ScpCommandMain.java 
b/sshd-cli/src/main/java/org/apache/sshd/cli/client/ScpCommandMain.java
index 3421cca..88910c2 100644
--- a/sshd-cli/src/main/java/org/apache/sshd/cli/client/ScpCommandMain.java
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/client/ScpCommandMain.java
@@ -149,7 +149,7 @@ public class ScpCommandMain extends SshClientCliSupport {
             Class<?> clazz = cl.loadClass(className);
             return ScpClientCreator.class.cast(clazz.newInstance());
         } catch (Exception e) {
-            stderr.append("Failed 
(").append(e.getClass().getSimpleName()).append(')')
+            stderr.append("WARNING: Failed 
(").append(e.getClass().getSimpleName()).append(')')
                 .append(" to instantiate ").append(className)
                 .append(": ").println(e.getMessage());
             stderr.flush();

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshClientCliSupport.java
----------------------------------------------------------------------
diff --git 
a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshClientCliSupport.java 
b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshClientCliSupport.java
index 4741e72..6917c94 100644
--- a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshClientCliSupport.java
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshClientCliSupport.java
@@ -397,7 +397,8 @@ public abstract class SshClientCliSupport extends 
CliSupport {
                         answers[i] = stdin.readLine();
                     }
                 } catch (IOException e) {
-                    stderr.append(e.getClass().getSimpleName()).append(" while 
read prompts: ").println(e.getMessage());
+                    stderr.append("WARNING: 
").append(e.getClass().getSimpleName())
+                        .append(" while read prompts: 
").println(e.getMessage());
                 }
                 return answers;
             }
@@ -408,7 +409,8 @@ public abstract class SshClientCliSupport extends 
CliSupport {
                 try {
                     return stdin.readLine();
                 } catch (IOException e) {
-                    stderr.append(e.getClass().getSimpleName()).append(" while 
read password: ").println(e.getMessage());
+                    stderr.append("WARNING: 
").append(e.getClass().getSimpleName())
+                        .append(" while read password: 
").println(e.getMessage());
                     return null;
                 }
             }
@@ -438,11 +440,11 @@ public abstract class SshClientCliSupport extends 
CliSupport {
         }
 
         ((KnownHostsServerKeyVerifier) 
current).setModifiedServerKeyAcceptor((clientSession, remoteAddress, entry, 
expected, actual) -> {
-            stderr.append("Mismatched keys presented by 
").append(Objects.toString(remoteAddress))
+            stderr.append("WARNING: Mismatched keys presented by 
").append(Objects.toString(remoteAddress))
                   .append(" for entry=").println(entry);
-            
stderr.append('\t').append("Expected=").append(KeyUtils.getKeyType(expected))
+            stderr.append("    
").append("Expected=").append(KeyUtils.getKeyType(expected))
                   .append('-').println(KeyUtils.getFingerPrint(expected));
-            
stderr.append('\t').append("Actual=").append(KeyUtils.getKeyType(actual))
+            stderr.append("    
").append("Actual=").append(KeyUtils.getKeyType(actual))
                   .append('-').println(KeyUtils.getFingerPrint(actual));
             stderr.flush(); // just making sure
 
@@ -538,7 +540,7 @@ public abstract class SshClientCliSupport extends 
CliSupport {
 
         Collection<String> unsupported = result.getUnsupportedFactories();
         if (GenericUtils.size(unsupported) > 0) {
-            stderr.append("Ignored unsupported compressions: 
").println(GenericUtils.join(unsupported, ','));
+            stderr.append("WARNING: Ignored unsupported compressions: 
").println(GenericUtils.join(unsupported, ','));
         }
 
         return new ArrayList<>(available);
@@ -566,7 +568,7 @@ public abstract class SshClientCliSupport extends 
CliSupport {
 
         Collection<String> unsupported = result.getUnsupportedFactories();
         if (GenericUtils.size(unsupported) > 0) {
-            stderr.append("Ignored unsupported MACs: 
").println(GenericUtils.join(unsupported, ','));
+            stderr.append("WARNING: Ignored unsupported MACs: 
").println(GenericUtils.join(unsupported, ','));
         }
 
         return new ArrayList<>(available);
@@ -589,13 +591,13 @@ public abstract class SshClientCliSupport extends 
CliSupport {
         BuiltinCiphers.ParseResult result = 
BuiltinCiphers.parseCiphersList(argVal);
         Collection<? extends NamedFactory<Cipher>> available = 
result.getParsedFactories();
         if (GenericUtils.isEmpty(available)) {
-            showError(stderr, "No known ciphers in " + argVal);
+            showError(stderr, "WARNING: No known ciphers in " + argVal);
             return null;
         }
 
         Collection<String> unsupported = result.getUnsupportedFactories();
         if (GenericUtils.size(unsupported) > 0) {
-            stderr.append("Ignored unsupported ciphers: 
").println(GenericUtils.join(unsupported, ','));
+            stderr.append("WARNING: Ignored unsupported ciphers: 
").println(GenericUtils.join(unsupported, ','));
         }
 
         return new ArrayList<>(available);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java
----------------------------------------------------------------------
diff --git 
a/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java 
b/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java
index 2521ea1..a5357f5 100644
--- a/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java
@@ -117,19 +117,33 @@ public abstract class SshServerCliSupport extends 
CliSupport {
             for (String keyFilePath : keyFiles) {
                 Path path = Paths.get(keyFilePath);
                 PathResource location = new PathResource(path);
+                Iterable<KeyPair> ids;
                 try (InputStream inputStream = location.openInputStream()) {
-                    KeyPair kp = SecurityUtils.loadKeyPairIdentity(null, 
location, inputStream, null);
-                    pairs.add(kp);
+                    ids = SecurityUtils.loadKeyPairIdentities(null, location, 
inputStream, null);
                 } catch (Exception e) {
-                    stderr.append("Failed 
(").append(e.getClass().getSimpleName()).append(')')
+                    stderr.append("ERROR: Failed 
(").append(e.getClass().getSimpleName()).append(')')
                         .append(" to load host key file=").append(keyFilePath)
                         .append(": ").println(e.getMessage());
                     stderr.flush();
                     throw e;
                 }
+
+                if (ids == null) {
+                    stderr.append("WARNING: No keys loaded from 
").println(keyFilePath);
+                    continue;
+                }
+
+                for (KeyPair kp : ids) {
+                    if (kp == null) {
+                        stderr.append("WARNING: empty key found in 
").println(keyFilePath);
+                        continue;   // debug breakpoint
+                    }
+                    pairs.add(kp);
+                }
             }
 
-            return new MappedKeyPairProvider(pairs);
+            return new MappedKeyPairProvider(
+                ValidateUtils.checkNotNullAndNotEmpty(pairs, "No key pairs 
loaded for provided key files"));
         }
     }
 
@@ -157,7 +171,7 @@ public abstract class SshServerCliSupport extends 
CliSupport {
                     SubsystemFactory factory = 
SubsystemFactory.class.cast(clazz.newInstance());
                     subsystems.add(factory);
                 } catch (Exception e) {
-                    stderr.append("Failed 
(").append(e.getClass().getSimpleName()).append(')')
+                    stderr.append("ERROR: Failed 
(").append(e.getClass().getSimpleName()).append(')')
                         .append(" to instantiate subsystem=").append(fqcn)
                         .append(": ").println(e.getMessage());
                     stderr.flush();
@@ -208,7 +222,7 @@ public abstract class SshServerCliSupport extends 
CliSupport {
             Object instance = clazz.newInstance();
             return ShellFactory.class.cast(instance);
         } catch (Exception e) {
-            stderr.append("Failed 
(").append(e.getClass().getSimpleName()).append(')')
+            stderr.append("ERROR: Failed 
(").append(e.getClass().getSimpleName()).append(')')
                 .append(" to instantiate shell factory=").append(factory)
                 .append(": ").println(e.getMessage());
             stderr.flush();

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-cli/src/test/java/org/apache/sshd/cli/client/ChannelExecMain.java
----------------------------------------------------------------------
diff --git 
a/sshd-cli/src/test/java/org/apache/sshd/cli/client/ChannelExecMain.java 
b/sshd-cli/src/test/java/org/apache/sshd/cli/client/ChannelExecMain.java
index 99d0a7d..8afcd42 100644
--- a/sshd-cli/src/test/java/org/apache/sshd/cli/client/ChannelExecMain.java
+++ b/sshd-cli/src/test/java/org/apache/sshd/cli/client/ChannelExecMain.java
@@ -59,7 +59,7 @@ public class ChannelExecMain extends BaseTestSupport {
                         stdout.append('\t').println(l);
                     }
                 } catch (Exception e) {
-                    stderr.append(e.getClass().getSimpleName()).append(": 
").println(e.getMessage());
+                    stderr.append("WARNING: 
").append(e.getClass().getSimpleName()).append(": ").println(e.getMessage());
                 }
 
                 stdout.append("Execute ").append(command).print(" again [y]/n 
");

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-cli/src/test/java/org/apache/sshd/cli/server/SshFsMounter.java
----------------------------------------------------------------------
diff --git 
a/sshd-cli/src/test/java/org/apache/sshd/cli/server/SshFsMounter.java 
b/sshd-cli/src/test/java/org/apache/sshd/cli/server/SshFsMounter.java
index 0fbc926..6c17416 100644
--- a/sshd-cli/src/test/java/org/apache/sshd/cli/server/SshFsMounter.java
+++ b/sshd-cli/src/test/java/org/apache/sshd/cli/server/SshFsMounter.java
@@ -126,7 +126,7 @@ public final class SshFsMounter extends SshServerCliSupport 
{
                 callback.onExit(0);
             } catch (Exception e) {
                 log.error("run(" + username + ")[" + command + "] " + 
e.getClass().getSimpleName() + ": " + e.getMessage(), e);
-                stderr.append(e.getClass().getSimpleName()).append(": 
").println(e.getMessage());
+                stderr.append("ERROR: 
").append(e.getClass().getSimpleName()).append(": ").println(e.getMessage());
                 callback.onExit(-1, e.toString());
             }
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentitiesWatcher.java
----------------------------------------------------------------------
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentitiesWatcher.java
 
b/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentitiesWatcher.java
index d3e567c..dbf9c4a 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentitiesWatcher.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentitiesWatcher.java
@@ -75,12 +75,12 @@ public class ClientIdentitiesWatcher extends 
AbstractKeyPairProvider implements
     }
 
     protected Iterable<KeyPair> loadKeys(SessionContext session, Predicate<? 
super KeyPair> filter) {
-        return ClientIdentityProvider.lazyKeysLoader(providers, p -> 
doGetKeyPair(session, p), filter);
+        return ClientIdentityProvider.lazyKeysLoader(providers, p -> 
doGetKeyPairs(session, p), filter);
     }
 
-    protected KeyPair doGetKeyPair(SessionContext session, 
ClientIdentityProvider p) {
+    protected Iterable<KeyPair> doGetKeyPairs(SessionContext session, 
ClientIdentityProvider p) {
         try {
-            KeyPair kp = p.getClientIdentity(session);
+            Iterable<KeyPair> kp = p.getClientIdentities(session);
             if (kp == null) {
                 if (log.isDebugEnabled()) {
                     log.debug("loadKeys({}) no key loaded", p);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcher.java
----------------------------------------------------------------------
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcher.java
 
b/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcher.java
index 56f946d..eabfab8 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcher.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcher.java
@@ -45,7 +45,7 @@ import org.apache.sshd.common.util.io.resource.PathResource;
 public class ClientIdentityFileWatcher
         extends ModifiableFileWatcher
         implements ClientIdentityProvider, ClientIdentityLoaderHolder, 
FilePasswordProviderHolder {
-    private final AtomicReference<KeyPair> identityHolder = new 
AtomicReference<>(null);
+    private final AtomicReference<Iterable<KeyPair>> identitiesHolder = new 
AtomicReference<>(null);
     private final ClientIdentityLoaderHolder loaderHolder;
     private final FilePasswordProviderHolder providerHolder;
     private final boolean strict;
@@ -89,30 +89,27 @@ public class ClientIdentityFileWatcher
     }
 
     @Override
-    public KeyPair getClientIdentity(SessionContext session) throws 
IOException, GeneralSecurityException {
+    public Iterable<KeyPair> getClientIdentities(SessionContext session)
+            throws IOException, GeneralSecurityException {
         if (!checkReloadRequired()) {
-            return identityHolder.get();
+            return identitiesHolder.get();
         }
 
-        KeyPair kp = identityHolder.getAndSet(null);     // start fresh
+        Iterable<KeyPair> kp = identitiesHolder.getAndSet(null);     // start 
fresh
         Path path = getPath();
         if (!exists()) {
-            return identityHolder.get();
+            return identitiesHolder.get();
         }
 
-        KeyPair id = reloadClientIdentity(session, path);
-        if (!KeyUtils.compareKeyPairs(kp, id)) {
-            if (log.isDebugEnabled()) {
-                log.debug("getClientIdentity({}) identity {}", path, (kp == 
null) ? "loaded" : "re-loaded");
-            }
-        }
+        Iterable<KeyPair> id = reloadClientIdentities(session, path);
 
         updateReloadAttributes();
-        identityHolder.set(id);
-        return identityHolder.get();
+        identitiesHolder.set(id);
+        return identitiesHolder.get();
     }
 
-    protected KeyPair reloadClientIdentity(SessionContext session, Path path) 
throws IOException, GeneralSecurityException {
+    protected Iterable<KeyPair> reloadClientIdentities(SessionContext session, 
Path path)
+            throws IOException, GeneralSecurityException {
         if (isStrict()) {
             Map.Entry<String, Object> violation =
                 KeyUtils.validateStrictKeyFilePermissions(path, 
IoUtils.EMPTY_LINK_OPTIONS);
@@ -127,18 +124,22 @@ public class ClientIdentityFileWatcher
         PathResource location = new PathResource(path);
         ClientIdentityLoader idLoader = 
Objects.requireNonNull(getClientIdentityLoader(), "No client identity loader");
         if (idLoader.isValidLocation(location)) {
-            KeyPair kp = idLoader.loadClientIdentity(session, location, 
getFilePasswordProvider());
+            Iterable<KeyPair> ids = idLoader.loadClientIdentities(session, 
location, getFilePasswordProvider());
             if (log.isTraceEnabled()) {
-                PublicKey key = (kp == null) ? null : kp.getPublic();
-                if (key != null) {
-                    log.trace("reloadClientIdentity({}) loaded {}-{}",
-                          location, KeyUtils.getKeyType(key), 
KeyUtils.getFingerPrint(key));
+                if (ids == null) {
+                    log.trace("reloadClientIdentity({}) no keys loaded", 
location);
                 } else {
-                    log.trace("reloadClientIdentity({}) no key loaded", 
location);
+                    for (KeyPair kp : ids) {
+                        PublicKey key = (kp == null) ? null : kp.getPublic();
+                        if (key != null) {
+                            log.trace("reloadClientIdentity({}) loaded {}-{}",
+                                location, KeyUtils.getKeyType(key), 
KeyUtils.getFingerPrint(key));
+                        }
+                    }
                 }
             }
 
-            return kp;
+            return ids;
         }
 
         if (log.isDebugEnabled()) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityLoader.java
----------------------------------------------------------------------
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityLoader.java
 
b/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityLoader.java
index ceb914e..ae30f40 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityLoader.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityLoader.java
@@ -58,13 +58,13 @@ public interface ClientIdentityLoader {
         }
 
         @Override
-        public KeyPair loadClientIdentity(
+        public Iterable<KeyPair> loadClientIdentities(
                 SessionContext session, NamedResource location, 
FilePasswordProvider provider)
                     throws IOException, GeneralSecurityException {
             Path path = toPath(location);
             PathResource resource = new PathResource(path);
             try (InputStream inputStream = resource.openInputStream()) {
-                return SecurityUtils.loadKeyPairIdentity(session, resource, 
inputStream, provider);
+                return SecurityUtils.loadKeyPairIdentities(session, resource, 
inputStream, provider);
             }
         }
 
@@ -105,7 +105,7 @@ public interface ClientIdentityLoader {
      * @throws GeneralSecurityException If failed to convert the contents into
      * a valid identity
      */
-    KeyPair loadClientIdentity(
+    Iterable<KeyPair> loadClientIdentities(
         SessionContext session, NamedResource location, FilePasswordProvider 
provider)
             throws IOException, GeneralSecurityException;
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityProvider.java
----------------------------------------------------------------------
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityProvider.java
 
b/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityProvider.java
index 8c52d4f..9d0f989 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityProvider.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/client/config/keys/ClientIdentityProvider.java
@@ -40,24 +40,25 @@ public interface ClientIdentityProvider {
      *
      * @param session The {@link SessionContext} for invoking this load 
command - may
      * be {@code null} if not invoked within a session context (e.g., offline 
tool).
-     * @return The client identity - may be {@code null} if no currently
+     * @return The client identities - may be {@code null}/empty if no 
currently
      * available identity from this provider. <B>Note:</B> the provider
      * may return a <U>different</U> value every time this method is called
      * - e.g., if it is (re-)loading contents from a file.
      * @throws IOException If failed to load the identity
      * @throws GeneralSecurityException If failed to parse the identity
      */
-    KeyPair getClientIdentity(SessionContext session) throws IOException, 
GeneralSecurityException;
+    Iterable<KeyPair> getClientIdentities(SessionContext session)
+        throws IOException, GeneralSecurityException;
 
     /**
      * Wraps a {@link KeyPair} into a {@link ClientIdentityProvider} that
-     * simply returns this value as it {@link #getClientIdentity()}.
+     * simply returns this value as it {@link 
#getClientIdentities(SessionContext)}.
      *
      * @param kp The {@link KeyPair} instance (including {@code null})
      * @return The wrapping provider
      */
     static ClientIdentityProvider of(KeyPair kp) {
-        return session -> kp;
+        return session -> Collections.singletonList(kp);
     }
 
     /**
@@ -80,7 +81,7 @@ public interface ClientIdentityProvider {
      */
     static Iterable<KeyPair> lazyKeysLoader(
             Iterable<? extends ClientIdentityProvider> providers,
-            Function<? super ClientIdentityProvider, ? extends KeyPair> 
kpExtractor,
+            Function<? super ClientIdentityProvider, ? extends Iterable<? 
extends KeyPair>> kpExtractor,
             Predicate<? super KeyPair> filter) {
         Objects.requireNonNull(kpExtractor, "No key pair extractor provided");
         if (providers == null) {
@@ -116,7 +117,7 @@ public interface ClientIdentityProvider {
      */
     static Iterator<KeyPair> lazyKeysIterator(
             Iterator<? extends ClientIdentityProvider> providers,
-            Function<? super ClientIdentityProvider, ? extends KeyPair> 
kpExtractor,
+            Function<? super ClientIdentityProvider, ? extends Iterable<? 
extends KeyPair>> kpExtractor,
             Predicate<? super KeyPair> filter) {
         Objects.requireNonNull(kpExtractor, "No key pair extractor provided");
         return (providers == null)

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-common/src/main/java/org/apache/sshd/client/config/keys/LazyClientIdentityIterator.java
----------------------------------------------------------------------
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/client/config/keys/LazyClientIdentityIterator.java
 
b/sshd-common/src/main/java/org/apache/sshd/client/config/keys/LazyClientIdentityIterator.java
index b8b04ae..a3e5a2e 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/client/config/keys/LazyClientIdentityIterator.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/client/config/keys/LazyClientIdentityIterator.java
@@ -26,6 +26,8 @@ import java.util.Objects;
 import java.util.function.Function;
 import java.util.function.Predicate;
 
+import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
+
 /**
  * Wraps several {@link ClientIdentityProvider} into a {@link KeyPair}
  * {@link Iterator} that invokes each provider &quot;lazily&quot; - i.e.,
@@ -36,10 +38,11 @@ import java.util.function.Predicate;
  */
 public class LazyClientIdentityIterator implements Iterator<KeyPair> {
     protected boolean finished;
+    protected Iterator<? extends KeyPair> currentIdentities;
     protected KeyPair currentPair;
 
     private final Iterator<? extends ClientIdentityProvider> providers;
-    private final Function<? super ClientIdentityProvider, ? extends KeyPair> 
kpExtractor;
+    private final Function<? super ClientIdentityProvider, ? extends 
Iterable<? extends KeyPair>> kpExtractor;
     private final Predicate<? super KeyPair> filter;
 
     /**
@@ -52,7 +55,7 @@ public class LazyClientIdentityIterator implements 
Iterator<KeyPair> {
      */
     public LazyClientIdentityIterator(
             Iterator<? extends ClientIdentityProvider> providers,
-            Function<? super ClientIdentityProvider, ? extends KeyPair> 
kpExtractor,
+            Function<? super ClientIdentityProvider, ? extends Iterable<? 
extends KeyPair>> kpExtractor,
             Predicate<? super KeyPair> filter) {
         this.providers = providers;
         this.kpExtractor = Objects.requireNonNull(kpExtractor, "No key pair 
extractor provided");
@@ -63,7 +66,7 @@ public class LazyClientIdentityIterator implements 
Iterator<KeyPair> {
         return providers;
     }
 
-    public Function<? super ClientIdentityProvider, ? extends KeyPair> 
getIdentityExtractor() {
+    public Function<? super ClientIdentityProvider, ? extends Iterable<? 
extends KeyPair>> getIdentitiesExtractor() {
         return kpExtractor;
     }
 
@@ -83,7 +86,12 @@ public class LazyClientIdentityIterator implements 
Iterator<KeyPair> {
             return false;
         }
 
-        Function<? super ClientIdentityProvider, ? extends KeyPair> x = 
getIdentityExtractor();
+        currentPair = 
KeyIdentityProvider.exhaustCurrentIdentities(currentIdentities);
+        if (currentPair != null) {
+            return true;
+        }
+
+        Function<? super ClientIdentityProvider, ? extends Iterable<? extends 
KeyPair>> x = getIdentitiesExtractor();
         Predicate<? super KeyPair> f = getFilter();
         while (provs.hasNext()) {
             ClientIdentityProvider p = provs.next();
@@ -91,7 +99,9 @@ public class LazyClientIdentityIterator implements 
Iterator<KeyPair> {
                 continue;
             }
 
-            currentPair = x.apply(p);
+            Iterable<? extends KeyPair> ids = x.apply(p);
+            currentIdentities = (ids == null) ? null : ids.iterator();
+            currentPair = 
KeyIdentityProvider.exhaustCurrentIdentities(currentIdentities);
             if (currentPair == null) {
                 continue;
             }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-common/src/main/java/org/apache/sshd/client/config/keys/LazyClientKeyIdentityProvider.java
----------------------------------------------------------------------
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/client/config/keys/LazyClientKeyIdentityProvider.java
 
b/sshd-common/src/main/java/org/apache/sshd/client/config/keys/LazyClientKeyIdentityProvider.java
index 05596be..cd7a8e0 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/client/config/keys/LazyClientKeyIdentityProvider.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/client/config/keys/LazyClientKeyIdentityProvider.java
@@ -75,6 +75,7 @@ public class LazyClientKeyIdentityProvider implements 
KeyIdentityProvider, Clien
     }
 
     @Override
+    @SuppressWarnings("checkstyle:anoninnerlength")
     public Iterable<KeyPair> loadKeys(SessionContext session)
             throws IOException, GeneralSecurityException {
         Collection<? extends NamedResource> locs = getLocations();
@@ -84,6 +85,7 @@ public class LazyClientKeyIdentityProvider implements 
KeyIdentityProvider, Clien
 
         return () -> new Iterator<KeyPair>() {
             private final Iterator<? extends NamedResource> iter = 
locs.iterator();
+            private Iterator<KeyPair> currentIdentities;
             private KeyPair currentPair;
             private boolean finished;
 
@@ -93,15 +95,23 @@ public class LazyClientKeyIdentityProvider implements 
KeyIdentityProvider, Clien
                     return false;
                 }
 
+                currentPair = 
KeyIdentityProvider.exhaustCurrentIdentities(currentIdentities);
+                if (currentPair != null) {
+                    return true;
+                }
+
                 while (iter.hasNext()) {
                     NamedResource l = iter.next();
+                    Iterable<KeyPair> ids;
                     try {
-                        currentPair = loadClientIdentity(session, l);
+                        ids = loadClientIdentities(session, l);
                     } catch (IOException | GeneralSecurityException e) {
                         throw new RuntimeException("Failed (" + 
e.getClass().getSimpleName() + ")"
                             + " to load key from " + l.getName() + ": " + 
e.getMessage(), e);
                     }
 
+                    currentIdentities = (ids == null) ? null : ids.iterator();
+                    currentPair = 
KeyIdentityProvider.exhaustCurrentIdentities(currentIdentities);
                     if (currentPair != null) {
                         return true;
                     }
@@ -132,7 +142,7 @@ public class LazyClientKeyIdentityProvider implements 
KeyIdentityProvider, Clien
         };
     }
 
-    protected KeyPair loadClientIdentity(SessionContext session, NamedResource 
location)
+    protected Iterable<KeyPair> loadClientIdentities(SessionContext session, 
NamedResource location)
             throws IOException, GeneralSecurityException {
         ClientIdentityLoader loader = getClientIdentityLoader();
         boolean ignoreInvalid = isIgnoreNonExisting();
@@ -152,6 +162,6 @@ public class LazyClientKeyIdentityProvider implements 
KeyIdentityProvider, Clien
             throw e;
         }
 
-        return loader.loadClientIdentity(session, location, 
getFilePasswordProvider());
+        return loader.loadClientIdentities(session, location, 
getFilePasswordProvider());
     }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityUtils.java
----------------------------------------------------------------------
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityUtils.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityUtils.java
index 0212806..82f8454 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityUtils.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityUtils.java
@@ -28,6 +28,7 @@ import java.security.GeneralSecurityException;
 import java.security.KeyPair;
 import java.util.Collections;
 import java.util.Map;
+import java.util.NavigableMap;
 import java.util.TreeMap;
 
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
@@ -133,29 +134,37 @@ public final class IdentityUtils {
      *                 to {@code FilePasswordProvider#getPassword} is the path 
of the
      *                 file whose key is to be loaded
      * @param options  The {@link OpenOption}s to use when reading the key data
-     * @return A {@link Map} of the identities where key=identity type (case
+     * @return A {@link NavigableMap} of the identities where key=identity 
type (case
      * <U>insensitive</U>), value=the {@link KeyPair} of the identity
      * @throws IOException              If failed to access the file system
      * @throws GeneralSecurityException If failed to load the keys
      * @see SecurityUtils#loadKeyPairIdentity(String, InputStream, 
FilePasswordProvider)
      */
-    public static Map<String, KeyPair> loadIdentities(
+    public static NavigableMap<String, KeyPair> loadIdentities(
             SessionContext session, Map<String, ? extends Path> paths, 
FilePasswordProvider provider, OpenOption... options)
                 throws IOException, GeneralSecurityException {
         if (GenericUtils.isEmpty(paths)) {
-            return Collections.emptyMap();
+            return Collections.emptyNavigableMap();
         }
 
-        Map<String, KeyPair> ids = new 
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+        NavigableMap<String, KeyPair> ids = new 
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
         // Cannot use forEach because the potential for IOExceptions being 
thrown
         for (Map.Entry<String, ? extends Path> pe : paths.entrySet()) {
             String type = pe.getKey();
             Path path = pe.getValue();
-            PathResource location = new PathResource(path);
+            PathResource location = new PathResource(path, options);
+            Iterable<KeyPair> pairs;
             try (InputStream inputStream = location.openInputStream()) {
-                KeyPair kp = SecurityUtils.loadKeyPairIdentity(session, 
location, inputStream, provider);
+                pairs = SecurityUtils.loadKeyPairIdentities(session, location, 
inputStream, provider);
+            }
+
+            if (pairs == null) {
+                continue;
+            }
+
+            for (KeyPair kp : pairs) {
                 KeyPair prev = ids.put(type, kp);
-                ValidateUtils.checkTrue(prev == null, "Multiple keys for 
type=%s", type);
+                ValidateUtils.checkTrue(prev == null, "Multiple keys for 
type=%s due to %s", type, path);
             }
         }
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java
----------------------------------------------------------------------
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java
index fd33ec2..ff78317 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java
@@ -24,7 +24,6 @@ import java.io.InputStream;
 import java.io.StreamCorruptedException;
 import java.security.GeneralSecurityException;
 import java.security.KeyPair;
-import java.security.PublicKey;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
@@ -36,7 +35,6 @@ import java.util.TreeSet;
 
 import org.apache.sshd.common.NamedResource;
 import org.apache.sshd.common.config.keys.FilePasswordProvider;
-import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.session.SessionContext;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
@@ -55,7 +53,7 @@ public abstract class AbstractResourceKeyPairProvider<R> 
extends AbstractKeyPair
      * practice to have 2 key files that differ from one another only in their
      * case...
      */
-    private final Map<String, KeyPair> cacheMap = new 
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+    private final Map<String, Iterable<KeyPair>> cacheMap = new 
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
 
     protected AbstractResourceKeyPairProvider() {
         super();
@@ -126,60 +124,55 @@ public abstract class AbstractResourceKeyPairProvider<R> 
extends AbstractKeyPair
         return IoResource.forResource(resource);
     }
 
-    protected KeyPair doLoadKey(SessionContext session, R resource)
+    protected Iterable<KeyPair> doLoadKeys(SessionContext session, R resource)
             throws IOException, GeneralSecurityException {
         IoResource<?> ioResource =
             ValidateUtils.checkNotNull(getIoResource(session, resource), "No 
I/O resource available for %s", resource);
         String resourceKey =
             ValidateUtils.checkNotNullAndNotEmpty(ioResource.getName(), "No 
resource string value for %s", resource);
-        KeyPair kp;
+        Iterable<KeyPair> ids;
         synchronized (cacheMap) {
             // check if lucky enough to have already loaded this file
-            kp = cacheMap.get(resourceKey);
+            ids = cacheMap.get(resourceKey);
         }
 
-        if (kp != null) {
+        if (ids != null) {
             if (log.isTraceEnabled()) {
-                PublicKey key = kp.getPublic();
-                log.trace("doLoadKey({}) use cached key {}-{}",
-                      resourceKey, KeyUtils.getKeyType(key), 
KeyUtils.getFingerPrint(key));
+                log.trace("doLoadKeys({}) using cached identifiers", 
resourceKey);
             }
-            return kp;
+            return ids;
         }
 
-        kp = doLoadKey(session, ioResource, resource, getPasswordFinder());
-        if (kp != null) {
+        ids = doLoadKeys(session, ioResource, resource, getPasswordFinder());
+        if (ids != null) {
             boolean reusedKey;
             synchronized (cacheMap) {
                 // if somebody else beat us to it, use the cached key - just 
in case file contents changed
                 reusedKey = cacheMap.containsKey(resourceKey);
                 if (reusedKey) {
-                    kp = cacheMap.get(resourceKey);
+                    ids = cacheMap.get(resourceKey);
                 } else {
-                    cacheMap.put(resourceKey, kp);
+                    cacheMap.put(resourceKey, ids);
                 }
             }
 
             if (log.isDebugEnabled()) {
-                PublicKey key = kp.getPublic();
-                log.debug("doLoadKey({}) {} {}-{}",
-                      resourceKey, reusedKey ? "re-loaded" : "loaded",
-                      KeyUtils.getKeyType(key), KeyUtils.getFingerPrint(key));
+                log.debug("doLoadKeys({}) {}", resourceKey, reusedKey ? 
"re-loaded" : "loaded");
             }
         } else {
             if (log.isDebugEnabled()) {
-                log.debug("doLoadKey({}) no key loaded", resourceKey);
+                log.debug("doLoadKeys({}) no key loaded", resourceKey);
             }
         }
 
-        return kp;
+        return ids;
     }
 
-    protected KeyPair doLoadKey(
+    protected Iterable<KeyPair> doLoadKeys(
             SessionContext session, NamedResource resourceKey, R resource, 
FilePasswordProvider provider)
                 throws IOException, GeneralSecurityException {
         try (InputStream inputStream = openKeyPairResource(session, 
resourceKey, resource)) {
-            return doLoadKey(session, resourceKey, inputStream, provider);
+            return doLoadKeys(session, resourceKey, inputStream, provider);
         }
     }
 
@@ -193,15 +186,16 @@ public abstract class AbstractResourceKeyPairProvider<R> 
extends AbstractKeyPair
         throw new StreamCorruptedException("Cannot open resource data for " + 
resource);
     }
 
-    protected KeyPair doLoadKey(
+    protected Iterable<KeyPair> doLoadKeys(
             SessionContext session, NamedResource resourceKey, InputStream 
inputStream, FilePasswordProvider provider)
                 throws IOException, GeneralSecurityException {
-        return SecurityUtils.loadKeyPairIdentity(session, resourceKey, 
inputStream, provider);
+        return SecurityUtils.loadKeyPairIdentities(session, resourceKey, 
inputStream, provider);
     }
 
     protected class KeyPairIterator implements Iterator<KeyPair> {
         protected final SessionContext session;
         private final Iterator<? extends R> iterator;
+        private Iterator<KeyPair> currentIdentities;
         private KeyPair nextKeyPair;
         private boolean nextKeyPairSet;
 
@@ -233,11 +227,19 @@ public abstract class AbstractResourceKeyPairProvider<R> 
extends AbstractKeyPair
 
         @SuppressWarnings("synthetic-access")
         private boolean setNextObject() {
+            nextKeyPair = 
KeyIdentityProvider.exhaustCurrentIdentities(currentIdentities);
+            if (nextKeyPair != null) {
+                nextKeyPairSet = true;
+                return true;
+            }
+
             boolean debugEnabled = log.isDebugEnabled();
             while (iterator.hasNext()) {
                 R r = iterator.next();
                 try {
-                    nextKeyPair = doLoadKey(session, r);
+                    Iterable<KeyPair> ids = doLoadKeys(session, r);
+                    currentIdentities = (ids == null) ? null : ids.iterator();
+                    nextKeyPair = 
KeyIdentityProvider.exhaustCurrentIdentities(currentIdentities);
                 } catch (Throwable e) {
                     log.warn("Failed (" + e.getClass().getSimpleName() + ")"
                            + " to load key resource=" + r + ": " + 
e.getMessage());

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/FileKeyPairProvider.java
----------------------------------------------------------------------
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/FileKeyPairProvider.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/FileKeyPairProvider.java
index 613e0cf..acb1767 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/FileKeyPairProvider.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/FileKeyPairProvider.java
@@ -81,8 +81,8 @@ public class FileKeyPairProvider extends 
AbstractResourceKeyPairProvider<Path> {
     }
 
     @Override
-    protected KeyPair doLoadKey(SessionContext session, Path resource)
+    protected Iterable<KeyPair> doLoadKeys(SessionContext session, Path 
resource)
             throws IOException, GeneralSecurityException {
-        return super.doLoadKey(session, (resource == null) ? null : 
resource.toAbsolutePath());
+        return super.doLoadKeys(session, (resource == null) ? null : 
resource.toAbsolutePath());
     }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/KeyIdentityProvider.java
----------------------------------------------------------------------
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/KeyIdentityProvider.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/KeyIdentityProvider.java
index 6ce5996..dafbbaf 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/KeyIdentityProvider.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/KeyIdentityProvider.java
@@ -186,4 +186,22 @@ public interface KeyIdentityProvider {
     static KeyIdentityProvider wrapKeyPairs(Iterable<KeyPair> pairs) {
         return (pairs == null) ? EMPTY_KEYS_PROVIDER : session -> pairs;
     }
+
+    /**
+     * Attempts to find the first non-{@code null} {@link KeyPair}
+     *
+     * @param ids The {@link Iterator} - ignored if {@code null} or no next 
element available
+     * @return The first non-{@code null} key pair found in the iterator - 
{@code null} if
+     * all elements exhausted without such an entry
+     */
+    static KeyPair exhaustCurrentIdentities(Iterator<? extends KeyPair> ids) {
+        while ((ids != null) && ids.hasNext()) {
+            KeyPair kp = ids.next();
+            if (kp != null) {
+                return kp;
+            }
+        }
+
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-common/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java
----------------------------------------------------------------------
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 cac845e..622a55c 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
@@ -35,7 +35,6 @@ import java.security.PrivateKey;
 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;
@@ -477,11 +476,11 @@ public final class SecurityUtils {
      * @param inputStream The {@link InputStream} for the <U>private</U> key
      * @param provider    A {@link FilePasswordProvider} - may be {@code null}
      *                    if the loaded key is <U>guaranteed</U> not to be 
encrypted
-     * @return The loaded {@link KeyPair}
+     * @return The loaded {@link KeyPair}-s - or {@code null} if none loaded
      * @throws IOException              If failed to read/parse the input 
stream
      * @throws GeneralSecurityException If failed to generate the keys
      */
-    public static KeyPair loadKeyPairIdentity(
+    public static Iterable<KeyPair> loadKeyPairIdentities(
             SessionContext session, NamedResource resourceKey, InputStream 
inputStream, FilePasswordProvider provider)
                 throws IOException, GeneralSecurityException {
         KeyPairResourceParser parser = getKeyPairResourceParser();
@@ -495,11 +494,7 @@ public final class SecurityUtils {
             return null;
         }
 
-        if (numLoaded != 1) {
-            throw new InvalidKeySpecException("Multiple private key pairs N/A: 
" + resourceKey);
-        }
-
-        return GenericUtils.head(ids);
+        return ids;
     }
 
     /* -------------------------------------------------------------------- */

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-common/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java
----------------------------------------------------------------------
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java
 
b/sshd-common/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java
index 1ed3a6c..bce84d6 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java
@@ -30,6 +30,7 @@ import java.security.KeyPair;
 import java.security.KeyPairGenerator;
 import java.security.PublicKey;
 import java.security.spec.AlgorithmParameterSpec;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
@@ -43,6 +44,7 @@ import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.keyprovider.AbstractKeyPairProvider;
 import org.apache.sshd.common.keyprovider.KeySizeIndicator;
 import org.apache.sshd.common.session.SessionContext;
+import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.common.util.io.resource.PathResource;
 import org.apache.sshd.common.util.security.SecurityUtils;
@@ -61,7 +63,7 @@ public abstract class AbstractGeneratorHostKeyProvider
     public static final String DEFAULT_ALGORITHM = KeyUtils.RSA_ALGORITHM;
     public static final boolean DEFAULT_ALLOWED_TO_OVERWRITE = true;
 
-    private final AtomicReference<KeyPair> keyPairHolder = new 
AtomicReference<>();
+    private final AtomicReference<Iterable<KeyPair>> keyPairHolder = new 
AtomicReference<>();
 
     private Path path;
     private String algorithm = DEFAULT_ALGORITHM;
@@ -116,29 +118,27 @@ public abstract class AbstractGeneratorHostKeyProvider
     }
 
     public void clearLoadedKeys() {
-        KeyPair kp;
+        Iterable<KeyPair> ids;
         synchronized (keyPairHolder) {
-            kp = keyPairHolder.getAndSet(null);
+            ids = keyPairHolder.getAndSet(null);
         }
 
-        if ((kp != null) & log.isDebugEnabled()) {
-            PublicKey key = kp.getPublic();
-            log.debug("clearLoadedKeys({}) removed key={}-{}",
-                  getPath(), KeyUtils.getKeyType(key), 
KeyUtils.getFingerPrint(key));
+        if ((ids != null) & log.isDebugEnabled()) {
+            log.debug("clearLoadedKeys({}) removed keys", getPath());
         }
     }
 
     @Override   // co-variant return
     public synchronized List<KeyPair> loadKeys(SessionContext session) {
         Path keyPath = getPath();
-        KeyPair kp;
+        Iterable<KeyPair> ids;
         synchronized (keyPairHolder) {
-            kp = keyPairHolder.get();
-            if (kp == null) {
+            ids = keyPairHolder.get();
+            if (ids == null) {
                 try {
-                    kp = resolveKeyPair(session, keyPath);
-                    if (kp != null) {
-                        keyPairHolder.set(kp);
+                    ids = resolveKeyPairs(session, keyPath);
+                    if (ids != null) {
+                        keyPairHolder.set(ids);
                     }
                 } catch (Throwable t) {
                     log.warn("loadKeys({}) Failed ({}) to resolve: {}",
@@ -150,21 +150,32 @@ public abstract class AbstractGeneratorHostKeyProvider
             }
         }
 
-        if (kp == null) {
-            return Collections.emptyList();
-        } else {
-            return Collections.singletonList(kp);
+        List<KeyPair> pairs = Collections.emptyList();
+        if (ids instanceof List<?>) {
+            pairs = (List<KeyPair>) ids;
+        } else if (ids != null) {
+            pairs = new ArrayList<>();
+            for (KeyPair kp : ids) {
+                if (kp == null) {
+                    continue;
+                }
+
+                pairs.add(kp);
+            }
         }
+
+        return pairs;
     }
 
-    protected KeyPair resolveKeyPair(SessionContext session, Path keyPath) 
throws IOException, GeneralSecurityException {
+    protected Iterable<KeyPair> resolveKeyPairs(SessionContext session, Path 
keyPath)
+            throws IOException, GeneralSecurityException {
         String alg = getAlgorithm();
-        KeyPair kp;
         if (keyPath != null) {
             try {
-                kp = loadFromFile(session, alg, keyPath);
+                Iterable<KeyPair> ids = loadFromFile(session, alg, keyPath);
+                KeyPair kp = GenericUtils.head(ids);
                 if (kp != null) {
-                    return kp;
+                    return ids;
                 }
             } catch (Throwable e) {
                 log.warn("resolveKeyPair({}) Failed ({}) to load: {}",
@@ -176,6 +187,7 @@ public abstract class AbstractGeneratorHostKeyProvider
         }
 
         // either no file specified or no key in file
+        KeyPair kp = null;
         try {
             kp = generateKeyPair(alg);
             if (kp == null) {
@@ -185,11 +197,11 @@ public abstract class AbstractGeneratorHostKeyProvider
             if (log.isDebugEnabled()) {
                 PublicKey key = kp.getPublic();
                 log.debug("resolveKeyPair({}) generated {} key={}-{}",
-                          keyPath, alg, KeyUtils.getKeyType(key), 
KeyUtils.getFingerPrint(key));
+                      keyPath, alg, KeyUtils.getKeyType(key), 
KeyUtils.getFingerPrint(key));
             }
         } catch (Throwable e) {
             log.warn("resolveKeyPair({})[{}] Failed ({}) to generate {} 
key-pair: {}",
-                     keyPath, alg, e.getClass().getSimpleName(), alg, 
e.getMessage());
+                 keyPath, alg, e.getClass().getSimpleName(), alg, 
e.getMessage());
             if (log.isDebugEnabled()) {
                 log.debug("resolveKeyPair(" + keyPath + ")[" + alg + "] 
key-pair generation failure details", e);
             }
@@ -209,20 +221,23 @@ public abstract class AbstractGeneratorHostKeyProvider
             }
         }
 
-        return kp;
+        return Collections.singletonList(kp);
     }
 
-    protected KeyPair loadFromFile(SessionContext session, String alg, Path 
keyPath) throws IOException, GeneralSecurityException {
+    protected Iterable<KeyPair> loadFromFile(SessionContext session, String 
alg, Path keyPath)
+            throws IOException, GeneralSecurityException {
         LinkOption[] options = IoUtils.getLinkOptions(true);
         if ((!Files.exists(keyPath, options)) || 
(!Files.isRegularFile(keyPath, options))) {
             return null;
         }
 
-        KeyPair kp = readKeyPair(session, keyPath, IoUtils.EMPTY_OPEN_OPTIONS);
+        Iterable<KeyPair> ids = readKeyPairs(session, keyPath, 
IoUtils.EMPTY_OPEN_OPTIONS);
+        KeyPair kp = GenericUtils.head(ids);
         if (kp == null) {
             return null;
         }
 
+        // Assume all keys are of same type
         PublicKey key = kp.getPublic();
         String keyAlgorithm = key.getAlgorithm();
         if (BuiltinIdentities.Constants.ECDSA.equalsIgnoreCase(keyAlgorithm)) {
@@ -236,7 +251,7 @@ public abstract class AbstractGeneratorHostKeyProvider
                 log.debug("resolveKeyPair({}) loaded key={}-{}",
                       keyPath, KeyUtils.getKeyType(key), 
KeyUtils.getFingerPrint(key));
             }
-            return kp;
+            return ids;
         }
 
         // Not same algorithm - start again
@@ -248,17 +263,17 @@ public abstract class AbstractGeneratorHostKeyProvider
         return null;
     }
 
-    protected KeyPair readKeyPair(SessionContext session, Path keyPath, 
OpenOption... options)
+    protected Iterable<KeyPair> readKeyPairs(SessionContext session, Path 
keyPath, OpenOption... options)
             throws IOException, GeneralSecurityException {
         PathResource location = new PathResource(keyPath, options);
         try (InputStream inputStream = location.openInputStream()) {
-            return doReadKeyPair(session, location, inputStream);
+            return doReadKeyPairs(session, location, inputStream);
         }
     }
 
-    protected KeyPair doReadKeyPair(SessionContext session, NamedResource 
resourceKey, InputStream inputStream)
+    protected Iterable<KeyPair> doReadKeyPairs(SessionContext session, 
NamedResource resourceKey, InputStream inputStream)
             throws IOException, GeneralSecurityException {
-        return SecurityUtils.loadKeyPairIdentity(session, resourceKey, 
inputStream, null);
+        return SecurityUtils.loadKeyPairIdentities(session, resourceKey, 
inputStream, null);
     }
 
     protected void writeKeyPair(KeyPair kp, Path keyPath, OpenOption... 
options)

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-common/src/main/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProvider.java
----------------------------------------------------------------------
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProvider.java
 
b/sshd-common/src/main/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProvider.java
index c0ccd16..95c6bb0 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProvider.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/server/keyprovider/SimpleGeneratorHostKeyProvider.java
@@ -27,6 +27,7 @@ import java.nio.file.Path;
 import java.security.GeneralSecurityException;
 import java.security.KeyPair;
 import java.security.spec.InvalidKeySpecException;
+import java.util.Collections;
 
 import org.apache.sshd.common.NamedResource;
 import org.apache.sshd.common.session.SessionContext;
@@ -46,15 +47,18 @@ public class SimpleGeneratorHostKeyProvider extends 
AbstractGeneratorHostKeyProv
     }
 
     @Override
-    protected KeyPair doReadKeyPair(SessionContext session, NamedResource 
resourceKey, InputStream inputStream)
+    protected Iterable<KeyPair> doReadKeyPairs(SessionContext session, 
NamedResource resourceKey, InputStream inputStream)
             throws IOException, GeneralSecurityException {
+        KeyPair kp;
         try (ObjectInputStream r = new ObjectInputStream(inputStream)) {
             try {
-                return (KeyPair) r.readObject();
+                kp = (KeyPair) r.readObject();
             } catch (ClassNotFoundException e) {
                 throw new InvalidKeySpecException("Missing classes: " + 
e.getMessage(), e);
             }
         }
+
+        return Collections.singletonList(kp);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-common/src/test/java/org/apache/sshd/client/config/keys/BuiltinClientIdentitiesWatcherTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-common/src/test/java/org/apache/sshd/client/config/keys/BuiltinClientIdentitiesWatcherTest.java
 
b/sshd-common/src/test/java/org/apache/sshd/client/config/keys/BuiltinClientIdentitiesWatcherTest.java
index 64573c4..6e6541f 100644
--- 
a/sshd-common/src/test/java/org/apache/sshd/client/config/keys/BuiltinClientIdentitiesWatcherTest.java
+++ 
b/sshd-common/src/test/java/org/apache/sshd/client/config/keys/BuiltinClientIdentitiesWatcherTest.java
@@ -30,6 +30,7 @@ import java.security.GeneralSecurityException;
 import java.security.KeyPair;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
 import java.util.EnumMap;
 import java.util.Map;
@@ -80,12 +81,13 @@ public class BuiltinClientIdentitiesWatcherTest extends 
JUnitTestSupport {
 
         ClientIdentityLoader loader = new ClientIdentityLoader() {
             @Override
-            public KeyPair loadClientIdentity(
+            public Iterable<KeyPair> loadClientIdentities(
                     SessionContext session, NamedResource location, 
FilePasswordProvider provider)
                         throws IOException, GeneralSecurityException {
                 BuiltinIdentities id = findIdentity(location);
                 assertNotNull("Invalid location: " + location, id);
-                return idsMap.get(id);
+                KeyPair kp = idsMap.get(id);
+                return (kp == null) ? null : Collections.singletonList(kp);
             }
 
             @Override

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-common/src/test/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcherTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-common/src/test/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcherTest.java
 
b/sshd-common/src/test/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcherTest.java
index 2cf3828..4205205 100644
--- 
a/sshd-common/src/test/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcherTest.java
+++ 
b/sshd-common/src/test/java/org/apache/sshd/client/config/keys/ClientIdentityFileWatcherTest.java
@@ -28,6 +28,7 @@ import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
 import java.security.GeneralSecurityException;
 import java.security.KeyPair;
+import java.util.Collections;
 import java.util.Date;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -35,6 +36,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.sshd.common.NamedResource;
 import org.apache.sshd.common.config.keys.FilePasswordProvider;
 import org.apache.sshd.common.session.SessionContext;
+import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.util.test.CommonTestSupportUtils;
 import org.apache.sshd.util.test.JUnitTestSupport;
@@ -61,11 +63,11 @@ public class ClientIdentityFileWatcherTest extends 
JUnitTestSupport {
         KeyPair identity = 
CommonTestSupportUtils.getFirstKeyPair(createTestHostKeyProvider());
         ClientIdentityLoader loader = new ClientIdentityLoader() {
             @Override
-            public KeyPair loadClientIdentity(
+            public Iterable<KeyPair> loadClientIdentities(
                     SessionContext session, NamedResource location, 
FilePasswordProvider provider)
                         throws IOException, GeneralSecurityException {
                 assertTrue("Invalid location: " + location, 
isValidLocation(location));
-                return identity;
+                return Collections.singletonList(identity);
             }
 
             @Override
@@ -82,10 +84,11 @@ public class ClientIdentityFileWatcherTest extends 
JUnitTestSupport {
         AtomicInteger reloadCount = new AtomicInteger(0);
         ClientIdentityProvider idProvider = new 
ClientIdentityFileWatcher(idFile, loader, FilePasswordProvider.EMPTY, false) {
             @Override
-            protected KeyPair reloadClientIdentity(SessionContext session, 
Path path) throws IOException, GeneralSecurityException {
+            protected Iterable<KeyPair> reloadClientIdentities(SessionContext 
session, Path path)
+                    throws IOException, GeneralSecurityException {
                 assertEquals("Mismatched client identity path", idFile, path);
                 reloadCount.incrementAndGet();
-                return super.reloadClientIdentity(session, path);
+                return super.reloadClientIdentities(session, path);
             }
         };
         Files.deleteIfExists(idFile);
@@ -118,7 +121,8 @@ public class ClientIdentityFileWatcherTest extends 
JUnitTestSupport {
     private static void testIdentityReload(
             String phase, Number reloadCount, ClientIdentityProvider provider, 
KeyPair expectedIdentity, int expectedCount)
                 throws Exception {
-        KeyPair actualIdentity = provider.getClientIdentity(null);
+        Iterable<KeyPair> ids = provider.getClientIdentities(null);
+        KeyPair actualIdentity = GenericUtils.head(ids);
         assertSame(phase + ": mismatched identity", expectedIdentity, 
actualIdentity);
         assertEquals(phase + ": mismatched re-load count", expectedCount, 
reloadCount.intValue());
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java
 
b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java
index 445de2e..afa3738 100644
--- 
a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java
+++ 
b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java
@@ -33,6 +33,7 @@ import org.apache.commons.ssl.PEMItem;
 import org.apache.commons.ssl.PEMUtil;
 import org.apache.sshd.common.NamedResource;
 import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.security.SecurityUtils;
 import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory;
 import org.apache.sshd.util.test.JUnitTestSupport;
@@ -93,10 +94,12 @@ public class PKCS8PEMResourceKeyPairParserTest extends 
JUnitTestSupport {
             os.close();
 
             try (ByteArrayInputStream bais = new 
ByteArrayInputStream(os.toByteArray())) {
-                KeyPair kp2 = SecurityUtils.loadKeyPairIdentity(null, 
NamedResource.ofName(getCurrentTestName()), bais, null);
-
-                assertEquals("Mismatched public key", kp.getPublic(), 
kp2.getPublic());
-                assertEquals("Mismatched private key", prv1, kp2.getPrivate());
+                Iterable<KeyPair> ids = SecurityUtils.loadKeyPairIdentities(
+                        null, NamedResource.ofName(getCurrentTestName()), 
bais, null);
+                KeyPair kp2 = GenericUtils.head(ids);
+                assertNotNull("No identity loaded", kp2);
+                assertKeyEquals("Mismatched public key", kp.getPublic(), 
kp2.getPublic());
+                assertKeyEquals("Mismatched private key", prv1, 
kp2.getPrivate());
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-common/src/test/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProviderTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-common/src/test/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProviderTest.java
 
b/sshd-common/src/test/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProviderTest.java
index 7cd690c..29a77c7 100644
--- 
a/sshd-common/src/test/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProviderTest.java
+++ 
b/sshd-common/src/test/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProviderTest.java
@@ -69,7 +69,7 @@ public class AbstractGeneratorHostKeyProviderTest extends 
JUnitTestSupport {
         }
 
         @Override
-        protected KeyPair doReadKeyPair(
+        protected Iterable<KeyPair> doReadKeyPairs(
                 SessionContext session, NamedResource resourceKey, InputStream 
inputStream)
                     throws IOException, GeneralSecurityException {
             return null;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-common/src/test/java/rg/apache/sshd/client/config/keys/LazyClientIdentityIteratorTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-common/src/test/java/rg/apache/sshd/client/config/keys/LazyClientIdentityIteratorTest.java
 
b/sshd-common/src/test/java/rg/apache/sshd/client/config/keys/LazyClientIdentityIteratorTest.java
index 32f2712..8e072c1 100644
--- 
a/sshd-common/src/test/java/rg/apache/sshd/client/config/keys/LazyClientIdentityIteratorTest.java
+++ 
b/sshd-common/src/test/java/rg/apache/sshd/client/config/keys/LazyClientIdentityIteratorTest.java
@@ -23,6 +23,7 @@ import java.security.KeyPair;
 import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 
@@ -57,7 +58,7 @@ public class LazyClientIdentityIteratorTest extends 
JUnitTestSupport {
         Iterable<KeyPair> ids = ClientIdentityProvider.lazyKeysLoader(
             providers, p -> {
                 try {
-                    return p.getClientIdentity(null);
+                    return p.getClientIdentities(null);
                 } catch (Exception e) {
                     throw new RuntimeException("Unexpected " + 
e.getClass().getSimpleName() + ": " + e.getMessage(), e);
                 }
@@ -94,9 +95,9 @@ public class LazyClientIdentityIteratorTest extends 
JUnitTestSupport {
         }
 
         @Override
-        public KeyPair getClientIdentity(SessionContext session) {
+        public Iterable<KeyPair> getClientIdentities(SessionContext session) {
             loadCount++;
-            return getKeyPair();
+            return Collections.singletonList(getKeyPair());
         }
 
         @Override

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-core/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryResolverTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryResolverTest.java
 
b/sshd-core/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryResolverTest.java
index 8ede710..2fd8584 100644
--- 
a/sshd-core/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryResolverTest.java
+++ 
b/sshd-core/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryResolverTest.java
@@ -156,11 +156,11 @@ public class HostConfigEntryResolverTest extends 
BaseTestSupport {
             }
 
             @Override
-            public KeyPair loadClientIdentity(
+            public Iterable<KeyPair> loadClientIdentities(
                     SessionContext session, NamedResource location, 
FilePasswordProvider provider)
                         throws IOException, GeneralSecurityException {
                 if (isValidLocation(location)) {
-                    return identity;
+                    return Collections.singletonList(identity);
                 }
 
                 throw new FileNotFoundException("Unknown location: " + 
location);
@@ -223,12 +223,12 @@ public class HostConfigEntryResolverTest extends 
BaseTestSupport {
             }
 
             @Override
-            public KeyPair loadClientIdentity(
+            public Iterable<KeyPair> loadClientIdentities(
                     SessionContext session, NamedResource location, 
FilePasswordProvider provider)
                         throws IOException, GeneralSecurityException {
                 if (isValidLocation(location)) {
                     specificIdentityLoadCount.incrementAndGet();
-                    return specificIdentity;
+                    return Collections.singletonList(specificIdentity);
                 }
 
                 throw new FileNotFoundException("Unknown location: " + 
location);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3efd1edf/sshd-core/src/test/java/org/apache/sshd/common/auth/AuthenticationTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/common/auth/AuthenticationTest.java 
b/sshd-core/src/test/java/org/apache/sshd/common/auth/AuthenticationTest.java
index 34c418b..a2f3374 100644
--- 
a/sshd-core/src/test/java/org/apache/sshd/common/auth/AuthenticationTest.java
+++ 
b/sshd-core/src/test/java/org/apache/sshd/common/auth/AuthenticationTest.java
@@ -924,11 +924,12 @@ public class AuthenticationTest extends BaseTestSupport {
                         URL location = getClass().getResource(keyLocation);
                         assertNotNull("Missing key file " + keyLocation, 
location);
 
-                        KeyPair kp;
                         URLResource resourceKey = new URLResource(location);
+                        Iterable<KeyPair> ids;
                         try (InputStream keyData = 
resourceKey.openInputStream()) {
-                            kp = SecurityUtils.loadKeyPairIdentity(session, 
resourceKey, keyData, passwordProvider);
+                            ids = SecurityUtils.loadKeyPairIdentities(session, 
resourceKey, keyData, passwordProvider);
                         }
+                        KeyPair kp = GenericUtils.head(ids);
                         assertNotNull("No identity loaded from " + 
resourceKey, kp);
                         return Collections.singletonList(kp);
                     }

Reply via email to