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

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


The following commit(s) were added to refs/heads/master by this push:
     new a52b1b3  [SSHD-1063] Fixed known-hosts file server key verifier 
matching of same host with different ports
a52b1b3 is described below

commit a52b1b3cb46a601d34e59c43079918c0b09e0622
Author: Lyor Goldstein <lgoldst...@apache.org>
AuthorDate: Tue Aug 25 20:01:36 2020 +0300

    [SSHD-1063] Fixed known-hosts file server key verifier matching of same 
host with different ports
---
 CHANGES.md                                         |  2 +
 .../sshd/cli/client/SshClientCliSupport.java       |  4 +-
 .../client/config/hosts/HostPatternsHolder.java    | 19 +++++--
 .../client/config/hosts/KnownHostHashValue.java    |  4 +-
 .../java/org/apache/sshd/common/SshConstants.java  |  4 ++
 .../KnownHostsServerKeyVerifierTest.java           | 65 ++++++++++++++++++++--
 .../org/apache/sshd/scp/common/ScpLocation.java    |  3 +-
 .../sftp/client/fs/SftpFileSystemProvider.java     |  2 +-
 8 files changed, 86 insertions(+), 17 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index bf19bdd..1893207 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -47,3 +47,5 @@ or `-key-file` command line option.
 * [SSHD-1057](https://issues.apache.org/jira/browse/SSHD-1057) Added 
capability to select a ShellFactory based on the current session + use it for 
"WinSCP"
 * [SSHD-1058](https://issues.apache.org/jira/browse/SSHD-1058) Improve 
exception logging strategy.
 * [SSHD-1059](https://issues.apache.org/jira/browse/SSHD-1059) Do not send 
heartbeat if KEX state not DONE
+* [SSHD-1063](https://issues.apache.org/jira/browse/SSHD-1063) Fixed 
known-hosts file server key verifier matching of same host with different ports
+
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 685c812..db26179 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
@@ -251,9 +251,7 @@ public abstract class SshClientCliSupport extends 
CliSupport {
                 login = OsUtils.getCurrentUser();
             }
 
-            if (port <= 0) {
-                port = SshConstants.DEFAULT_PORT;
-            }
+            port = SshConstants.TO_EFFECTIVE_PORT.applyAsInt(port);
 
             HostConfigEntry entry = resolveHost(client, login, host, port, 
proxyJump);
             // TODO use a configurable wait time
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/client/config/hosts/HostPatternsHolder.java
 
b/sshd-common/src/main/java/org/apache/sshd/client/config/hosts/HostPatternsHolder.java
index ecdd6dd..7a7a88c 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/client/config/hosts/HostPatternsHolder.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/client/config/hosts/HostPatternsHolder.java
@@ -29,6 +29,7 @@ import java.util.Objects;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 
@@ -186,6 +187,10 @@ public abstract class HostPatternsHolder {
                 continue;
             }
 
+            if (!isPortMatch(port, pv.getPort())) {
+                continue;
+            }
+
             /*
              * According to 
https://www.freebsd.org/cgi/man.cgi?query=ssh_config&sektion=5:
              *
@@ -196,11 +201,6 @@ public abstract class HostPatternsHolder {
                 return false;
             }
 
-            int pvPort = pv.getPort();
-            if ((pvPort != 0) && (port != 0) && (pvPort != port)) {
-                continue;
-            }
-
             matchFound = true;
         }
 
@@ -208,6 +208,15 @@ public abstract class HostPatternsHolder {
     }
 
     /**
+     * @param  port1 1st port value - if non-positive the assumed to be {@link 
SshConstants#DEFAULT_PORT DEFAULT_PORT}
+     * @param  port2 2nd port value - if non-positive the assumed to be {@link 
SshConstants#DEFAULT_PORT DEFAULT_PORT}
+     * @return       {@code true} if ports are effectively equal
+     */
+    public static boolean isPortMatch(int port1, int port2) {
+        return SshConstants.TO_EFFECTIVE_PORT.applyAsInt(port1) == 
SshConstants.TO_EFFECTIVE_PORT.applyAsInt(port2);
+    }
+
+    /**
      * Checks if a given host name / address matches a host pattern
      *
      * @param  host    The host name / address - ignored if {@code null}/empty
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/client/config/hosts/KnownHostHashValue.java
 
b/sshd-common/src/main/java/org/apache/sshd/client/config/hosts/KnownHostHashValue.java
index 186b86b..bb7bd72 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/client/config/hosts/KnownHostHashValue.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/client/config/hosts/KnownHostHashValue.java
@@ -136,7 +136,7 @@ public class KnownHostHashValue {
     }
 
     public static String createHostPattern(String host, int port) {
-        if ((port <= 0) || (port == SshConstants.DEFAULT_PORT)) {
+        if (SshConstants.TO_EFFECTIVE_PORT.applyAsInt(port) == 
SshConstants.DEFAULT_PORT) {
             return host;
         }
 
@@ -151,7 +151,7 @@ public class KnownHostHashValue {
     }
 
     public static <A extends Appendable> A appendHostPattern(A sb, String 
host, int port) throws IOException {
-        boolean nonDefaultPort = (port > 0) && (port != 
SshConstants.DEFAULT_PORT);
+        boolean nonDefaultPort = 
SshConstants.TO_EFFECTIVE_PORT.applyAsInt(port) != SshConstants.DEFAULT_PORT;
         if (nonDefaultPort) {
             
sb.append(HostPatternsHolder.NON_STANDARD_PORT_PATTERN_ENCLOSURE_START_DELIM);
         }
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/SshConstants.java 
b/sshd-common/src/main/java/org/apache/sshd/common/SshConstants.java
index 900a865..05d2019 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/SshConstants.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/SshConstants.java
@@ -23,6 +23,7 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.IntUnaryOperator;
 
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.logging.LoggingUtils;
@@ -35,6 +36,9 @@ import org.apache.sshd.common.util.logging.LoggingUtils;
 public final class SshConstants {
     public static final int DEFAULT_PORT = 22;
 
+    /** Converts non-positive port value to {@value #DEFAULT_PORT} */
+    public static final IntUnaryOperator TO_EFFECTIVE_PORT = port -> (port > 
0) ? port : DEFAULT_PORT;
+
     //
     // SSH message identifiers
     //
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/client/keyverifier/KnownHostsServerKeyVerifierTest.java
 
b/sshd-core/src/test/java/org/apache/sshd/client/keyverifier/KnownHostsServerKeyVerifierTest.java
index 9482ffd..d23521c 100644
--- 
a/sshd-core/src/test/java/org/apache/sshd/client/keyverifier/KnownHostsServerKeyVerifierTest.java
+++ 
b/sshd-core/src/test/java/org/apache/sshd/client/keyverifier/KnownHostsServerKeyVerifierTest.java
@@ -41,6 +41,7 @@ import org.apache.sshd.client.config.hosts.KnownHostHashValue;
 import 
org.apache.sshd.client.keyverifier.KnownHostsServerKeyVerifier.HostEntryPair;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.config.keys.PublicKeyEntry;
@@ -266,8 +267,8 @@ public class KnownHostsServerKeyVerifierTest extends 
BaseTestSupport {
     @Test
     public void testRejectModifiedServerKey() throws Exception {
         KeyPair kp = 
CommonTestSupportUtils.generateKeyPair(KeyUtils.RSA_ALGORITHM, 1024);
-        final PublicKey modifiedKey = kp.getPublic();
-        final AtomicInteger acceptCount = new AtomicInteger(0);
+        PublicKey modifiedKey = kp.getPublic();
+        AtomicInteger acceptCount = new AtomicInteger(0);
         ServerKeyVerifier verifier
                 = new 
KnownHostsServerKeyVerifier(AcceptAllServerKeyVerifier.INSTANCE, 
createKnownHostsCopy()) {
                     @Override
@@ -296,7 +297,7 @@ public class KnownHostsServerKeyVerifierTest extends 
BaseTestSupport {
     @Test
     public void testAcceptModifiedServerKeyUpdatesFile() throws Exception {
         KeyPair kp = 
CommonTestSupportUtils.generateKeyPair(KeyUtils.RSA_ALGORITHM, 1024);
-        final PublicKey modifiedKey = kp.getPublic();
+        PublicKey modifiedKey = kp.getPublic();
         Path path = createKnownHostsCopy();
         ServerKeyVerifier verifier = new 
KnownHostsServerKeyVerifier(AcceptAllServerKeyVerifier.INSTANCE, path) {
             @Override
@@ -338,6 +339,62 @@ public class KnownHostsServerKeyVerifierTest extends 
BaseTestSupport {
         assertTrue("Unexpected extra updated entries: " + updatedKeys, 
updatedKeys.isEmpty());
     }
 
+    @Test   // SSHD-1063
+    public void testUpdateSameHost2PortsStdFirstSameKey() throws Exception {
+        testUpdateSameHostWithDifferentPorts(SshConstants.DEFAULT_PORT, 2020, 
true);
+    }
+
+    @Test   // SSHD-1063
+    public void testUpdateSameHost2PortsStdLastSameKey() throws Exception {
+        testUpdateSameHostWithDifferentPorts(2020, SshConstants.DEFAULT_PORT, 
true);
+    }
+
+    @Test   // SSHD-1063
+    public void testUpdateSameHost2NonStdPortsSameKey() throws Exception {
+        testUpdateSameHostWithDifferentPorts(2020, 2222, true);
+    }
+
+    @Test   // SSHD-1063
+    public void testUpdateSameHost2PortsStdFirstDiffKeys() throws Exception {
+        testUpdateSameHostWithDifferentPorts(SshConstants.DEFAULT_PORT, 2020, 
false);
+    }
+
+    @Test   // SSHD-1063
+    public void testUpdateSameHost2PortsStdLastDiffKeys() throws Exception {
+        testUpdateSameHostWithDifferentPorts(2020, SshConstants.DEFAULT_PORT, 
false);
+    }
+
+    @Test   // SSHD-1063
+    public void testUpdateSameHost2NonStdPortsDiffKeys() throws Exception {
+        testUpdateSameHostWithDifferentPorts(2020, 2222, false);
+    }
+
+    private void testUpdateSameHostWithDifferentPorts(int port1, int port2, 
boolean useSameKey) throws Exception {
+        Path path = getKnownHostCopyPath();
+        Files.write(path, Collections.singletonList(""));   // start empty
+        // accept all unknown entries
+        KnownHostsServerKeyVerifier verifier = new 
KnownHostsServerKeyVerifier(AcceptAllServerKeyVerifier.INSTANCE, path);
+        // Reject modified entries
+        verifier.setModifiedServerKeyAcceptor((clientSession, remoteAddress, 
entry, expected, actual) -> false);
+
+        KeyPair kp1 = 
CommonTestSupportUtils.generateKeyPair(KeyUtils.RSA_ALGORITHM, 1024);
+        PublicKey serverKey1 = kp1.getPublic();
+
+        SocketAddress address1 = new SshdSocketAddress(HASHED_HOST, port1);
+        boolean accepted1 = invokeVerifier(verifier, address1, serverKey1);
+        assertTrue("Accepted on port=" + port1 + " ?", accepted1);
+
+        KeyPair kp2 = useSameKey ? kp1 : 
CommonTestSupportUtils.generateKeyPair(KeyUtils.RSA_ALGORITHM, 1024);
+        PublicKey serverKey2 = kp2.getPublic();
+
+        SocketAddress address2 = new SshdSocketAddress(HASHED_HOST, port2);
+        boolean accepted2 = invokeVerifier(verifier, address2, serverKey2);
+        assertTrue("Accepted on port=" + port2 + " ?", accepted2);
+
+        Map<SshdSocketAddress, KnownHostEntry> updatedKeys = loadEntries(path);
+        assertEquals("Mismatched total entries count", 2, 
GenericUtils.size(updatedKeys));
+    }
+
     private Path createKnownHostsCopy() throws IOException {
         Path file = getKnownHostCopyPath();
         Files.copy(entriesFile, file, StandardCopyOption.REPLACE_EXISTING);
@@ -350,7 +407,7 @@ public class KnownHostsServerKeyVerifierTest extends 
BaseTestSupport {
         return file;
     }
 
-    private boolean invokeVerifier(ServerKeyVerifier verifier, 
SshdSocketAddress hostIdentity, PublicKey serverKey) {
+    private boolean invokeVerifier(ServerKeyVerifier verifier, SocketAddress 
hostIdentity, PublicKey serverKey) {
         ClientSession session = Mockito.mock(ClientSession.class);
         Mockito.when(session.getConnectAddress()).thenReturn(hostIdentity);
         Mockito.when(session.toString()).thenReturn(getCurrentTestName() + "[" 
+ hostIdentity + "]");
diff --git a/sshd-scp/src/main/java/org/apache/sshd/scp/common/ScpLocation.java 
b/sshd-scp/src/main/java/org/apache/sshd/scp/common/ScpLocation.java
index 4605bbc..c5ed07b 100644
--- a/sshd-scp/src/main/java/org/apache/sshd/scp/common/ScpLocation.java
+++ b/sshd-scp/src/main/java/org/apache/sshd/scp/common/ScpLocation.java
@@ -92,8 +92,7 @@ public class ScpLocation implements MutableUserHolder, 
Serializable, Cloneable {
     }
 
     public int resolvePort() {
-        int portValue = getPort();
-        return (portValue <= 0) ? SshConstants.DEFAULT_PORT : portValue;
+        return SshConstants.TO_EFFECTIVE_PORT.applyAsInt(getPort());
     }
 
     @Override
diff --git 
a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpFileSystemProvider.java
 
b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpFileSystemProvider.java
index 3664697..e1645c2 100644
--- 
a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpFileSystemProvider.java
+++ 
b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpFileSystemProvider.java
@@ -1328,7 +1328,7 @@ public class SftpFileSystemProvider extends 
FileSystemProvider {
 
     public static String getFileSystemIdentifier(String host, int port, String 
username) {
         return GenericUtils.trimToEmpty(host) + ':'
-               + ((port <= 0) ? SshConstants.DEFAULT_PORT : port) + ':'
+               + SshConstants.TO_EFFECTIVE_PORT.applyAsInt(port) + ':'
                + GenericUtils.trimToEmpty(username);
     }
 

Reply via email to