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 edb2b95121ff19866e34245abdee8460cea1b4ca
Author: Thomas Wolf <tw...@apache.org>
AuthorDate: Fri Feb 2 00:38:36 2024 +0100

    Remove AES-CBC ciphers from the server's default KEX proposal
    
    CBC implementations have been historically susceptible to various
    padding oracle attacks, and the use of CBC-mode ciphers in the SSH
    protocol was found insecure in 2008 in another attack known as
    CPNI-957037[1], VU#958563[2], or CVE-2008-5161[3]. Details were
    published in [4] in 2009.
    
    OpenSSH does not propose the CBC ciphers (unless explicitly enabled)
    in servers since 2014, and has removed them from the client proposal
    in 2017, too.
    
    Before the full disclosure in 2009, OpenSSH had implemented some
    mitigations against CPNI-957037, but given the nature of the attack
    I'm not convinced they are effective. The attack leverages OpenSSH
    as an oracle and it does not need to control the IV, so it should be
    possible to perform the decryption attack offline using an older
    unpatched SSH implementation.
    
    TLS has deprecated CBC ciphers in TLS v1.2, and has removed them in
    TLS v.1.3.
    
    For clients, we keep the CBC ciphers by default for now to facilitate
    connecting to legacy servers. I plan to remove them from the client's
    default list in the next release.
    
    [1] https://www.openssh.com/txt/cbc.adv
    [2] https://www.kb.cert.org/vuls/id/958563
    [3] https://cve.mitre.org/cgi-bin/cvename.cgi?name=2008-5161
    [4] 
https://www.cs.umd.edu/~jkatz/security/downloads/PlaintextRecoverySSH.pdf
---
 CHANGES.md                                         | 23 +++++++++++
 .../java/org/apache/sshd/server/ServerBuilder.java | 22 ++++++++++
 .../org/apache/sshd/DefaultSetupTestSupport.java   |  7 +++-
 .../sshd/client/ClientSessionListenerTest.java     |  2 +-
 .../sshd/common/mac/MacCompatibilityTest.java      | 48 ++++++++++++++--------
 5 files changed, 83 insertions(+), 19 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 405eb4225..e6e60e08e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -164,5 +164,28 @@ such excess data is silently discarded.
 
 ## Potential compatibility issues
 
+### AES-CBC ciphers removed from server's defaults
+
+The AES-CBC ciphers `aes128-cbc`, `aes192-cbc`, and `aes256-cbc` have been 
removed from the default
+list of cipher algorithms that a server proposes in the key exchange. OpenSSH 
has removed these
+cipher algorithms from the server proposal in 2014, and has removed them from 
the client proposal
+in 2017.
+
+The cipher implementations still exist but they are not enabled by default. 
Existing code that
+explicitly sets the cipher factories is unaffected. Code that relies on the 
default settings
+will newly create a server that does not support the CBC-mode ciphers. To 
enable the CBC-mode
+ciphers, one can use for instance
+
+```
+SshServer server = ServerBuilder.builder()
+   ...
+   .cipherFactories(BuiltinFactory.setUpFactories(false, 
BaseBuilder.DEFAULT_CIPHERS_PREFERENCES));
+   ...
+   .build();
+```
+
+For the SSH _client_, the CBC ciphers are still enabled by default to 
facilitate connecting to
+legacy servers. We plan to remove the CBC ciphers from the client's defaults 
in the next release.
+
 ## Major Code Re-factoring
 
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/ServerBuilder.java 
b/sshd-core/src/main/java/org/apache/sshd/server/ServerBuilder.java
index 4fe4961e3..5a7ed835c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/ServerBuilder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/ServerBuilder.java
@@ -25,9 +25,11 @@ import java.util.List;
 import java.util.function.Function;
 
 import org.apache.sshd.common.BaseBuilder;
+import org.apache.sshd.common.BuiltinFactory;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.channel.ChannelFactory;
 import org.apache.sshd.common.channel.RequestHandler;
+import org.apache.sshd.common.cipher.BuiltinCiphers;
 import org.apache.sshd.common.compression.BuiltinCompressions;
 import org.apache.sshd.common.compression.Compression;
 import org.apache.sshd.common.compression.CompressionFactory;
@@ -86,6 +88,23 @@ public class ServerBuilder extends BaseBuilder<SshServer, 
ServerBuilder> {
                     BuiltinCompressions.delayedZlib));
     public static final KexExtensionHandler DEFAULT_KEX_EXTENSION_HANDLER = 
DefaultServerKexExtensionHandler.INSTANCE;
 
+    /**
+     * Default list of ciphers for a server. This excludes the AES-CBC ciphers 
-- OpenSSH has stopped proposing them by
+     * default in 2014 (and removed them from the client proposal in 2017, 
too). CBC is susceptible to padding oracle
+     * attacks and other attacks and is thus not recommended anymore.
+     * <p>
+     * For clients, we do still include the CBC modes to better support 
connecting with legacy servers.
+     * </p>
+     */
+    public static final List<BuiltinCiphers> DEFAULT_SERVER_CIPHERS_PREFERENCE 
= Collections.unmodifiableList(
+            Arrays.asList(
+                    BuiltinCiphers.cc20p1305_openssh,
+                    BuiltinCiphers.aes128ctr,
+                    BuiltinCiphers.aes192ctr,
+                    BuiltinCiphers.aes256ctr,
+                    BuiltinCiphers.aes128gcm,
+                    BuiltinCiphers.aes256gcm));
+
     protected PublickeyAuthenticator pubkeyAuthenticator;
     protected KeyboardInteractiveAuthenticator interactiveAuthenticator;
 
@@ -105,6 +124,9 @@ public class ServerBuilder extends BaseBuilder<SshServer, 
ServerBuilder> {
 
     @Override
     protected ServerBuilder fillWithDefaultValues() {
+        if (cipherFactories == null) {
+            cipherFactories(BuiltinFactory.setUpFactories(false, 
DEFAULT_SERVER_CIPHERS_PREFERENCE));
+        }
         super.fillWithDefaultValues();
 
         if (compressionFactories == null) {
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/DefaultSetupTestSupport.java 
b/sshd-core/src/test/java/org/apache/sshd/DefaultSetupTestSupport.java
index c2f82be7a..45f810db8 100644
--- a/sshd-core/src/test/java/org/apache/sshd/DefaultSetupTestSupport.java
+++ b/sshd-core/src/test/java/org/apache/sshd/DefaultSetupTestSupport.java
@@ -38,6 +38,8 @@ import org.apache.sshd.common.mac.Mac;
 import org.apache.sshd.common.signature.BuiltinSignatures;
 import org.apache.sshd.common.signature.Signature;
 import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.server.ServerBuilder;
+import org.apache.sshd.server.SshServer;
 import org.apache.sshd.util.test.BaseTestSupport;
 import org.apache.sshd.util.test.NoIoTestCase;
 import org.junit.Test;
@@ -59,7 +61,10 @@ public abstract class DefaultSetupTestSupport<M extends 
AbstractFactoryManager>
 
     @Test
     public void testDefaultCiphersList() {
-        assertSameNamedFactoriesListInstances(Cipher.class.getSimpleName(), 
BaseBuilder.DEFAULT_CIPHERS_PREFERENCE,
+        assertSameNamedFactoriesListInstances(Cipher.class.getSimpleName(),
+                factory instanceof SshServer
+                        ? ServerBuilder.DEFAULT_SERVER_CIPHERS_PREFERENCE
+                        : BaseBuilder.DEFAULT_CIPHERS_PREFERENCE,
                 factory.getCipherFactories());
     }
 
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java 
b/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java
index 585c5afd3..e1b73e822 100644
--- 
a/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java
+++ 
b/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java
@@ -96,7 +96,7 @@ public class ClientSessionListenerTest extends 
BaseTestSupport {
     public void testSessionListenerCanModifyKEXNegotiation() throws Exception {
         Map<KexProposalOption, NamedResource> kexParams = new 
EnumMap<>(KexProposalOption.class);
         kexParams.put(KexProposalOption.ALGORITHMS, 
getLeastFavorite(KeyExchange.class, client.getKeyExchangeFactories()));
-        kexParams.put(KexProposalOption.C2SENC, 
getLeastFavorite(CipherFactory.class, client.getCipherFactories()));
+        kexParams.put(KexProposalOption.C2SENC, 
getLeastFavorite(CipherFactory.class, sshd.getCipherFactories()));
         kexParams.put(KexProposalOption.C2SMAC, 
getLeastFavorite(MacFactory.class, client.getMacFactories()));
 
         SessionListener listener = new SessionListener() {
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/common/mac/MacCompatibilityTest.java 
b/sshd-core/src/test/java/org/apache/sshd/common/mac/MacCompatibilityTest.java
index 692a22953..319d27406 100644
--- 
a/sshd-core/src/test/java/org/apache/sshd/common/mac/MacCompatibilityTest.java
+++ 
b/sshd-core/src/test/java/org/apache/sshd/common/mac/MacCompatibilityTest.java
@@ -26,7 +26,9 @@ import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
 import ch.ethz.ssh2.Connection;
@@ -162,29 +164,41 @@ public class MacCompatibilityTest extends BaseTestSupport 
{
         Assume.assumeTrue("Known JSCH bug with " + macName, 
!BuiltinMacs.hmacsha512.equals(factory));
 
         JSch sch = new JSch();
-        JSch.setConfig("cipher.s2c", 
"aes128-cbc,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc,none");
-        JSch.setConfig("cipher.c2s", 
"aes128-cbc,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc,none");
-        JSch.setConfig("mac.s2c", macName);
-        JSch.setConfig("mac.c2s", macName);
-        JSch.setConfig(macName, jschMacClass);
-
-        com.jcraft.jsch.Session session = sch.getSession(getCurrentTestName(), 
TEST_LOCALHOST, port);
+        Map<String, String> values = new HashMap<>();
+        values.put("cipher.s2c", JSch.getConfig("cipher.s2c"));
+        values.put("cipher.c2s", JSch.getConfig("cipher.s2c"));
+        values.put("mac.s2c", JSch.getConfig("mac.s2c"));
+        values.put("mac.c2s", JSch.getConfig("mac.s2c"));
+        values.put(macName, JSch.getConfig(macName));
         try {
-            session.setUserInfo(new SimpleUserInfo(getCurrentTestName()));
-            session.connect();
+            JSch.setConfig("cipher.s2c", 
"aes128-ctr,aes192-ctr,aes256-ctr,none");
+            JSch.setConfig("cipher.c2s", 
"aes128-ctr,aes192-ctr,aes256-ctr,none");
+            JSch.setConfig("mac.s2c", macName);
+            JSch.setConfig("mac.c2s", macName);
+            JSch.setConfig(macName, jschMacClass);
+
+            com.jcraft.jsch.Session session = 
sch.getSession(getCurrentTestName(), TEST_LOCALHOST, port);
+            try {
+                session.setUserInfo(new SimpleUserInfo(getCurrentTestName()));
+                session.connect();
 
-            com.jcraft.jsch.Channel channel = 
session.openChannel(Channel.CHANNEL_SHELL);
-            channel.connect();
+                com.jcraft.jsch.Channel channel = 
session.openChannel(Channel.CHANNEL_SHELL);
+                channel.connect();
 
-            try (OutputStream stdin = channel.getOutputStream();
-                 InputStream stdout = channel.getInputStream();
-                 InputStream stderr = channel.getExtInputStream()) {
-                runShellTest(stdin, stdout);
+                try (OutputStream stdin = channel.getOutputStream();
+                     InputStream stdout = channel.getInputStream();
+                     InputStream stderr = channel.getExtInputStream()) {
+                    runShellTest(stdin, stdout);
+                } finally {
+                    channel.disconnect();
+                }
             } finally {
-                channel.disconnect();
+                session.disconnect();
             }
         } finally {
-            session.disconnect();
+            for (Map.Entry<String, String> item : values.entrySet()) {
+                JSch.setConfig(item.getKey(), item.getValue());
+            }
         }
     }
 

Reply via email to