Mercurial > 510Connectbot
comparison src/ch/ethz/ssh2/transport/ClientKexManager.java @ 273:91a31873c42a ganymed
start conversion from trilead to ganymed
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Fri, 18 Jul 2014 11:21:46 -0700 |
parents | |
children | d7e088fa2123 |
comparison
equal
deleted
inserted
replaced
272:ce2f4e397703 | 273:91a31873c42a |
---|---|
1 /* | |
2 * Copyright (c) 2006-2013 Christian Plattner. All rights reserved. | |
3 * Please refer to the LICENSE.txt for licensing details. | |
4 */ | |
5 package ch.ethz.ssh2.transport; | |
6 | |
7 import java.io.IOException; | |
8 import java.security.DigestException; | |
9 import java.security.SecureRandom; | |
10 | |
11 import ch.ethz.ssh2.ConnectionInfo; | |
12 import ch.ethz.ssh2.PacketTypeException; | |
13 import ch.ethz.ssh2.ServerHostKeyVerifier; | |
14 import ch.ethz.ssh2.compression.CompressionFactory; | |
15 import ch.ethz.ssh2.compression.Compressor; | |
16 import ch.ethz.ssh2.crypto.CryptoWishList; | |
17 import ch.ethz.ssh2.crypto.cipher.BlockCipher; | |
18 import ch.ethz.ssh2.crypto.cipher.BlockCipherFactory; | |
19 import ch.ethz.ssh2.crypto.dh.DhExchange; | |
20 import ch.ethz.ssh2.crypto.dh.DhGroupExchange; | |
21 import ch.ethz.ssh2.crypto.digest.MAC; | |
22 import ch.ethz.ssh2.packets.PacketKexDHInit; | |
23 import ch.ethz.ssh2.packets.PacketKexDHReply; | |
24 import ch.ethz.ssh2.packets.PacketKexDhGexGroup; | |
25 import ch.ethz.ssh2.packets.PacketKexDhGexInit; | |
26 import ch.ethz.ssh2.packets.PacketKexDhGexReply; | |
27 import ch.ethz.ssh2.packets.PacketKexDhGexRequest; | |
28 import ch.ethz.ssh2.packets.PacketKexDhGexRequestOld; | |
29 import ch.ethz.ssh2.packets.PacketKexInit; | |
30 import ch.ethz.ssh2.packets.Packets; | |
31 import ch.ethz.ssh2.signature.DSAPublicKey; | |
32 import ch.ethz.ssh2.signature.DSASHA1Verify; | |
33 import ch.ethz.ssh2.signature.DSASignature; | |
34 import ch.ethz.ssh2.signature.RSAPublicKey; | |
35 import ch.ethz.ssh2.signature.RSASHA1Verify; | |
36 import ch.ethz.ssh2.signature.RSASignature; | |
37 | |
38 /** | |
39 * @version $Id: ClientKexManager.java 160 2014-05-01 14:30:26Z dkocher@sudo.ch $ | |
40 */ | |
41 public class ClientKexManager extends KexManager { | |
42 | |
43 private final ServerHostKeyVerifier verifier; | |
44 | |
45 private final String hostname; | |
46 | |
47 private final int port; | |
48 | |
49 public ClientKexManager(TransportManager tm, ClientServerHello csh, CryptoWishList initialCwl, String hostname, int port, | |
50 ServerHostKeyVerifier keyVerifier, SecureRandom rnd) { | |
51 super(tm, csh, initialCwl, rnd); | |
52 this.hostname = hostname; | |
53 this.port = port; | |
54 this.verifier = keyVerifier; | |
55 } | |
56 | |
57 protected boolean verifySignature(byte[] sig, byte[] hostkey) throws IOException { | |
58 if(kxs.np.server_host_key_algo.equals("ssh-rsa")) { | |
59 RSASignature rs = RSASHA1Verify.decodeSSHRSASignature(sig); | |
60 RSAPublicKey rpk = RSASHA1Verify.decodeSSHRSAPublicKey(hostkey); | |
61 | |
62 log.debug("Verifying ssh-rsa signature"); | |
63 | |
64 return RSASHA1Verify.verifySignature(kxs.H, rs, rpk); | |
65 } | |
66 | |
67 if(kxs.np.server_host_key_algo.equals("ssh-dss")) { | |
68 DSASignature ds = DSASHA1Verify.decodeSSHDSASignature(sig); | |
69 DSAPublicKey dpk = DSASHA1Verify.decodeSSHDSAPublicKey(hostkey); | |
70 | |
71 log.debug("Verifying ssh-dss signature"); | |
72 | |
73 return DSASHA1Verify.verifySignature(kxs.H, ds, dpk); | |
74 } | |
75 | |
76 throw new IOException("Unknown server host key algorithm '" + kxs.np.server_host_key_algo + "'"); | |
77 } | |
78 | |
79 @Override | |
80 public void handleFailure(final IOException failure) { | |
81 synchronized(accessLock) { | |
82 connectionClosed = true; | |
83 accessLock.notifyAll(); | |
84 } | |
85 } | |
86 | |
87 @Override | |
88 public synchronized void handleMessage(byte[] msg) throws IOException { | |
89 PacketKexInit kip; | |
90 | |
91 if((kxs == null) && (msg[0] != Packets.SSH_MSG_KEXINIT)) { | |
92 throw new PacketTypeException(msg[0]); | |
93 } | |
94 | |
95 if(ignore_next_kex_packet) { | |
96 ignore_next_kex_packet = false; | |
97 return; | |
98 } | |
99 | |
100 if(msg[0] == Packets.SSH_MSG_KEXINIT) { | |
101 if((kxs != null) && (kxs.state != 0)) { | |
102 throw new PacketTypeException(msg[0]); | |
103 } | |
104 | |
105 if(kxs == null) { | |
106 /* | |
107 * Ah, OK, peer wants to do KEX. Let's be nice and play | |
108 * together. | |
109 */ | |
110 kxs = new KexState(); | |
111 kxs.dhgexParameters = nextKEXdhgexParameters; | |
112 kip = new PacketKexInit(nextKEXcryptoWishList, rnd); | |
113 kxs.localKEX = kip; | |
114 tm.sendKexMessage(kip.getPayload()); | |
115 } | |
116 | |
117 kip = new PacketKexInit(msg); | |
118 kxs.remoteKEX = kip; | |
119 | |
120 kxs.np = mergeKexParameters(kxs.localKEX.getKexParameters(), kxs.remoteKEX.getKexParameters()); | |
121 | |
122 if(kxs.remoteKEX.isFirst_kex_packet_follows() && (kxs.np.guessOK == false)) { | |
123 // Guess was wrong, we need to ignore the next kex packet. | |
124 ignore_next_kex_packet = true; | |
125 } | |
126 | |
127 if(kxs.np.kex_algo.equals("diffie-hellman-group-exchange-sha1")) { | |
128 if(kxs.dhgexParameters.getMin_group_len() == 0) { | |
129 PacketKexDhGexRequestOld dhgexreq = new PacketKexDhGexRequestOld(kxs.dhgexParameters); | |
130 tm.sendKexMessage(dhgexreq.getPayload()); | |
131 | |
132 } | |
133 else { | |
134 PacketKexDhGexRequest dhgexreq = new PacketKexDhGexRequest(kxs.dhgexParameters); | |
135 tm.sendKexMessage(dhgexreq.getPayload()); | |
136 } | |
137 kxs.state = 1; | |
138 return; | |
139 } | |
140 | |
141 if(kxs.np.kex_algo.equals("diffie-hellman-group1-sha1") | |
142 || kxs.np.kex_algo.equals("diffie-hellman-group14-sha1")) { | |
143 kxs.dhx = new DhExchange(); | |
144 | |
145 if(kxs.np.kex_algo.equals("diffie-hellman-group1-sha1")) { | |
146 kxs.dhx.clientInit(1, rnd); | |
147 } | |
148 else { | |
149 kxs.dhx.clientInit(14, rnd); | |
150 } | |
151 | |
152 PacketKexDHInit kp = new PacketKexDHInit(kxs.dhx.getE()); | |
153 tm.sendKexMessage(kp.getPayload()); | |
154 kxs.state = 1; | |
155 return; | |
156 } | |
157 | |
158 throw new IllegalStateException("Unkown KEX method!"); | |
159 } | |
160 | |
161 if(msg[0] == Packets.SSH_MSG_NEWKEYS) { | |
162 if(km == null) { | |
163 throw new IOException("Peer sent SSH_MSG_NEWKEYS, but I have no key material ready!"); | |
164 } | |
165 | |
166 BlockCipher cbc; | |
167 MAC mac; | |
168 Compressor comp; | |
169 | |
170 try { | |
171 cbc = BlockCipherFactory.createCipher(kxs.np.enc_algo_server_to_client, false, | |
172 km.enc_key_server_to_client, km.initial_iv_server_to_client); | |
173 | |
174 try { | |
175 mac = new MAC(kxs.np.mac_algo_server_to_client, km.integrity_key_server_to_client); | |
176 } | |
177 catch(DigestException e) { | |
178 throw new IOException(e); | |
179 } | |
180 | |
181 comp = CompressionFactory.createCompressor(kxs.np.comp_algo_server_to_client); | |
182 } | |
183 catch(IllegalArgumentException e) { | |
184 throw new IOException(e.getMessage()); | |
185 } | |
186 | |
187 tm.changeRecvCipher(cbc, mac); | |
188 tm.changeRecvCompression(comp); | |
189 | |
190 ConnectionInfo sci = new ConnectionInfo(); | |
191 | |
192 kexCount++; | |
193 | |
194 sci.keyExchangeAlgorithm = kxs.np.kex_algo; | |
195 sci.keyExchangeCounter = kexCount; | |
196 sci.clientToServerCryptoAlgorithm = kxs.np.enc_algo_client_to_server; | |
197 sci.serverToClientCryptoAlgorithm = kxs.np.enc_algo_server_to_client; | |
198 sci.clientToServerMACAlgorithm = kxs.np.mac_algo_client_to_server; | |
199 sci.serverToClientMACAlgorithm = kxs.np.mac_algo_server_to_client; | |
200 sci.serverHostKeyAlgorithm = kxs.np.server_host_key_algo; | |
201 sci.serverHostKey = kxs.remote_hostkey; | |
202 | |
203 synchronized(accessLock) { | |
204 lastConnInfo = sci; | |
205 accessLock.notifyAll(); | |
206 } | |
207 | |
208 kxs = null; | |
209 return; | |
210 } | |
211 | |
212 if((kxs == null) || (kxs.state == 0)) { | |
213 throw new IOException("Unexpected Kex submessage!"); | |
214 } | |
215 | |
216 if(kxs.np.kex_algo.equals("diffie-hellman-group-exchange-sha1")) { | |
217 if(kxs.state == 1) { | |
218 PacketKexDhGexGroup dhgexgrp = new PacketKexDhGexGroup(msg); | |
219 kxs.dhgx = new DhGroupExchange(dhgexgrp.getP(), dhgexgrp.getG()); | |
220 kxs.dhgx.init(rnd); | |
221 PacketKexDhGexInit dhgexinit = new PacketKexDhGexInit(kxs.dhgx.getE()); | |
222 tm.sendKexMessage(dhgexinit.getPayload()); | |
223 kxs.state = 2; | |
224 return; | |
225 } | |
226 | |
227 if(kxs.state == 2) { | |
228 PacketKexDhGexReply dhgexrpl = new PacketKexDhGexReply(msg); | |
229 | |
230 kxs.remote_hostkey = dhgexrpl.getHostKey(); | |
231 | |
232 if(verifier != null) { | |
233 try { | |
234 if(!verifier.verifyServerHostKey(hostname, port, kxs.np.server_host_key_algo, kxs.remote_hostkey)) { | |
235 throw new IOException("The server host key was not accepted by the verifier callback"); | |
236 } | |
237 } | |
238 catch(Exception e) { | |
239 throw new IOException( | |
240 "The server host key was not accepted by the verifier callback.", e); | |
241 } | |
242 } | |
243 | |
244 kxs.dhgx.setF(dhgexrpl.getF()); | |
245 | |
246 try { | |
247 kxs.H = kxs.dhgx.calculateH(csh.getClientString(), csh.getServerString(), | |
248 kxs.localKEX.getPayload(), kxs.remoteKEX.getPayload(), dhgexrpl.getHostKey(), | |
249 kxs.dhgexParameters); | |
250 } | |
251 catch(IllegalArgumentException e) { | |
252 throw new IOException("KEX error.", e); | |
253 } | |
254 if(!verifySignature(dhgexrpl.getSignature(), kxs.remote_hostkey)) { | |
255 throw new IOException("Invalid remote host key signature"); | |
256 } | |
257 kxs.K = kxs.dhgx.getK(); | |
258 finishKex(true); | |
259 kxs.state = -1; | |
260 return; | |
261 } | |
262 | |
263 throw new IllegalStateException("Illegal State in KEX Exchange!"); | |
264 } | |
265 | |
266 if(kxs.np.kex_algo.equals("diffie-hellman-group1-sha1") | |
267 || kxs.np.kex_algo.equals("diffie-hellman-group14-sha1")) { | |
268 if(kxs.state == 1) { | |
269 | |
270 PacketKexDHReply dhr = new PacketKexDHReply(msg); | |
271 | |
272 kxs.remote_hostkey = dhr.getHostKey(); | |
273 | |
274 if(verifier != null) { | |
275 try { | |
276 if(!verifier.verifyServerHostKey(hostname, port, kxs.np.server_host_key_algo, kxs.remote_hostkey)) { | |
277 throw new IOException("The server host key was not accepted by the verifier callback"); | |
278 } | |
279 } | |
280 catch(Exception e) { | |
281 throw new IOException("The server host key was not accepted by the verifier callback", e); | |
282 } | |
283 } | |
284 kxs.dhx.setF(dhr.getF()); | |
285 try { | |
286 kxs.H = kxs.dhx.calculateH(csh.getClientString(), csh.getServerString(), kxs.localKEX.getPayload(), | |
287 kxs.remoteKEX.getPayload(), dhr.getHostKey()); | |
288 } | |
289 catch(IllegalArgumentException e) { | |
290 throw new IOException("KEX error.", e); | |
291 } | |
292 if(!verifySignature(dhr.getSignature(), kxs.remote_hostkey)) { | |
293 throw new IOException("Invalid remote host key signature"); | |
294 } | |
295 kxs.K = kxs.dhx.getK(); | |
296 finishKex(true); | |
297 kxs.state = -1; | |
298 return; | |
299 } | |
300 } | |
301 throw new IllegalStateException(String.format("Unknown KEX method %s", kxs.np.kex_algo)); | |
302 } | |
303 } |