comparison 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
comparison
equal deleted inserted replaced
297:c1f929cb3dd0 298:ab3a99f11a36
69 * @see #connect(int) 69 * @see #connect(int)
70 * 70 *
71 * @param s The socket 71 * @param s The socket
72 * @param dsa_key The DSA hostkey, may be <code>NULL</code> 72 * @param dsa_key The DSA hostkey, may be <code>NULL</code>
73 * @param rsa_key The RSA hostkey, may be <code>NULL</code> 73 * @param rsa_key The RSA hostkey, may be <code>NULL</code>
74 */ 74 * @param ec_key The EC hostkey, may be <code>NULL</code>
75 public ServerConnection(Socket s, KeyPair dsa_key, KeyPair rsa_key) 75 */
76 public ServerConnection(Socket s, KeyPair dsa_key, KeyPair rsa_key, KeyPair ec_key)
76 { 77 {
77 state.s = s; 78 state.s = s;
78 state.softwareversion = softwareversion; 79 state.softwareversion = softwareversion;
79 state.next_dsa_key = dsa_key; 80 state.next_dsa_key = dsa_key;
80 state.next_rsa_key = rsa_key; 81 state.next_rsa_key = rsa_key;
81 fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key); 82 state.next_ec_key = ec_key;
83 fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
82 } 84 }
83 85
84 /** 86 /**
85 * Establish the connection and block until the first handshake has completed. 87 * Establish the connection and block until the first handshake has completed.
86 * <p> 88 * <p>
98 } 100 }
99 101
100 /** 102 /**
101 * Establish the connection and block until the first handshake has completed. 103 * Establish the connection and block until the first handshake has completed.
102 * <p> 104 * <p>
103 * Note 1: either a DSA or a RSA (or both) hostkey must be set before calling this method. 105 * Note 1: at least one DSA, RSA or EC hostkey must be set before calling this method.
104 * <p> 106 * <p>
105 * Note 2: You must set the callbacks for authentication ({@link #setAuthenticationCallback(ServerAuthenticationCallback)}) 107 * Note 2: You must set the callbacks for authentication ({@link #setAuthenticationCallback(ServerAuthenticationCallback)})
106 * and connection events ({@link #setServerConnectionCallback(ServerConnectionCallback)}). 108 * and connection events ({@link #setServerConnectionCallback(ServerConnectionCallback)}).
107 * 109 *
108 * @see #setPEMHostKey(char[], String) 110 * @see #setPEMHostKey(char[], String)
124 throw new IllegalStateException("The callback for authentication events has not been set."); 126 throw new IllegalStateException("The callback for authentication events has not been set.");
125 127
126 if (state.tm != null) 128 if (state.tm != null)
127 throw new IllegalStateException("The initial handshake has already been started."); 129 throw new IllegalStateException("The initial handshake has already been started.");
128 130
129 if ((state.next_dsa_key == null) && (state.next_rsa_key == null)) 131 if ((state.next_dsa_key == null) && (state.next_rsa_key == null) && (state.next_ec_key == null))
130 throw new IllegalStateException("Neither a RSA nor a DSA host key has been specified!"); 132 throw new IllegalStateException("Neither an RSA nor a DSA nor an EC host key has been specified!");
131 133
132 state.tm = new ServerTransportManager(state.s); 134 state.tm = new ServerTransportManager(state.s);
133 } 135 }
134 136
135 state.tm.connect(state); 137 state.tm.connect(state);
169 { 171 {
170 if (state.tm == null) 172 if (state.tm == null)
171 throw new IllegalStateException( 173 throw new IllegalStateException(
172 "Cannot force another key exchange, you need to start the key exchange first."); 174 "Cannot force another key exchange, you need to start the key exchange first.");
173 175
174 state.tm.forceKeyExchange(state.next_cryptoWishList, null, state.next_dsa_key, state.next_rsa_key); 176 state.tm.forceKeyExchange(state.next_cryptoWishList, null, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
175 } 177 }
176 } 178 }
177 179
178 /** 180 /**
179 * Returns a {@link ConnectionInfo} object containing the details of 181 * Returns a {@link ConnectionInfo} object containing the details of
197 199
198 return state.tm.getConnectionInfo(1); 200 return state.tm.getConnectionInfo(1);
199 } 201 }
200 202
201 /** 203 /**
202 * Change the current DSA hostkey. Either a DSA or RSA private key must be set for a successful handshake with 204 * Change the current DSA hostkey. Either a DSA or RSA or EC private key must be set for a successful handshake with
203 * the client. 205 * the client.
204 * <p> 206 * <p>
205 * Note: You can change an existing DSA hostkey after the initial kex exchange (the new value will 207 * Note: You can change an existing DSA hostkey after the initial kex exchange (the new value will
206 * be used during the next server initiated key exchange), but you cannot remove (i.e., set to <code>null</code>) the 208 * be used during the next server initiated key exchange), but you cannot remove (i.e., set to <code>null</code>) the
207 * current DSA key, otherwise the next key exchange may fail in case the client supports only DSA hostkeys. 209 * current DSA key, otherwise the next key exchange may fail in case the client supports only DSA hostkeys.
214 { 216 {
215 if ((dsa_hostkey == null) && (state.next_dsa_key != null) && (state.tm != null)) 217 if ((dsa_hostkey == null) && (state.next_dsa_key != null) && (state.tm != null))
216 throw new IllegalStateException("Cannot remove DSA hostkey after first key exchange."); 218 throw new IllegalStateException("Cannot remove DSA hostkey after first key exchange.");
217 219
218 state.next_dsa_key = dsa_hostkey; 220 state.next_dsa_key = dsa_hostkey;
219 fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key); 221 fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
220 } 222 }
221 } 223 }
222 224
223 /** 225 /**
224 * Change the current RSA hostkey. Either a DSA or RSA private key must be set for a successful handshake with 226 * Change the current RSA hostkey. Either a DSA or RSA or EC private key must be set for a successful handshake with
225 * the client. 227 * the client.
226 * <p> 228 * <p>
227 * Note: You can change an existing RSA hostkey after the initial kex exchange (the new value will 229 * Note: You can change an existing RSA hostkey after the initial kex exchange (the new value will
228 * be used during the next server initiated key exchange), but you cannot remove (i.e., set to <code>null</code>) the 230 * be used during the next server initiated key exchange), but you cannot remove (i.e., set to <code>null</code>) the
229 * current RSA key, otherwise the next key exchange may fail in case the client supports only RSA hostkeys. 231 * current RSA key, otherwise the next key exchange may fail in case the client supports only RSA hostkeys.
236 { 238 {
237 if ((rsa_hostkey == null) && (state.next_rsa_key != null) && (state.tm != null)) 239 if ((rsa_hostkey == null) && (state.next_rsa_key != null) && (state.tm != null))
238 throw new IllegalStateException("Cannot remove RSA hostkey after first key exchange."); 240 throw new IllegalStateException("Cannot remove RSA hostkey after first key exchange.");
239 241
240 state.next_rsa_key = rsa_hostkey; 242 state.next_rsa_key = rsa_hostkey;
241 fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key); 243 fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
244 }
245 }
246
247 /**
248 * Change the current EC hostkey. Either a DSA or RSA or EC private key must be set for a successful handshake with
249 * the client.
250 * <p>
251 * Note: You can change an existing EC hostkey after the initial kex exchange (the new value will
252 * be used during the next server initiated key exchange), but you cannot remove (i.e., set to <code>null</code>) the
253 * current EC key, otherwise the next key exchange may fail in case the client supports only EC hostkeys.
254 *
255 * @param rsa_hostkey
256 */
257 public synchronized void setEcHostKey(KeyPair ec_hostkey)
258 {
259 synchronized (state)
260 {
261 if ((ec_hostkey == null) && (state.next_ec_key != null) && (state.tm != null))
262 throw new IllegalStateException("Cannot remove EC hostkey after first key exchange.");
263
264 state.next_ec_key = ec_hostkey;
265 fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
242 } 266 }
243 } 267 }
244 268
245 /** 269 /**
246 * Utility method that loads a PEM based hostkey (either RSA or DSA based) and 270 * Utility method that loads a PEM based hostkey (either RSA or DSA based) and
256 PrivateKey key = pair.getPrivate(); 280 PrivateKey key = pair.getPrivate();
257 281
258 if (key instanceof DSAPrivateKey) setDsaHostKey(pair); 282 if (key instanceof DSAPrivateKey) setDsaHostKey(pair);
259 283
260 if (key instanceof RSAPrivateKey) setRsaHostKey(pair); 284 if (key instanceof RSAPrivateKey) setRsaHostKey(pair);
285
286 if (key instanceof ECPrivateKey) setEcHostKey(pair);
261 } 287 }
262 288
263 /** 289 /**
264 * Utility method that loads a hostkey from a PEM file (either RSA or DSA based) and 290 * Utility method that loads a hostkey from a PEM file (either RSA or DSA based) and
265 * calls either <code>setRsaHostKey()</code> or <code>setDsaHostKey()</code>. 291 * calls either <code>setRsaHostKey()</code> or <code>setDsaHostKey()</code>.
290 fr.close(); 316 fr.close();
291 317
292 setPEMHostKey(cw.toCharArray(), password); 318 setPEMHostKey(cw.toCharArray(), password);
293 } 319 }
294 320
295 private void fixCryptoWishList(CryptoWishList next_cryptoWishList, KeyPair next_dsa_key, KeyPair next_rsa_key) 321 private void fixCryptoWishList(CryptoWishList next_cryptoWishList, KeyPair next_dsa_key, KeyPair next_rsa_key, KeyPair next_ec_key)
296 { 322 {
297 if ((next_dsa_key != null) && (next_rsa_key != null)) 323 List<String> algos = new ArrayList<string>();
298 next_cryptoWishList.serverHostKeyAlgorithms = new String[] { "ssh-rsa", "ssh-dss" }; 324 if (next_dsa_key != null) algos.add("ssh-dss");
299 else if (next_dsa_key != null) 325 if (next_rsa_key != null) algos.add("ssh-rsa");
300 next_cryptoWishList.serverHostKeyAlgorithms = new String[] { "ssh-dss" }; 326 if (next_ec_key != null) algos.add("ssh-ec");
301 else if (next_rsa_key != null) 327 next_cryptoWishList.serverHostKeyAlgorithms = new String[algos.size()];
302 next_cryptoWishList.serverHostKeyAlgorithms = new String[] { "ssh-rsa" }; 328 algos.toArray(next_cryptoWishList.serverHostKeyAlgorithms);
303 else
304 next_cryptoWishList.serverHostKeyAlgorithms = new String[0];
305 } 329 }
306 330
307 /** 331 /**
308 * Callback interface with methods that will be called upon events 332 * Callback interface with methods that will be called upon events
309 * generated by the client (e.g., client opens a new Session which results in a <code>ServerSession</code>). 333 * generated by the client (e.g., client opens a new Session which results in a <code>ServerSession</code>).