diff src/ch/ethz/ssh2/ServerConnection.java @ 298:ab3a99f11a36 ganymed

add ecdsa key support everywhere
author Carl Byington <carl@five-ten-sg.com>
date Tue, 29 Jul 2014 18:01:08 -0700
parents d2ee20d9dff1
children 349847b2e318
line wrap: on
line diff
--- a/src/ch/ethz/ssh2/ServerConnection.java	Tue Jul 29 16:43:12 2014 -0700
+++ b/src/ch/ethz/ssh2/ServerConnection.java	Tue Jul 29 18:01:08 2014 -0700
@@ -71,14 +71,16 @@
 	 * @param s The socket
 	 * @param dsa_key The DSA hostkey, may be <code>NULL</code>
 	 * @param rsa_key The RSA hostkey, may be <code>NULL</code>
+	 * @param ec_key  The EC  hostkey, may be <code>NULL</code>
 	 */
-	public ServerConnection(Socket s, KeyPair dsa_key, KeyPair rsa_key)
+	public ServerConnection(Socket s, KeyPair dsa_key, KeyPair rsa_key, KeyPair ec_key)
 	{
 		state.s = s;
 		state.softwareversion = softwareversion;
 		state.next_dsa_key = dsa_key;
 		state.next_rsa_key = rsa_key;
-		fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key);
+		state.next_ec_key  = ec_key;
+		fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
 	}
 
 	/**
@@ -100,7 +102,7 @@
 	/**
 	 * Establish the connection and block until the first handshake has completed.
 	 * <p>
-	 * Note 1: either a DSA or a RSA (or both) hostkey must be set before calling this method.
+	 * Note 1: at least one DSA, RSA or EC hostkey must be set before calling this method.
 	 * <p>
 	 * Note 2: You must set the callbacks for authentication ({@link #setAuthenticationCallback(ServerAuthenticationCallback)})
 	 * and connection events ({@link #setServerConnectionCallback(ServerConnectionCallback)}).
@@ -126,8 +128,8 @@
 			if (state.tm != null)
 				throw new IllegalStateException("The initial handshake has already been started.");
 
-			if ((state.next_dsa_key == null) && (state.next_rsa_key == null))
-				throw new IllegalStateException("Neither a RSA nor a DSA host key has been specified!");
+			if ((state.next_dsa_key == null) && (state.next_rsa_key == null) && (state.next_ec_key == null))
+				throw new IllegalStateException("Neither an RSA nor a DSA nor an EC host key has been specified!");
 
 			state.tm = new ServerTransportManager(state.s);
 		}
@@ -171,7 +173,7 @@
 				throw new IllegalStateException(
 						"Cannot force another key exchange, you need to start the key exchange first.");
 
-			state.tm.forceKeyExchange(state.next_cryptoWishList, null, state.next_dsa_key, state.next_rsa_key);
+			state.tm.forceKeyExchange(state.next_cryptoWishList, null, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
 		}
 	}
 
@@ -199,7 +201,7 @@
 	}
 
 	/**
-	 * Change the current DSA hostkey. Either a DSA or RSA private key must be set for a successful handshake with
+	 * Change the current DSA hostkey. Either a DSA or RSA or EC private key must be set for a successful handshake with
 	 * the client.
 	 * <p>
 	 * Note: You can change an existing DSA hostkey after the initial kex exchange (the new value will
@@ -216,12 +218,12 @@
 				throw new IllegalStateException("Cannot remove DSA hostkey after first key exchange.");
 
 			state.next_dsa_key = dsa_hostkey;
-			fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key);
+			fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
 		}
 	}
 
 	/**
-	 * Change the current RSA hostkey. Either a DSA or RSA private key must be set for a successful handshake with
+	 * Change the current RSA hostkey. Either a DSA or RSA or EC private key must be set for a successful handshake with
 	 * the client.
 	 * <p>
 	 * Note: You can change an existing RSA hostkey after the initial kex exchange (the new value will
@@ -238,7 +240,29 @@
 				throw new IllegalStateException("Cannot remove RSA hostkey after first key exchange.");
 
 			state.next_rsa_key = rsa_hostkey;
-			fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key);
+			fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
+		}
+	}
+
+	/**
+	 * Change the current EC hostkey. Either a DSA or RSA or EC private key must be set for a successful handshake with
+	 * the client.
+	 * <p>
+	 * Note: You can change an existing EC hostkey after the initial kex exchange (the new value will
+	 * be used during the next server initiated key exchange), but you cannot remove (i.e., set to <code>null</code>) the
+	 * current EC key, otherwise the next key exchange may fail in case the client supports only EC hostkeys.
+	 *
+	 * @param rsa_hostkey
+	 */
+	public synchronized void setEcHostKey(KeyPair ec_hostkey)
+	{
+		synchronized (state)
+		{
+			if ((ec_hostkey == null) && (state.next_ec_key != null) && (state.tm != null))
+				throw new IllegalStateException("Cannot remove EC hostkey after first key exchange.");
+
+			state.next_ec_key = ec_hostkey;
+			fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
 		}
 	}
 
@@ -258,6 +282,8 @@
 		if (key instanceof DSAPrivateKey) setDsaHostKey(pair);
 
 		if (key instanceof RSAPrivateKey) setRsaHostKey(pair);
+
+        if (key instanceof ECPrivateKey) setEcHostKey(pair);
 	}
 
 	/**
@@ -292,16 +318,14 @@
 		setPEMHostKey(cw.toCharArray(), password);
 	}
 
-	private void fixCryptoWishList(CryptoWishList next_cryptoWishList, KeyPair next_dsa_key, KeyPair next_rsa_key)
+	private void fixCryptoWishList(CryptoWishList next_cryptoWishList, KeyPair next_dsa_key, KeyPair next_rsa_key, KeyPair next_ec_key)
 	{
-		if ((next_dsa_key != null) && (next_rsa_key != null))
-			next_cryptoWishList.serverHostKeyAlgorithms = new String[] { "ssh-rsa", "ssh-dss" };
-		else if (next_dsa_key != null)
-			next_cryptoWishList.serverHostKeyAlgorithms = new String[] { "ssh-dss" };
-		else if (next_rsa_key != null)
-			next_cryptoWishList.serverHostKeyAlgorithms = new String[] { "ssh-rsa" };
-		else
-			next_cryptoWishList.serverHostKeyAlgorithms = new String[0];
+        List<String> algos = new ArrayList<string>();
+		if (next_dsa_key != null) algos.add("ssh-dss");
+		if (next_rsa_key != null) algos.add("ssh-rsa");
+		if (next_ec_key != null)  algos.add("ssh-ec");
+ 	    next_cryptoWishList.serverHostKeyAlgorithms = new String[algos.size()];
+        algos.toArray(next_cryptoWishList.serverHostKeyAlgorithms);
 	}
 
 	/**