Hack SshDaemon to not use SecureRandom during tests
We previously needed 8 bytes of data from a SecureRandom in order to
start an SSH daemon. Unfortunately, sometimes machines run out of
entropy, for example when running the Gerrit test suite several times
in a row.
Add an undocumented configuration option to use a different Random
factory for Apache SSHD that uses a hard-coded seed instead of
depending on SecureRandom. Unfortunately, because SshDaemon is
constructed using Daemon's injector stack, we can't easily modify its
modules to swap out the provider, so a configuration option is the
easiest solution.
Change-Id: I539b8e3d39d2da9908962fdb8d9633adf935fb4c
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
index 3e8f0b2..644a4bb 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
@@ -131,6 +131,7 @@
cfg.setString("gerrit", null, "canonicalWebUrl", url);
cfg.setString("httpd", null, "listenUrl", url);
cfg.setString("sshd", null, "listenAddress", forceEphemeralPort);
+ cfg.setBoolean("sshd", null, "testUseInsecureRandom", true);
cfg.setString("cache", null, "directory", null);
cfg.setString("gerrit", null, "basePath", "git");
cfg.setBoolean("sendemail", null, "enable", false);
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 3306592..cdaf20e 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
@@ -45,6 +45,7 @@
import org.apache.sshd.common.KeyExchange;
import org.apache.sshd.common.KeyPairProvider;
import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.Random;
import org.apache.sshd.common.Session;
import org.apache.sshd.common.Signature;
import org.apache.sshd.common.SshdSocketAddress;
@@ -94,6 +95,8 @@
import org.apache.sshd.server.kex.DHG1;
import org.apache.sshd.server.kex.DHG14;
import org.apache.sshd.server.session.SessionFactory;
+import org.bouncycastle.crypto.prng.RandomGenerator;
+import org.bouncycastle.crypto.prng.VMPCRandomGenerator;
import org.eclipse.jgit.lib.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -197,7 +200,7 @@
MinaServiceFactory.class.getName());
if (SecurityUtils.isBouncyCastleRegistered()) {
- initProviderBouncyCastle();
+ initProviderBouncyCastle(cfg);
} else {
initProviderJce();
}
@@ -366,11 +369,42 @@
return r.toString();
}
- private void initProviderBouncyCastle() {
+ private void initProviderBouncyCastle(Config cfg) {
setKeyExchangeFactories(Arrays.<NamedFactory<KeyExchange>> asList(
new DHG14.Factory(), new DHG1.Factory()));
- setRandomFactory(new SingletonRandomFactory(
- new BouncyCastleRandom.Factory()));
+ NamedFactory<Random> factory;
+ if (cfg.getBoolean("sshd", null, "testUseInsecureRandom", false)) {
+ factory = new InsecureBouncyCastleRandom.Factory();
+ } else {
+ factory = new BouncyCastleRandom.Factory();
+ }
+ setRandomFactory(new SingletonRandomFactory(factory));
+ }
+
+ private static class InsecureBouncyCastleRandom implements Random {
+ private static class Factory implements NamedFactory<Random> {
+ @Override
+ public String getName() {
+ return "INSECURE_bouncycastle";
+ }
+
+ @Override
+ public Random create() {
+ return new InsecureBouncyCastleRandom();
+ }
+ }
+
+ private final RandomGenerator random;
+
+ private InsecureBouncyCastleRandom() {
+ random = new VMPCRandomGenerator();
+ random.addSeedMaterial(1234);
+ }
+
+ @Override
+ public void fill(byte[] bytes, int start, int len) {
+ random.nextBytes(bytes, start, len);
+ }
}
private void initProviderJce() {