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 }