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();