Merge "Add configuration of key exchange algorithms for sshd"
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 7836b09..ed49276 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -3666,6 +3666,40 @@
 +
 By default, all supported MACs are available.
 
+[[sshd.kex]]sshd.kex::
++
+--
+Available key exchange algorithms. To permit multiple algorithms,
+specify multiple `sshd.kex` keys in the configuration file, one key
+exchange algorithm per key.  Key exchange algorithm names starting
+with `+` are enabled in addition to the default key exchange
+algorithms, key exchange algorithm names starting with `-` are
+removed from the default key exchange algorithms.
+
+In the following example configuration, support for the 1024-bit
+`diffie-hellman-group1-sha1` key exchange is disabled while leaving
+all of the other default algorithms enabled:
+
+----
+[sshd]
+  kex = -diffie-hellman-group1-sha1
+----
+
+Supported key exchange algorithms:
+
+* `ecdh-sha2-nistp521`
+* `ecdh-sha2-nistp384`
+* `ecdh-sha2-nistp256`
+* `diffie-hellman-group-exchange-sha256`
+* `diffie-hellman-group-exchange-sha1`
+* `diffie-hellman-group14-sha1`
+* `diffie-hellman-group1-sha1`
+
+By default, all supported key exchange algorithms are available.
+Without Bouncy Castle, `diffie-hellman-group1-sha1` is the only
+available algorithm.
+--
+
 [[sshd.kerberosKeytab]]sshd.kerberosKeytab::
 +
 Enable kerberos authentication for SSH connections.  To permit
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java
index 36d024d..466edf5 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java
@@ -56,7 +56,7 @@
 import org.apache.sshd.common.io.mina.MinaServiceFactoryFactory;
 import org.apache.sshd.common.io.mina.MinaSession;
 import org.apache.sshd.common.io.nio2.Nio2ServiceFactoryFactory;
-import org.apache.sshd.common.kex.BuiltinDHFactories;
+import org.apache.sshd.common.kex.KeyExchange;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
 import org.apache.sshd.common.mac.Mac;
 import org.apache.sshd.common.random.JceRandomFactory;
@@ -223,6 +223,7 @@
       initProviderJce();
     }
     initCiphers(cfg);
+    initKeyExchanges(cfg);
     initMacs(cfg);
     initSignatures();
     initChannels();
@@ -426,14 +427,15 @@
     return r.toString();
   }
 
+  @SuppressWarnings("unchecked")
+  private void initKeyExchanges(Config cfg) {
+    List<NamedFactory<KeyExchange>> a =
+        ServerBuilder.setUpDefaultKeyExchanges(true);
+    setKeyExchangeFactories(filter(cfg, "kex",
+        (NamedFactory<KeyExchange>[])a.toArray(new NamedFactory[a.size()])));
+  }
+
   private void initProviderBouncyCastle(Config cfg) {
-    setKeyExchangeFactories(
-        NamedFactory.Utils.setUpTransformedFactories(true,
-            Collections.unmodifiableList(Arrays.asList(
-                BuiltinDHFactories.dhg14,
-                BuiltinDHFactories.dhg1
-            )),
-        ServerBuilder.DH2KEX));
     NamedFactory<Random> factory;
     if (cfg.getBoolean("sshd", null, "testUseInsecureRandom", false)) {
       factory = new InsecureBouncyCastleRandom.Factory();
@@ -508,13 +510,6 @@
   }
 
   private void initProviderJce() {
-    setKeyExchangeFactories(
-        NamedFactory.Utils.setUpTransformedFactories(true,
-            Collections.unmodifiableList(Arrays.asList(
-                BuiltinDHFactories.dhg1
-            )),
-        ServerBuilder.DH2KEX));
-    setKeyExchangeFactories(ServerBuilder.setUpDefaultKeyExchanges(true));
     setRandomFactory(new SingletonRandomFactory(JceRandomFactory.INSTANCE));
   }