Mercurial > dropbear
comparison common-kex.c @ 4:fe6bca95afa7
Makefile.in contains updated files required
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Tue, 01 Jun 2004 02:46:09 +0000 |
parents | |
children | c1e5d9195402 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 4:fe6bca95afa7 |
---|---|
1 /* | |
2 * Dropbear - a SSH2 server | |
3 * SSH client implementation | |
4 * | |
5 * This code is copied from the larger file "kex.c" | |
6 * some functions are verbatim, others are generalized --mihnea | |
7 * | |
8 * Copyright (c) 2002,2003 Matt Johnston | |
9 * Portions Copyright (c) 2004 by Mihnea Stoenescu | |
10 * All rights reserved. | |
11 * | |
12 * Permission is hereby granted, free of charge, to any person obtaining a copy | |
13 * of this software and associated documentation files (the "Software"), to deal | |
14 * in the Software without restriction, including without limitation the rights | |
15 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
16 * copies of the Software, and to permit persons to whom the Software is | |
17 * furnished to do so, subject to the following conditions: | |
18 * | |
19 * The above copyright notice and this permission notice shall be included in | |
20 * all copies or substantial portions of the Software. | |
21 * | |
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
27 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
28 * SOFTWARE. */ | |
29 | |
30 #include "includes.h" | |
31 #include "dbutil.h" | |
32 #include "algo.h" | |
33 #include "buffer.h" | |
34 #include "session.h" | |
35 #include "kex.h" | |
36 #include "ssh.h" | |
37 #include "packet.h" | |
38 #include "bignum.h" | |
39 #include "random.h" | |
40 | |
41 /* diffie-hellman-group1-sha1 value for p */ | |
42 const unsigned char dh_p_val[] = { | |
43 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, | |
44 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, | |
45 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, | |
46 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, | |
47 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, | |
48 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, | |
49 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, | |
50 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, | |
51 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, | |
52 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81, | |
53 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | |
54 | |
55 const int DH_G_VAL = 2; | |
56 | |
57 static void gen_new_keys(); | |
58 #ifndef DISABLE_ZLIB | |
59 static void gen_new_zstreams(); | |
60 #endif | |
61 /* helper function for gen_new_keys */ | |
62 static void hashkeys(unsigned char *out, int outlen, | |
63 const hash_state * hs, unsigned const char X); | |
64 | |
65 | |
66 /* Send our list of algorithms we can use */ | |
67 void send_msg_kexinit() { | |
68 | |
69 CHECKCLEARTOWRITE(); | |
70 buf_putbyte(ses.writepayload, SSH_MSG_KEXINIT); | |
71 | |
72 /* cookie */ | |
73 genrandom(buf_getwriteptr(ses.writepayload, 16), 16); | |
74 buf_incrwritepos(ses.writepayload, 16); | |
75 | |
76 /* kex algos */ | |
77 buf_put_algolist(ses.writepayload, sshkex); | |
78 | |
79 /* server_host_key_algorithms */ | |
80 buf_put_algolist(ses.writepayload, sshhostkey); | |
81 | |
82 /* encryption_algorithms_client_to_server */ | |
83 buf_put_algolist(ses.writepayload, sshciphers); | |
84 | |
85 /* encryption_algorithms_server_to_client */ | |
86 buf_put_algolist(ses.writepayload, sshciphers); | |
87 | |
88 /* mac_algorithms_client_to_server */ | |
89 buf_put_algolist(ses.writepayload, sshhashes); | |
90 | |
91 /* mac_algorithms_server_to_client */ | |
92 buf_put_algolist(ses.writepayload, sshhashes); | |
93 | |
94 /* compression_algorithms_client_to_server */ | |
95 buf_put_algolist(ses.writepayload, sshcompress); | |
96 | |
97 /* compression_algorithms_server_to_client */ | |
98 buf_put_algolist(ses.writepayload, sshcompress); | |
99 | |
100 /* languages_client_to_server */ | |
101 buf_putstring(ses.writepayload, "", 0); | |
102 | |
103 /* languages_server_to_client */ | |
104 buf_putstring(ses.writepayload, "", 0); | |
105 | |
106 /* first_kex_packet_follows - unimplemented for now */ | |
107 buf_putbyte(ses.writepayload, 0x00); | |
108 | |
109 /* reserved unit32 */ | |
110 buf_putint(ses.writepayload, 0); | |
111 | |
112 /* set up transmitted kex packet buffer for hashing. | |
113 * This is freed after the end of the kex */ | |
114 ses.transkexinit = buf_newcopy(ses.writepayload); | |
115 | |
116 encrypt_packet(); | |
117 ses.dataallowed = 0; /* don't send other packets during kex */ | |
118 | |
119 TRACE(("DATAALLOWED=0")); | |
120 TRACE(("-> KEXINIT")); | |
121 ses.kexstate.sentkexinit = 1; | |
122 } | |
123 | |
124 /* *** NOTE regarding (send|recv)_msg_newkeys *** | |
125 * Changed by mihnea from the original kex.c to set dataallowed after a | |
126 * completed key exchange, no matter the order in which it was performed. | |
127 * This enables client mode without affecting server functionality. | |
128 */ | |
129 | |
130 /* Bring new keys into use after a key exchange, and let the client know*/ | |
131 void send_msg_newkeys() { | |
132 | |
133 TRACE(("enter send_msg_newkeys")); | |
134 | |
135 /* generate the kexinit request */ | |
136 CHECKCLEARTOWRITE(); | |
137 buf_putbyte(ses.writepayload, SSH_MSG_NEWKEYS); | |
138 encrypt_packet(); | |
139 | |
140 | |
141 /* set up our state */ | |
142 if (ses.kexstate.recvnewkeys) { | |
143 TRACE(("while RECVNEWKEYS=1")); | |
144 gen_new_keys(); | |
145 kexinitialise(); /* we've finished with this kex */ | |
146 TRACE((" -> DATAALLOWED=1")); | |
147 ses.dataallowed = 1; /* we can send other packets again now */ | |
148 } else { | |
149 ses.kexstate.sentnewkeys = 1; | |
150 TRACE(("SENTNEWKEYS=1")); | |
151 } | |
152 | |
153 TRACE(("-> MSG_NEWKEYS")); | |
154 TRACE(("leave send_msg_newkeys")); | |
155 } | |
156 | |
157 /* Bring the new keys into use after a key exchange */ | |
158 void recv_msg_newkeys() { | |
159 | |
160 TRACE(("<- MSG_NEWKEYS")); | |
161 TRACE(("enter recv_msg_newkeys")); | |
162 | |
163 /* simply check if we've sent SSH_MSG_NEWKEYS, and if so, | |
164 * switch to the new keys */ | |
165 if (ses.kexstate.sentnewkeys) { | |
166 TRACE(("while SENTNEWKEYS=1")); | |
167 gen_new_keys(); | |
168 kexinitialise(); /* we've finished with this kex */ | |
169 TRACE((" -> DATAALLOWED=1")); | |
170 ses.dataallowed = 1; /* we can send other packets again now */ | |
171 } else { | |
172 TRACE(("RECVNEWKEYS=1")); | |
173 ses.kexstate.recvnewkeys = 1; | |
174 } | |
175 | |
176 TRACE(("leave recv_msg_newkeys")); | |
177 } | |
178 | |
179 | |
180 /* Duplicated verbatim from kex.c --mihnea */ | |
181 void kexinitialise() { | |
182 | |
183 struct timeval tv; | |
184 | |
185 TRACE(("kexinitialise()")); | |
186 | |
187 /* sent/recv'd MSG_KEXINIT */ | |
188 ses.kexstate.sentkexinit = 0; | |
189 ses.kexstate.recvkexinit = 0; | |
190 | |
191 /* sent/recv'd MSG_NEWKEYS */ | |
192 ses.kexstate.recvnewkeys = 0; | |
193 ses.kexstate.sentnewkeys = 0; | |
194 | |
195 /* first_packet_follows */ | |
196 /* TODO - currently not handled */ | |
197 ses.kexstate.firstfollows = 0; | |
198 | |
199 ses.kexstate.datatrans = 0; | |
200 ses.kexstate.datarecv = 0; | |
201 | |
202 if (gettimeofday(&tv, 0) < 0) { | |
203 dropbear_exit("Error getting time"); | |
204 } | |
205 ses.kexstate.lastkextime = tv.tv_sec; | |
206 | |
207 } | |
208 | |
209 /* Helper function for gen_new_keys, creates a hash. It makes a copy of the | |
210 * already initialised hash_state hs, which should already have processed | |
211 * the dh_K and hash, since these are common. X is the letter 'A', 'B' etc. | |
212 * out must have at least min(SHA1_HASH_SIZE, outlen) bytes allocated. | |
213 * The output will only be expanded once, since that is all that is required | |
214 * (for 3DES and SHA, with 24 and 20 bytes respectively). | |
215 * | |
216 * See Section 5.2 of the IETF secsh Transport Draft for details */ | |
217 | |
218 /* Duplicated verbatim from kex.c --mihnea */ | |
219 static void hashkeys(unsigned char *out, int outlen, | |
220 const hash_state * hs, const unsigned char X) { | |
221 | |
222 hash_state hs2; | |
223 unsigned char k2[SHA1_HASH_SIZE]; /* used to extending */ | |
224 | |
225 memcpy(&hs2, hs, sizeof(hash_state)); | |
226 sha1_process(&hs2, &X, 1); | |
227 sha1_process(&hs2, ses.session_id, SHA1_HASH_SIZE); | |
228 sha1_done(&hs2, out); | |
229 if (SHA1_HASH_SIZE < outlen) { | |
230 /* need to extend */ | |
231 memcpy(&hs2, hs, sizeof(hash_state)); | |
232 sha1_process(&hs2, out, SHA1_HASH_SIZE); | |
233 sha1_done(&hs2, k2); | |
234 memcpy(&out[SHA1_HASH_SIZE], k2, outlen - SHA1_HASH_SIZE); | |
235 } | |
236 } | |
237 | |
238 /* Generate the actual encryption/integrity keys, using the results of the | |
239 * key exchange, as specified in section 5.2 of the IETF secsh-transport | |
240 * draft. This occurs after the DH key-exchange. | |
241 * | |
242 * ses.newkeys is the new set of keys which are generated, these are only | |
243 * taken into use after both sides have sent a newkeys message */ | |
244 | |
245 /* Originally from kex.c, generalized for cli/svr mode --mihnea */ | |
246 static void gen_new_keys() { | |
247 | |
248 unsigned char C2S_IV[MAX_IV_LEN]; | |
249 unsigned char C2S_key[MAX_KEY_LEN]; | |
250 unsigned char S2C_IV[MAX_IV_LEN]; | |
251 unsigned char S2C_key[MAX_KEY_LEN]; | |
252 /* unsigned char key[MAX_KEY_LEN]; */ | |
253 unsigned char *trans_IV, *trans_key, *recv_IV, *recv_key; | |
254 | |
255 hash_state hs; | |
256 unsigned int C2S_keysize, S2C_keysize; | |
257 char mactransletter, macrecvletter; /* Client or server specific */ | |
258 | |
259 TRACE(("enter gen_new_keys")); | |
260 /* the dh_K and hash are the start of all hashes, we make use of that */ | |
261 | |
262 sha1_init(&hs); | |
263 sha1_process_mp(&hs, ses.dh_K); | |
264 mp_clear(ses.dh_K); | |
265 m_free(ses.dh_K); | |
266 sha1_process(&hs, ses.hash, SHA1_HASH_SIZE); | |
267 m_burn(ses.hash, SHA1_HASH_SIZE); | |
268 | |
269 hashkeys(C2S_IV, SHA1_HASH_SIZE, &hs, 'A'); | |
270 hashkeys(S2C_IV, SHA1_HASH_SIZE, &hs, 'B'); | |
271 | |
272 if (IS_DROPBEAR_CLIENT) { | |
273 trans_IV = C2S_IV; | |
274 recv_IV = S2C_IV; | |
275 trans_key = C2S_key; | |
276 recv_key = S2C_key; | |
277 C2S_keysize = ses.newkeys->trans_algo_crypt->keysize; | |
278 S2C_keysize = ses.newkeys->recv_algo_crypt->keysize; | |
279 mactransletter = 'E'; | |
280 macrecvletter = 'F'; | |
281 } else { | |
282 trans_IV = S2C_IV; | |
283 recv_IV = C2S_IV; | |
284 trans_key = S2C_key; | |
285 recv_key = C2S_key; | |
286 C2S_keysize = ses.newkeys->recv_algo_crypt->keysize; | |
287 S2C_keysize = ses.newkeys->trans_algo_crypt->keysize; | |
288 mactransletter = 'F'; | |
289 macrecvletter = 'E'; | |
290 } | |
291 | |
292 hashkeys(C2S_key, C2S_keysize, &hs, 'C'); | |
293 hashkeys(S2C_key, S2C_keysize, &hs, 'D'); | |
294 | |
295 if (cbc_start( | |
296 find_cipher(ses.newkeys->recv_algo_crypt->cipherdesc->name), | |
297 recv_IV, recv_key, | |
298 ses.newkeys->recv_algo_crypt->keysize, 0, | |
299 &ses.newkeys->recv_symmetric_struct) != CRYPT_OK) { | |
300 dropbear_exit("crypto error"); | |
301 } | |
302 | |
303 if (cbc_start( | |
304 find_cipher(ses.newkeys->trans_algo_crypt->cipherdesc->name), | |
305 trans_IV, trans_key, | |
306 ses.newkeys->trans_algo_crypt->keysize, 0, | |
307 &ses.newkeys->trans_symmetric_struct) != CRYPT_OK) { | |
308 dropbear_exit("crypto error"); | |
309 } | |
310 | |
311 /* MAC keys */ | |
312 hashkeys(ses.newkeys->transmackey, | |
313 ses.newkeys->trans_algo_mac->keysize, &hs, mactransletter); | |
314 hashkeys(ses.newkeys->recvmackey, | |
315 ses.newkeys->recv_algo_mac->keysize, &hs, macrecvletter); | |
316 | |
317 #ifndef DISABLE_ZLIB | |
318 gen_new_zstreams(); | |
319 #endif | |
320 | |
321 /* Switch over to the new keys */ | |
322 m_burn(ses.keys, sizeof(struct key_context)); | |
323 m_free(ses.keys); | |
324 ses.keys = ses.newkeys; | |
325 ses.newkeys = NULL; | |
326 | |
327 TRACE(("leave gen_new_keys")); | |
328 } | |
329 | |
330 #ifndef DISABLE_ZLIB | |
331 /* Set up new zlib compression streams, close the old ones. Only | |
332 * called from gen_new_keys() */ | |
333 static void gen_new_zstreams() { | |
334 | |
335 /* create new zstreams */ | |
336 if (ses.newkeys->recv_algo_comp == DROPBEAR_COMP_ZLIB) { | |
337 ses.newkeys->recv_zstream = (z_streamp)m_malloc(sizeof(z_stream)); | |
338 ses.newkeys->recv_zstream->zalloc = Z_NULL; | |
339 ses.newkeys->recv_zstream->zfree = Z_NULL; | |
340 | |
341 if (inflateInit(ses.newkeys->recv_zstream) != Z_OK) { | |
342 dropbear_exit("zlib error"); | |
343 } | |
344 } else { | |
345 ses.newkeys->recv_zstream = NULL; | |
346 } | |
347 | |
348 if (ses.newkeys->trans_algo_comp == DROPBEAR_COMP_ZLIB) { | |
349 ses.newkeys->trans_zstream = (z_streamp)m_malloc(sizeof(z_stream)); | |
350 ses.newkeys->trans_zstream->zalloc = Z_NULL; | |
351 ses.newkeys->trans_zstream->zfree = Z_NULL; | |
352 | |
353 if (deflateInit(ses.newkeys->trans_zstream, Z_DEFAULT_COMPRESSION) | |
354 != Z_OK) { | |
355 dropbear_exit("zlib error"); | |
356 } | |
357 } else { | |
358 ses.newkeys->trans_zstream = NULL; | |
359 } | |
360 | |
361 /* clean up old keys */ | |
362 if (ses.keys->recv_zstream != NULL) { | |
363 if (inflateEnd(ses.keys->recv_zstream) == Z_STREAM_ERROR) { | |
364 /* Z_DATA_ERROR is ok, just means that stream isn't ended */ | |
365 dropbear_exit("crypto error"); | |
366 } | |
367 m_free(ses.keys->recv_zstream); | |
368 } | |
369 if (ses.keys->trans_zstream != NULL) { | |
370 if (deflateEnd(ses.keys->trans_zstream) == Z_STREAM_ERROR) { | |
371 /* Z_DATA_ERROR is ok, just means that stream isn't ended */ | |
372 dropbear_exit("crypto error"); | |
373 } | |
374 m_free(ses.keys->trans_zstream); | |
375 } | |
376 } | |
377 #endif | |
378 | |
379 | |
380 /* Executed upon receiving a kexinit message from the client to initiate | |
381 * key exchange. If we haven't already done so, we send the list of our | |
382 * preferred algorithms. The client's requested algorithms are processed, | |
383 * and we calculate the first portion of the key-exchange-hash for used | |
384 * later in the key exchange. No response is sent, as the client should | |
385 * initiate the diffie-hellman key exchange */ | |
386 | |
387 /* Originally from kex.c, generalized for cli/svr mode --mihnea */ | |
388 /* Belongs in common_kex.c where it should be moved after review */ | |
389 void recv_msg_kexinit() { | |
390 | |
391 TRACE(("<- KEXINIT")); | |
392 TRACE(("enter recv_msg_kexinit")); | |
393 | |
394 /* start the kex hash */ | |
395 ses.kexhashbuf = buf_new(MAX_KEXHASHBUF); | |
396 | |
397 if (!ses.kexstate.sentkexinit) { | |
398 /* we need to send a kex packet */ | |
399 send_msg_kexinit(); | |
400 TRACE(("continue recv_msg_kexinit: sent kexinit")); | |
401 } | |
402 | |
403 | |
404 if (IS_DROPBEAR_CLIENT) { | |
405 | |
406 /* read the peer's choice of algos */ | |
407 cli_read_kex(); | |
408 | |
409 /* V_C, the client's version string (CR and NL excluded) */ | |
410 buf_putstring(ses.kexhashbuf, | |
411 (unsigned char*)LOCAL_IDENT, strlen(LOCAL_IDENT)); | |
412 /* V_S, the server's version string (CR and NL excluded) */ | |
413 buf_putstring(ses.kexhashbuf, | |
414 ses.remoteident, strlen((char*)ses.remoteident)); | |
415 | |
416 /* I_C, the payload of the client's SSH_MSG_KEXINIT */ | |
417 buf_putstring(ses.kexhashbuf, | |
418 buf_getptr(ses.transkexinit, ses.transkexinit->len), | |
419 ses.transkexinit->len); | |
420 /* I_S, the payload of the server's SSH_MSG_KEXINIT */ | |
421 buf_setpos(ses.payload, 0); | |
422 buf_putstring(ses.kexhashbuf, | |
423 buf_getptr(ses.payload, ses.payload->len), | |
424 ses.payload->len); | |
425 | |
426 } else { | |
427 | |
428 /* read the peer's choice of algos */ | |
429 svr_read_kex(); | |
430 /* V_C, the client's version string (CR and NL excluded) */ | |
431 buf_putstring(ses.kexhashbuf, | |
432 ses.remoteident, strlen((char*)ses.remoteident)); | |
433 /* V_S, the server's version string (CR and NL excluded) */ | |
434 buf_putstring(ses.kexhashbuf, | |
435 (unsigned char*)LOCAL_IDENT, strlen(LOCAL_IDENT)); | |
436 | |
437 /* I_C, the payload of the client's SSH_MSG_KEXINIT */ | |
438 buf_setpos(ses.payload, 0); | |
439 buf_putstring(ses.kexhashbuf, | |
440 buf_getptr(ses.payload, ses.payload->len), | |
441 ses.payload->len); | |
442 /* I_S, the payload of the server's SSH_MSG_KEXINIT */ | |
443 buf_putstring(ses.kexhashbuf, | |
444 buf_getptr(ses.transkexinit, ses.transkexinit->len), | |
445 ses.transkexinit->len); | |
446 } | |
447 | |
448 buf_free(ses.transkexinit); | |
449 ses.transkexinit = NULL; | |
450 /* the rest of ses.kexhashbuf will be done after DH exchange */ | |
451 | |
452 ses.kexstate.recvkexinit = 1; | |
453 // ses.expecting = SSH_MSG_KEXDH_INIT; | |
454 ses.expecting = 0; | |
455 | |
456 TRACE(("leave recv_msg_kexinit")); | |
457 } | |
458 |