Mercurial > 510Connectbot
comparison src/com/trilead/ssh2/transport/KexManager.java @ 0:0ce5cc452d02
initial version
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Thu, 22 May 2014 10:41:19 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:0ce5cc452d02 |
---|---|
1 | |
2 package com.trilead.ssh2.transport; | |
3 | |
4 import java.io.IOException; | |
5 import java.security.SecureRandom; | |
6 import java.security.interfaces.DSAPublicKey; | |
7 import java.security.interfaces.ECPublicKey; | |
8 import java.security.interfaces.RSAPublicKey; | |
9 import java.util.Set; | |
10 import java.util.TreeSet; | |
11 | |
12 import com.trilead.ssh2.ConnectionInfo; | |
13 import com.trilead.ssh2.DHGexParameters; | |
14 import com.trilead.ssh2.ServerHostKeyVerifier; | |
15 import com.trilead.ssh2.compression.CompressionFactory; | |
16 import com.trilead.ssh2.compression.ICompressor; | |
17 import com.trilead.ssh2.crypto.CryptoWishList; | |
18 import com.trilead.ssh2.crypto.KeyMaterial; | |
19 import com.trilead.ssh2.crypto.cipher.BlockCipher; | |
20 import com.trilead.ssh2.crypto.cipher.BlockCipherFactory; | |
21 import com.trilead.ssh2.crypto.dh.DhGroupExchange; | |
22 import com.trilead.ssh2.crypto.dh.GenericDhExchange; | |
23 import com.trilead.ssh2.crypto.digest.MAC; | |
24 import com.trilead.ssh2.log.Logger; | |
25 import com.trilead.ssh2.packets.PacketKexDHInit; | |
26 import com.trilead.ssh2.packets.PacketKexDHReply; | |
27 import com.trilead.ssh2.packets.PacketKexDhGexGroup; | |
28 import com.trilead.ssh2.packets.PacketKexDhGexInit; | |
29 import com.trilead.ssh2.packets.PacketKexDhGexReply; | |
30 import com.trilead.ssh2.packets.PacketKexDhGexRequest; | |
31 import com.trilead.ssh2.packets.PacketKexDhGexRequestOld; | |
32 import com.trilead.ssh2.packets.PacketKexInit; | |
33 import com.trilead.ssh2.packets.PacketNewKeys; | |
34 import com.trilead.ssh2.packets.Packets; | |
35 import com.trilead.ssh2.signature.DSASHA1Verify; | |
36 import com.trilead.ssh2.signature.ECDSASHA2Verify; | |
37 import com.trilead.ssh2.signature.RSASHA1Verify; | |
38 | |
39 | |
40 /** | |
41 * KexManager. | |
42 * | |
43 * @author Christian Plattner, plattner@trilead.com | |
44 * @version $Id: KexManager.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ | |
45 */ | |
46 public class KexManager { | |
47 private static final Logger log = Logger.getLogger(KexManager.class); | |
48 | |
49 private static final Set<String> HOSTKEY_ALGS = new TreeSet<String>(); | |
50 static { | |
51 HOSTKEY_ALGS.add("ecdsa-sha2-nistp256"); | |
52 HOSTKEY_ALGS.add("ecdsa-sha2-nistp384"); | |
53 HOSTKEY_ALGS.add("ecdsa-sha2-nistp521"); | |
54 HOSTKEY_ALGS.add("ssh-rsa"); | |
55 HOSTKEY_ALGS.add("ssh-dsa"); | |
56 } | |
57 | |
58 private static final Set<String> KEX_ALGS = new TreeSet<String>(); | |
59 static { | |
60 KEX_ALGS.add("ecdh-sha2-nistp256"); | |
61 KEX_ALGS.add("ecdh-sha2-nistp384"); | |
62 KEX_ALGS.add("ecdh-sha2-nistp521"); | |
63 KEX_ALGS.add("diffie-hellman-group-exchange-sha256"); | |
64 KEX_ALGS.add("diffie-hellman-group-exchange-sha1"); | |
65 KEX_ALGS.add("diffie-hellman-group14-sha1"); | |
66 KEX_ALGS.add("diffie-hellman-group1-sha1"); | |
67 } | |
68 | |
69 KexState kxs; | |
70 int kexCount = 0; | |
71 KeyMaterial km; | |
72 byte[] sessionId; | |
73 ClientServerHello csh; | |
74 | |
75 final Object accessLock = new Object(); | |
76 ConnectionInfo lastConnInfo = null; | |
77 | |
78 boolean connectionClosed = false; | |
79 | |
80 boolean ignore_next_kex_packet = false; | |
81 | |
82 final TransportManager tm; | |
83 | |
84 CryptoWishList nextKEXcryptoWishList; | |
85 DHGexParameters nextKEXdhgexParameters; | |
86 | |
87 ServerHostKeyVerifier verifier; | |
88 final String hostname; | |
89 final int port; | |
90 final SecureRandom rnd; | |
91 | |
92 public KexManager(TransportManager tm, ClientServerHello csh, CryptoWishList initialCwl, String hostname, int port, | |
93 ServerHostKeyVerifier keyVerifier, SecureRandom rnd) { | |
94 this.tm = tm; | |
95 this.csh = csh; | |
96 this.nextKEXcryptoWishList = initialCwl; | |
97 this.nextKEXdhgexParameters = new DHGexParameters(); | |
98 this.hostname = hostname; | |
99 this.port = port; | |
100 this.verifier = keyVerifier; | |
101 this.rnd = rnd; | |
102 } | |
103 | |
104 public ConnectionInfo getOrWaitForConnectionInfo(int minKexCount) throws IOException { | |
105 synchronized (accessLock) { | |
106 while (true) { | |
107 if ((lastConnInfo != null) && (lastConnInfo.keyExchangeCounter >= minKexCount)) | |
108 return lastConnInfo; | |
109 | |
110 if (connectionClosed) | |
111 throw(IOException) new IOException("Key exchange was not finished, connection is closed.") | |
112 .initCause(tm.getReasonClosedCause()); | |
113 | |
114 try { | |
115 accessLock.wait(); | |
116 } | |
117 catch (InterruptedException e) { | |
118 } | |
119 } | |
120 } | |
121 } | |
122 | |
123 private String getFirstMatch(String[] client, String[] server) throws NegotiateException { | |
124 if (client == null || server == null) | |
125 throw new IllegalArgumentException(); | |
126 | |
127 if (client.length == 0) | |
128 return null; | |
129 | |
130 for (int i = 0; i < client.length; i++) { | |
131 for (int j = 0; j < server.length; j++) { | |
132 if (client[i].equals(server[j])) | |
133 return client[i]; | |
134 } | |
135 } | |
136 | |
137 throw new NegotiateException(); | |
138 } | |
139 | |
140 private boolean compareFirstOfNameList(String[] a, String[] b) { | |
141 if (a == null || b == null) | |
142 throw new IllegalArgumentException(); | |
143 | |
144 if ((a.length == 0) && (b.length == 0)) | |
145 return true; | |
146 | |
147 if ((a.length == 0) || (b.length == 0)) | |
148 return false; | |
149 | |
150 return (a[0].equals(b[0])); | |
151 } | |
152 | |
153 private boolean isGuessOK(KexParameters cpar, KexParameters spar) { | |
154 if (cpar == null || spar == null) | |
155 throw new IllegalArgumentException(); | |
156 | |
157 if (compareFirstOfNameList(cpar.kex_algorithms, spar.kex_algorithms) == false) { | |
158 return false; | |
159 } | |
160 | |
161 if (compareFirstOfNameList(cpar.server_host_key_algorithms, spar.server_host_key_algorithms) == false) { | |
162 return false; | |
163 } | |
164 | |
165 /* | |
166 * We do NOT check here if the other algorithms can be agreed on, this | |
167 * is just a check if kex_algorithms and server_host_key_algorithms were | |
168 * guessed right! | |
169 */ | |
170 return true; | |
171 } | |
172 | |
173 private NegotiatedParameters mergeKexParameters(KexParameters client, KexParameters server) { | |
174 NegotiatedParameters np = new NegotiatedParameters(); | |
175 | |
176 try { | |
177 np.kex_algo = getFirstMatch(client.kex_algorithms, server.kex_algorithms); | |
178 log.log(20, "kex_algo=" + np.kex_algo); | |
179 np.server_host_key_algo = getFirstMatch(client.server_host_key_algorithms, | |
180 server.server_host_key_algorithms); | |
181 log.log(20, "server_host_key_algo=" + np.server_host_key_algo); | |
182 np.enc_algo_client_to_server = getFirstMatch(client.encryption_algorithms_client_to_server, | |
183 server.encryption_algorithms_client_to_server); | |
184 np.enc_algo_server_to_client = getFirstMatch(client.encryption_algorithms_server_to_client, | |
185 server.encryption_algorithms_server_to_client); | |
186 log.log(20, "enc_algo_client_to_server=" + np.enc_algo_client_to_server); | |
187 log.log(20, "enc_algo_server_to_client=" + np.enc_algo_server_to_client); | |
188 np.mac_algo_client_to_server = getFirstMatch(client.mac_algorithms_client_to_server, | |
189 server.mac_algorithms_client_to_server); | |
190 np.mac_algo_server_to_client = getFirstMatch(client.mac_algorithms_server_to_client, | |
191 server.mac_algorithms_server_to_client); | |
192 log.log(20, "mac_algo_client_to_server=" + np.mac_algo_client_to_server); | |
193 log.log(20, "mac_algo_server_to_client=" + np.mac_algo_server_to_client); | |
194 np.comp_algo_client_to_server = getFirstMatch(client.compression_algorithms_client_to_server, | |
195 server.compression_algorithms_client_to_server); | |
196 np.comp_algo_server_to_client = getFirstMatch(client.compression_algorithms_server_to_client, | |
197 server.compression_algorithms_server_to_client); | |
198 log.log(20, "comp_algo_client_to_server=" + np.comp_algo_client_to_server); | |
199 log.log(20, "comp_algo_server_to_client=" + np.comp_algo_server_to_client); | |
200 } | |
201 catch (NegotiateException e) { | |
202 return null; | |
203 } | |
204 | |
205 try { | |
206 np.lang_client_to_server = getFirstMatch(client.languages_client_to_server, | |
207 server.languages_client_to_server); | |
208 } | |
209 catch (NegotiateException e1) { | |
210 np.lang_client_to_server = null; | |
211 } | |
212 | |
213 try { | |
214 np.lang_server_to_client = getFirstMatch(client.languages_server_to_client, | |
215 server.languages_server_to_client); | |
216 } | |
217 catch (NegotiateException e2) { | |
218 np.lang_server_to_client = null; | |
219 } | |
220 | |
221 if (isGuessOK(client, server)) | |
222 np.guessOK = true; | |
223 | |
224 return np; | |
225 } | |
226 | |
227 public synchronized void initiateKEX(CryptoWishList cwl, DHGexParameters dhgex) throws IOException { | |
228 nextKEXcryptoWishList = cwl; | |
229 nextKEXdhgexParameters = dhgex; | |
230 | |
231 if (kxs == null) { | |
232 kxs = new KexState(); | |
233 kxs.dhgexParameters = nextKEXdhgexParameters; | |
234 PacketKexInit kp = new PacketKexInit(nextKEXcryptoWishList); | |
235 kxs.localKEX = kp; | |
236 tm.sendKexMessage(kp.getPayload()); | |
237 } | |
238 } | |
239 | |
240 private boolean establishKeyMaterial() { | |
241 try { | |
242 int mac_cs_key_len = MAC.getKeyLen(kxs.np.mac_algo_client_to_server); | |
243 int enc_cs_key_len = BlockCipherFactory.getKeySize(kxs.np.enc_algo_client_to_server); | |
244 int enc_cs_block_len = BlockCipherFactory.getBlockSize(kxs.np.enc_algo_client_to_server); | |
245 int mac_sc_key_len = MAC.getKeyLen(kxs.np.mac_algo_server_to_client); | |
246 int enc_sc_key_len = BlockCipherFactory.getKeySize(kxs.np.enc_algo_server_to_client); | |
247 int enc_sc_block_len = BlockCipherFactory.getBlockSize(kxs.np.enc_algo_server_to_client); | |
248 km = KeyMaterial.create(kxs.hashAlgo, kxs.H, kxs.K, sessionId, enc_cs_key_len, enc_cs_block_len, mac_cs_key_len, | |
249 enc_sc_key_len, enc_sc_block_len, mac_sc_key_len); | |
250 } | |
251 catch (IllegalArgumentException e) { | |
252 return false; | |
253 } | |
254 | |
255 return true; | |
256 } | |
257 | |
258 private void finishKex() throws IOException { | |
259 if (sessionId == null) | |
260 sessionId = kxs.H; | |
261 | |
262 establishKeyMaterial(); | |
263 /* Tell the other side that we start using the new material */ | |
264 PacketNewKeys ign = new PacketNewKeys(); | |
265 tm.sendKexMessage(ign.getPayload()); | |
266 BlockCipher cbc; | |
267 MAC mac; | |
268 ICompressor comp; | |
269 | |
270 try { | |
271 cbc = BlockCipherFactory.createCipher(kxs.np.enc_algo_client_to_server, true, km.enc_key_client_to_server, | |
272 km.initial_iv_client_to_server); | |
273 mac = new MAC(kxs.np.mac_algo_client_to_server, km.integrity_key_client_to_server); | |
274 comp = CompressionFactory.createCompressor(kxs.np.comp_algo_client_to_server); | |
275 } | |
276 catch (IllegalArgumentException e1) { | |
277 throw new IOException("Fatal error during MAC startup!"); | |
278 } | |
279 | |
280 tm.changeSendCipher(cbc, mac); | |
281 tm.changeSendCompression(comp); | |
282 tm.kexFinished(); | |
283 } | |
284 | |
285 public static final String[] getDefaultServerHostkeyAlgorithmList() { | |
286 return HOSTKEY_ALGS.toArray(new String[HOSTKEY_ALGS.size()]); | |
287 } | |
288 | |
289 public static final void checkServerHostkeyAlgorithmsList(String[] algos) { | |
290 for (int i = 0; i < algos.length; i++) { | |
291 if (!HOSTKEY_ALGS.contains(algos[i])) | |
292 throw new IllegalArgumentException("Unknown server host key algorithm '" + algos[i] + "'"); | |
293 } | |
294 } | |
295 | |
296 public static final String[] getDefaultKexAlgorithmList() { | |
297 return KEX_ALGS.toArray(new String[KEX_ALGS.size()]); | |
298 } | |
299 | |
300 public static final void checkKexAlgorithmList(String[] algos) { | |
301 for (int i = 0; i < algos.length; i++) { | |
302 if (!KEX_ALGS.contains(algos[i])) | |
303 throw new IllegalArgumentException("Unknown kex algorithm '" + algos[i] + "'"); | |
304 } | |
305 } | |
306 | |
307 private boolean verifySignature(byte[] sig, byte[] hostkey) throws IOException { | |
308 if (kxs.np.server_host_key_algo.startsWith("ecdsa-sha2-")) { | |
309 byte[] rs = ECDSASHA2Verify.decodeSSHECDSASignature(sig); | |
310 ECPublicKey epk = ECDSASHA2Verify.decodeSSHECDSAPublicKey(hostkey); | |
311 log.log(50, "Verifying ecdsa signature"); | |
312 return ECDSASHA2Verify.verifySignature(kxs.H, rs, epk); | |
313 } | |
314 | |
315 if (kxs.np.server_host_key_algo.equals("ssh-rsa")) { | |
316 byte[] rs = RSASHA1Verify.decodeSSHRSASignature(sig); | |
317 RSAPublicKey rpk = RSASHA1Verify.decodeSSHRSAPublicKey(hostkey); | |
318 log.log(50, "Verifying ssh-rsa signature"); | |
319 return RSASHA1Verify.verifySignature(kxs.H, rs, rpk); | |
320 } | |
321 | |
322 if (kxs.np.server_host_key_algo.equals("ssh-dss")) { | |
323 byte[] ds = DSASHA1Verify.decodeSSHDSASignature(sig); | |
324 DSAPublicKey dpk = DSASHA1Verify.decodeSSHDSAPublicKey(hostkey); | |
325 log.log(50, "Verifying ssh-dss signature"); | |
326 return DSASHA1Verify.verifySignature(kxs.H, ds, dpk); | |
327 } | |
328 | |
329 throw new IOException("Unknown server host key algorithm '" + kxs.np.server_host_key_algo + "'"); | |
330 } | |
331 | |
332 public synchronized void handleMessage(byte[] msg, int msglen) throws IOException { | |
333 PacketKexInit kip; | |
334 | |
335 if (msg == null) { | |
336 synchronized (accessLock) { | |
337 connectionClosed = true; | |
338 accessLock.notifyAll(); | |
339 return; | |
340 } | |
341 } | |
342 | |
343 if ((kxs == null) && (msg[0] != Packets.SSH_MSG_KEXINIT)) | |
344 throw new IOException("Unexpected KEX message (type " + msg[0] + ")"); | |
345 | |
346 if (ignore_next_kex_packet) { | |
347 ignore_next_kex_packet = false; | |
348 return; | |
349 } | |
350 | |
351 if (msg[0] == Packets.SSH_MSG_KEXINIT) { | |
352 if ((kxs != null) && (kxs.state != 0)) | |
353 throw new IOException("Unexpected SSH_MSG_KEXINIT message during on-going kex exchange!"); | |
354 | |
355 if (kxs == null) { | |
356 /* | |
357 * Ah, OK, peer wants to do KEX. Let's be nice and play | |
358 * together. | |
359 */ | |
360 kxs = new KexState(); | |
361 kxs.dhgexParameters = nextKEXdhgexParameters; | |
362 kip = new PacketKexInit(nextKEXcryptoWishList); | |
363 kxs.localKEX = kip; | |
364 tm.sendKexMessage(kip.getPayload()); | |
365 } | |
366 | |
367 kip = new PacketKexInit(msg, 0, msglen); | |
368 kxs.remoteKEX = kip; | |
369 kxs.np = mergeKexParameters(kxs.localKEX.getKexParameters(), kxs.remoteKEX.getKexParameters()); | |
370 | |
371 if (kxs.np == null) | |
372 throw new IOException("Cannot negotiate, proposals do not match."); | |
373 | |
374 if (kxs.remoteKEX.isFirst_kex_packet_follows() && (kxs.np.guessOK == false)) { | |
375 /* | |
376 * Guess was wrong, we need to ignore the next kex packet. | |
377 */ | |
378 ignore_next_kex_packet = true; | |
379 } | |
380 | |
381 if (kxs.np.kex_algo.equals("diffie-hellman-group-exchange-sha1") | |
382 || kxs.np.kex_algo.equals("diffie-hellman-group-exchange-sha256")) { | |
383 if (kxs.dhgexParameters.getMin_group_len() == 0 || csh.server_versioncomment.matches("OpenSSH_2\\.([0-4]\\.|5\\.[0-2]).*")) { | |
384 PacketKexDhGexRequestOld dhgexreq = new PacketKexDhGexRequestOld(kxs.dhgexParameters); | |
385 tm.sendKexMessage(dhgexreq.getPayload()); | |
386 } | |
387 else { | |
388 PacketKexDhGexRequest dhgexreq = new PacketKexDhGexRequest(kxs.dhgexParameters); | |
389 tm.sendKexMessage(dhgexreq.getPayload()); | |
390 } | |
391 | |
392 if (kxs.np.kex_algo.endsWith("sha1")) { | |
393 kxs.hashAlgo = "SHA1"; | |
394 } | |
395 else { | |
396 kxs.hashAlgo = "SHA-256"; | |
397 } | |
398 | |
399 kxs.state = 1; | |
400 return; | |
401 } | |
402 | |
403 if (kxs.np.kex_algo.equals("diffie-hellman-group1-sha1") | |
404 || kxs.np.kex_algo.equals("diffie-hellman-group14-sha1") | |
405 || kxs.np.kex_algo.equals("ecdh-sha2-nistp256") | |
406 || kxs.np.kex_algo.equals("ecdh-sha2-nistp384") | |
407 || kxs.np.kex_algo.equals("ecdh-sha2-nistp521")) { | |
408 kxs.dhx = GenericDhExchange.getInstance(kxs.np.kex_algo); | |
409 kxs.dhx.init(kxs.np.kex_algo); | |
410 kxs.hashAlgo = kxs.dhx.getHashAlgo(); | |
411 PacketKexDHInit kp = new PacketKexDHInit(kxs.dhx.getE()); | |
412 tm.sendKexMessage(kp.getPayload()); | |
413 kxs.state = 1; | |
414 return; | |
415 } | |
416 | |
417 throw new IllegalStateException("Unknown KEX method!"); | |
418 } | |
419 | |
420 if (msg[0] == Packets.SSH_MSG_NEWKEYS) { | |
421 if (km == null) | |
422 throw new IOException("Peer sent SSH_MSG_NEWKEYS, but I have no key material ready!"); | |
423 | |
424 BlockCipher cbc; | |
425 MAC mac; | |
426 ICompressor comp; | |
427 | |
428 try { | |
429 cbc = BlockCipherFactory.createCipher(kxs.np.enc_algo_server_to_client, false, | |
430 km.enc_key_server_to_client, km.initial_iv_server_to_client); | |
431 mac = new MAC(kxs.np.mac_algo_server_to_client, km.integrity_key_server_to_client); | |
432 comp = CompressionFactory.createCompressor(kxs.np.comp_algo_server_to_client); | |
433 } | |
434 catch (IllegalArgumentException e1) { | |
435 throw new IOException("Fatal error during MAC startup!"); | |
436 } | |
437 | |
438 tm.changeRecvCipher(cbc, mac); | |
439 tm.changeRecvCompression(comp); | |
440 ConnectionInfo sci = new ConnectionInfo(); | |
441 kexCount++; | |
442 sci.keyExchangeAlgorithm = kxs.np.kex_algo; | |
443 sci.keyExchangeCounter = kexCount; | |
444 sci.clientToServerCryptoAlgorithm = kxs.np.enc_algo_client_to_server; | |
445 sci.serverToClientCryptoAlgorithm = kxs.np.enc_algo_server_to_client; | |
446 sci.clientToServerMACAlgorithm = kxs.np.mac_algo_client_to_server; | |
447 sci.serverToClientMACAlgorithm = kxs.np.mac_algo_server_to_client; | |
448 sci.serverHostKeyAlgorithm = kxs.np.server_host_key_algo; | |
449 sci.serverHostKey = kxs.hostkey; | |
450 | |
451 synchronized (accessLock) { | |
452 lastConnInfo = sci; | |
453 accessLock.notifyAll(); | |
454 } | |
455 | |
456 kxs = null; | |
457 return; | |
458 } | |
459 | |
460 if ((kxs == null) || (kxs.state == 0)) | |
461 throw new IOException("Unexpected Kex submessage!"); | |
462 | |
463 if (kxs.np.kex_algo.equals("diffie-hellman-group-exchange-sha1") | |
464 || kxs.np.kex_algo.equals("diffie-hellman-group-exchange-sha256")) { | |
465 if (kxs.state == 1) { | |
466 PacketKexDhGexGroup dhgexgrp = new PacketKexDhGexGroup(msg, 0, msglen); | |
467 kxs.dhgx = new DhGroupExchange(dhgexgrp.getP(), dhgexgrp.getG()); | |
468 kxs.dhgx.init(rnd); | |
469 PacketKexDhGexInit dhgexinit = new PacketKexDhGexInit(kxs.dhgx.getE()); | |
470 tm.sendKexMessage(dhgexinit.getPayload()); | |
471 kxs.state = 2; | |
472 return; | |
473 } | |
474 | |
475 if (kxs.state == 2) { | |
476 PacketKexDhGexReply dhgexrpl = new PacketKexDhGexReply(msg, 0, msglen); | |
477 kxs.hostkey = dhgexrpl.getHostKey(); | |
478 | |
479 if (verifier != null) { | |
480 boolean vres = false; | |
481 | |
482 try { | |
483 vres = verifier.verifyServerHostKey(hostname, port, kxs.np.server_host_key_algo, kxs.hostkey); | |
484 } | |
485 catch (Exception e) { | |
486 throw(IOException) new IOException( | |
487 "The server hostkey was not accepted by the verifier callback.").initCause(e); | |
488 } | |
489 | |
490 if (vres == false) | |
491 throw new IOException("The server hostkey was not accepted by the verifier callback"); | |
492 } | |
493 | |
494 kxs.dhgx.setF(dhgexrpl.getF()); | |
495 | |
496 try { | |
497 kxs.H = kxs.dhgx.calculateH(kxs.hashAlgo, | |
498 csh.getClientString(), csh.getServerString(), | |
499 kxs.localKEX.getPayload(), kxs.remoteKEX.getPayload(), | |
500 dhgexrpl.getHostKey(), kxs.dhgexParameters); | |
501 } | |
502 catch (IllegalArgumentException e) { | |
503 throw(IOException) new IOException("KEX error.").initCause(e); | |
504 } | |
505 | |
506 boolean res = verifySignature(dhgexrpl.getSignature(), kxs.hostkey); | |
507 | |
508 if (res == false) | |
509 throw new IOException("Hostkey signature sent by remote is wrong!"); | |
510 | |
511 kxs.K = kxs.dhgx.getK(); | |
512 finishKex(); | |
513 kxs.state = -1; | |
514 return; | |
515 } | |
516 | |
517 throw new IllegalStateException("Illegal State in KEX Exchange!"); | |
518 } | |
519 | |
520 if (kxs.np.kex_algo.equals("diffie-hellman-group1-sha1") | |
521 || kxs.np.kex_algo.equals("diffie-hellman-group14-sha1") | |
522 || kxs.np.kex_algo.equals("ecdh-sha2-nistp256") | |
523 || kxs.np.kex_algo.equals("ecdh-sha2-nistp384") | |
524 || kxs.np.kex_algo.equals("ecdh-sha2-nistp521")) { | |
525 if (kxs.state == 1) { | |
526 PacketKexDHReply dhr = new PacketKexDHReply(msg, 0, msglen); | |
527 kxs.hostkey = dhr.getHostKey(); | |
528 | |
529 if (verifier != null) { | |
530 boolean vres = false; | |
531 | |
532 try { | |
533 vres = verifier.verifyServerHostKey(hostname, port, kxs.np.server_host_key_algo, kxs.hostkey); | |
534 } | |
535 catch (Exception e) { | |
536 throw(IOException) new IOException( | |
537 "The server hostkey was not accepted by the verifier callback.").initCause(e); | |
538 } | |
539 | |
540 if (vres == false) | |
541 throw new IOException("The server hostkey was not accepted by the verifier callback"); | |
542 } | |
543 | |
544 kxs.dhx.setF(dhr.getF()); | |
545 | |
546 try { | |
547 kxs.H = kxs.dhx.calculateH(csh.getClientString(), csh.getServerString(), kxs.localKEX.getPayload(), | |
548 kxs.remoteKEX.getPayload(), dhr.getHostKey()); | |
549 } | |
550 catch (IllegalArgumentException e) { | |
551 throw(IOException) new IOException("KEX error.").initCause(e); | |
552 } | |
553 | |
554 boolean res = verifySignature(dhr.getSignature(), kxs.hostkey); | |
555 | |
556 if (res == false) | |
557 throw new IOException("Hostkey signature sent by remote is wrong!"); | |
558 | |
559 kxs.K = kxs.dhx.getK(); | |
560 finishKex(); | |
561 kxs.state = -1; | |
562 return; | |
563 } | |
564 } | |
565 | |
566 throw new IllegalStateException("Unkown KEX method! (" + kxs.np.kex_algo + ")"); | |
567 } | |
568 } |