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

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

commit baa97441bccb078d648089ef1dd50849a0633cd0
Author: Thomas Wolf <tw...@apache.org>
AuthorDate: Sun Feb 16 18:47:53 2025 +0100

    KEX: guard client against buggy servers
    
    Make the client abort the connection if a certificate key exchange
    had been negotiated but the server sends a plain public key. Also
    abort if a certificate is received, but no certificate key exchange
    was negotiated.
---
 .../org/apache/sshd/common/config/keys/KeyUtils.java  |  6 ++++++
 .../java/org/apache/sshd/client/kex/DHGClient.java    | 19 +++++++++++++------
 2 files changed, 19 insertions(+), 6 deletions(-)

diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java 
b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java
index 28883cb8d..b53a3ea78 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java
@@ -1287,4 +1287,10 @@ public final class KeyUtils {
             return chosenAlgorithm;
         }
     }
+
+    public static boolean isCertificateAlgorithm(String algorithm) {
+        synchronized (SIGNATURE_ALGORITHM_MAP) {
+            return SIGNATURE_ALGORITHM_MAP.containsKey(algorithm);
+        }
+    }
 }
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java 
b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
index baebc67e6..3c336134e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
@@ -176,12 +176,21 @@ public class DHGClient extends 
AbstractDHClientKeyExchange {
             }
         }
 
+        String keyAlg = 
session.getNegotiatedKexParameter(KexProposalOption.SERVERKEYS);
+
+        boolean wantCert = KeyUtils.isCertificateAlgorithm(keyAlg);
+
         buffer = new ByteArrayBuffer(k_s);
         PublicKey serverKey = buffer.getRawPublicKey();
         PublicKey serverPublicHostKey = serverKey;
 
         if (serverKey instanceof OpenSshCertificate) {
             OpenSshCertificate openSshKey = (OpenSshCertificate) serverKey;
+            if (!wantCert) {
+                log.error("Got a server key certificate, but negotiated 
algorithm is {}", keyAlg);
+                throw new 
SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
+                        "OpenSshCertificate found with KEX algorithm " + 
keyAlg);
+            }
             serverPublicHostKey = openSshKey.getCertPubKey();
 
             try {
@@ -195,12 +204,10 @@ public class DHGClient extends 
AbstractDHClientKeyExchange {
                     log.info("Ignoring invalid certificate {}", 
openSshKey.getId(), e);
                 }
             }
-        }
-
-        String keyAlg = 
session.getNegotiatedKexParameter(KexProposalOption.SERVERKEYS);
-        if (GenericUtils.isEmpty(keyAlg)) {
-            throw new SshException("Unsupported server key type: " + 
serverPublicHostKey.getAlgorithm()
-                                   + "[" + serverPublicHostKey.getFormat() + 
"]");
+        } else if (wantCert) {
+            log.error("Got a plain public key (not a certificate) for 
negotiated algorithm {}", keyAlg);
+            throw new 
SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
+                    "Server did not send a certificate with KEX algorithm " + 
keyAlg);
         }
 
         buffer = new ByteArrayBuffer();

Reply via email to