Make SSH host key loading more consistent over time
If the site starts out with a Java formatted "ssh_host_key" file,
but later installs BouncyCastle Crypto, we should continue to use
its existing Java formatted host key, to prevent needing to do a
host key change.
Only one host key (RSA or DSA) is actually required to load the
server and make it functional for clients. Rather than try to
require both keys at server startup we only load ones which are
available on disk.
Signed-off-by: Shawn O. Pearce <sop@google.com>
diff --git a/Documentation/install.txt b/Documentation/install.txt
index eb5ad06..7ad52f6 100644
--- a/Documentation/install.txt
+++ b/Documentation/install.txt
@@ -150,7 +150,8 @@
~~~~~~~~~~~~~
If you choose to install the Bouncy Castle Crypto APIs (see below)
-you must create RSA and DSA host keys for the daemon:
+you must create an RSA, DSA, or both, host keys for the daemon:
+
====
ssh-keygen -t rsa -P '' -f ssh_host_rsa_key
ssh-keygen -t dsa -P '' -f ssh_host_dsa_key
diff --git a/src/main/java/com/google/gerrit/server/ssh/GerritSshDaemon.java b/src/main/java/com/google/gerrit/server/ssh/GerritSshDaemon.java
index fbf02d1..86f9660 100644
--- a/src/main/java/com/google/gerrit/server/ssh/GerritSshDaemon.java
+++ b/src/main/java/com/google/gerrit/server/ssh/GerritSshDaemon.java
@@ -102,8 +102,11 @@
final GerritSshDaemon daemon = new GerritSshDaemon(srv);
try {
sshd = daemon;
- daemon.start();
hostKeys = computeHostKeys();
+ if (hostKeys.isEmpty()) {
+ throw new IOException("No SSHD host key");
+ }
+ daemon.start();
log.info("Started Gerrit SSHD on 0.0.0.0:" + daemon.getPort());
} catch (IOException e) {
log.error("Cannot start Gerrit SSHD on 0.0.0.0:" + daemon.getPort(), e);
@@ -178,7 +181,7 @@
initChannels();
initCompression();
initUserAuth(srv);
- initHostKey(srv);
+ setKeyPairProvider(initHostKey(srv));
setCommandFactory(new GerritCommandFactory());
setShellFactory(new NoShell());
setSessionFactory(new SessionFactory() {
@@ -350,20 +353,39 @@
setPublickeyAuthenticator(new DatabasePubKeyAuth(srv));
}
- private void initHostKey(final GerritServer srv) {
+ private KeyPairProvider initHostKey(final GerritServer srv) {
final File sitePath = srv.getSitePath();
- if (SecurityUtils.isBouncyCastleRegistered()) {
- setKeyPairProvider(new FileKeyPairProvider(new String[] {
- new File(sitePath, "ssh_host_rsa_key").getAbsolutePath(),
- new File(sitePath, "ssh_host_dsa_key").getAbsolutePath()}));
+ final File anyKey = new File(sitePath, "ssh_host_key");
+ final File rsaKey = new File(sitePath, "ssh_host_rsa_key");
+ final File dsaKey = new File(sitePath, "ssh_host_dsa_key");
+
+ final List<String> keys = new ArrayList<String>(2);
+ if (rsaKey.exists()) {
+ keys.add(rsaKey.getAbsolutePath());
+ }
+ if (dsaKey.exists()) {
+ keys.add(dsaKey.getAbsolutePath());
+ }
- } else {
+ if (anyKey.exists() && !keys.isEmpty()) {
+ // If both formats of host key exist, we don't know which format
+ // should be authoritative. Complain and abort.
+ //
+ keys.add(anyKey.getAbsolutePath());
+ throw new IllegalStateException("Multiple host keys exist: " + keys);
+ }
+
+ if (keys.isEmpty()) {
+ // No administrator created host key? Generate and save our own.
+ //
final SimpleGeneratorHostKeyProvider keyp;
keyp = new SimpleGeneratorHostKeyProvider();
- keyp.setPath(new File(sitePath, "ssh_host_key").getAbsolutePath());
- setKeyPairProvider(keyp);
+ keyp.setPath(anyKey.getAbsolutePath());
+ return keyp;
}
+
+ return new FileKeyPairProvider(keys.toArray(new String[keys.size()]));
}
}