Mercurial > dropbear
comparison common-kex.c @ 389:5ff8218bcee9
propagate from branch 'au.asn.ucc.matt.ltm.dropbear' (head 2af95f00ebd5bb7a28b3817db1218442c935388e)
to branch 'au.asn.ucc.matt.dropbear' (head ecd779509ef23a8cdf64888904fc9b31d78aa933)
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Thu, 11 Jan 2007 03:14:55 +0000 |
parents | 3e098639b05f |
children | e66eec4dcba7 b895f91c2ee6 |
comparison
equal
deleted
inserted
replaced
388:fb54020f78e1 | 389:5ff8218bcee9 |
---|---|
1 /* | |
2 * Dropbear SSH | |
3 * | |
4 * Copyright (c) 2002-2004 Matt Johnston | |
5 * Portions Copyright (c) 2004 by Mihnea Stoenescu | |
6 * All rights reserved. | |
7 * | |
8 * Permission is hereby granted, free of charge, to any person obtaining a copy | |
9 * of this software and associated documentation files (the "Software"), to deal | |
10 * in the Software without restriction, including without limitation the rights | |
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
12 * copies of the Software, and to permit persons to whom the Software is | |
13 * furnished to do so, subject to the following conditions: | |
14 * | |
15 * The above copyright notice and this permission notice shall be included in | |
16 * all copies or substantial portions of the Software. | |
17 * | |
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
24 * SOFTWARE. */ | |
25 | |
26 #include "includes.h" | |
27 #include "dbutil.h" | |
28 #include "algo.h" | |
29 #include "buffer.h" | |
30 #include "session.h" | |
31 #include "kex.h" | |
32 #include "ssh.h" | |
33 #include "packet.h" | |
34 #include "bignum.h" | |
35 #include "random.h" | |
36 | |
37 /* diffie-hellman-group1-sha1 value for p */ | |
38 static const unsigned char dh_p_val[] = { | |
39 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, | |
40 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, | |
41 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, | |
42 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, | |
43 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, | |
44 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, | |
45 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, | |
46 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, | |
47 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, | |
48 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81, | |
49 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | |
50 #define DH_P_LEN sizeof(dh_p_val) | |
51 | |
52 static const int DH_G_VAL = 2; | |
53 | |
54 static void kexinitialise(); | |
55 void gen_new_keys(); | |
56 #ifndef DISABLE_ZLIB | |
57 static void gen_new_zstreams(); | |
58 #endif | |
59 static void read_kex_algos(); | |
60 /* helper function for gen_new_keys */ | |
61 static void hashkeys(unsigned char *out, int outlen, | |
62 const hash_state * hs, unsigned const char X); | |
63 | |
64 | |
65 /* Send our list of algorithms we can use */ | |
66 void send_msg_kexinit() { | |
67 | |
68 CHECKCLEARTOWRITE(); | |
69 buf_putbyte(ses.writepayload, SSH_MSG_KEXINIT); | |
70 | |
71 /* cookie */ | |
72 genrandom(buf_getwriteptr(ses.writepayload, 16), 16); | |
73 buf_incrwritepos(ses.writepayload, 16); | |
74 | |
75 /* kex algos */ | |
76 buf_put_algolist(ses.writepayload, sshkex); | |
77 | |
78 /* server_host_key_algorithms */ | |
79 buf_put_algolist(ses.writepayload, sshhostkey); | |
80 | |
81 /* encryption_algorithms_client_to_server */ | |
82 buf_put_algolist(ses.writepayload, sshciphers); | |
83 | |
84 /* encryption_algorithms_server_to_client */ | |
85 buf_put_algolist(ses.writepayload, sshciphers); | |
86 | |
87 /* mac_algorithms_client_to_server */ | |
88 buf_put_algolist(ses.writepayload, sshhashes); | |
89 | |
90 /* mac_algorithms_server_to_client */ | |
91 buf_put_algolist(ses.writepayload, sshhashes); | |
92 | |
93 /* compression_algorithms_client_to_server */ | |
94 buf_put_algolist(ses.writepayload, sshcompress); | |
95 | |
96 /* compression_algorithms_server_to_client */ | |
97 buf_put_algolist(ses.writepayload, sshcompress); | |
98 | |
99 /* languages_client_to_server */ | |
100 buf_putstring(ses.writepayload, "", 0); | |
101 | |
102 /* languages_server_to_client */ | |
103 buf_putstring(ses.writepayload, "", 0); | |
104 | |
105 /* first_kex_packet_follows - unimplemented for now */ | |
106 buf_putbyte(ses.writepayload, 0x00); | |
107 | |
108 /* reserved unit32 */ | |
109 buf_putint(ses.writepayload, 0); | |
110 | |
111 /* set up transmitted kex packet buffer for hashing. | |
112 * This is freed after the end of the kex */ | |
113 ses.transkexinit = buf_newcopy(ses.writepayload); | |
114 | |
115 encrypt_packet(); | |
116 ses.dataallowed = 0; /* don't send other packets during kex */ | |
117 | |
118 TRACE(("DATAALLOWED=0")) | |
119 TRACE(("-> KEXINIT")) | |
120 ses.kexstate.sentkexinit = 1; | |
121 } | |
122 | |
123 /* *** NOTE regarding (send|recv)_msg_newkeys *** | |
124 * Changed by mihnea from the original kex.c to set dataallowed after a | |
125 * completed key exchange, no matter the order in which it was performed. | |
126 * This enables client mode without affecting server functionality. | |
127 */ | |
128 | |
129 /* Bring new keys into use after a key exchange, and let the client know*/ | |
130 void send_msg_newkeys() { | |
131 | |
132 TRACE(("enter send_msg_newkeys")) | |
133 | |
134 /* generate the kexinit request */ | |
135 CHECKCLEARTOWRITE(); | |
136 buf_putbyte(ses.writepayload, SSH_MSG_NEWKEYS); | |
137 encrypt_packet(); | |
138 | |
139 | |
140 /* set up our state */ | |
141 if (ses.kexstate.recvnewkeys) { | |
142 TRACE(("while RECVNEWKEYS=1")) | |
143 gen_new_keys(); | |
144 kexinitialise(); /* we've finished with this kex */ | |
145 TRACE((" -> DATAALLOWED=1")) | |
146 ses.dataallowed = 1; /* we can send other packets again now */ | |
147 ses.kexstate.donefirstkex = 1; | |
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 ses.kexstate.donefirstkex = 1; | |
172 } else { | |
173 TRACE(("RECVNEWKEYS=1")) | |
174 ses.kexstate.recvnewkeys = 1; | |
175 } | |
176 | |
177 TRACE(("leave recv_msg_newkeys")) | |
178 } | |
179 | |
180 | |
181 /* Set up the kex for the first time */ | |
182 void kexfirstinitialise() { | |
183 | |
184 ses.kexstate.donefirstkex = 0; | |
185 kexinitialise(); | |
186 } | |
187 | |
188 /* Reset the kex state, ready for a new negotiation */ | |
189 static void kexinitialise() { | |
190 | |
191 struct timeval tv; | |
192 | |
193 TRACE(("kexinitialise()")) | |
194 | |
195 /* sent/recv'd MSG_KEXINIT */ | |
196 ses.kexstate.sentkexinit = 0; | |
197 ses.kexstate.recvkexinit = 0; | |
198 | |
199 /* sent/recv'd MSG_NEWKEYS */ | |
200 ses.kexstate.recvnewkeys = 0; | |
201 ses.kexstate.sentnewkeys = 0; | |
202 | |
203 /* first_packet_follows */ | |
204 ses.kexstate.firstfollows = 0; | |
205 | |
206 ses.kexstate.datatrans = 0; | |
207 ses.kexstate.datarecv = 0; | |
208 | |
209 if (gettimeofday(&tv, 0) < 0) { | |
210 dropbear_exit("Error getting time"); | |
211 } | |
212 ses.kexstate.lastkextime = tv.tv_sec; | |
213 | |
214 } | |
215 | |
216 /* Helper function for gen_new_keys, creates a hash. It makes a copy of the | |
217 * already initialised hash_state hs, which should already have processed | |
218 * the dh_K and hash, since these are common. X is the letter 'A', 'B' etc. | |
219 * out must have at least min(SHA1_HASH_SIZE, outlen) bytes allocated. | |
220 * The output will only be expanded once, since that is all that is required | |
221 * (for 3DES and SHA, with 24 and 20 bytes respectively). | |
222 * | |
223 * See Section 5.2 of the IETF secsh Transport Draft for details */ | |
224 | |
225 /* Duplicated verbatim from kex.c --mihnea */ | |
226 static void hashkeys(unsigned char *out, int outlen, | |
227 const hash_state * hs, const unsigned char X) { | |
228 | |
229 hash_state hs2; | |
230 unsigned char k2[SHA1_HASH_SIZE]; /* used to extending */ | |
231 | |
232 memcpy(&hs2, hs, sizeof(hash_state)); | |
233 sha1_process(&hs2, &X, 1); | |
234 sha1_process(&hs2, ses.session_id, SHA1_HASH_SIZE); | |
235 sha1_done(&hs2, out); | |
236 if (SHA1_HASH_SIZE < outlen) { | |
237 /* need to extend */ | |
238 memcpy(&hs2, hs, sizeof(hash_state)); | |
239 sha1_process(&hs2, out, SHA1_HASH_SIZE); | |
240 sha1_done(&hs2, k2); | |
241 memcpy(&out[SHA1_HASH_SIZE], k2, outlen - SHA1_HASH_SIZE); | |
242 } | |
243 } | |
244 | |
245 /* Generate the actual encryption/integrity keys, using the results of the | |
246 * key exchange, as specified in section 5.2 of the IETF secsh-transport | |
247 * draft. This occurs after the DH key-exchange. | |
248 * | |
249 * ses.newkeys is the new set of keys which are generated, these are only | |
250 * taken into use after both sides have sent a newkeys message */ | |
251 | |
252 /* Originally from kex.c, generalized for cli/svr mode --mihnea */ | |
253 void gen_new_keys() { | |
254 | |
255 unsigned char C2S_IV[MAX_IV_LEN]; | |
256 unsigned char C2S_key[MAX_KEY_LEN]; | |
257 unsigned char S2C_IV[MAX_IV_LEN]; | |
258 unsigned char S2C_key[MAX_KEY_LEN]; | |
259 /* unsigned char key[MAX_KEY_LEN]; */ | |
260 unsigned char *trans_IV, *trans_key, *recv_IV, *recv_key; | |
261 | |
262 hash_state hs; | |
263 unsigned int C2S_keysize, S2C_keysize; | |
264 char mactransletter, macrecvletter; /* Client or server specific */ | |
265 int recv_cipher = 0, trans_cipher = 0; | |
266 | |
267 TRACE(("enter gen_new_keys")) | |
268 /* the dh_K and hash are the start of all hashes, we make use of that */ | |
269 | |
270 sha1_init(&hs); | |
271 sha1_process_mp(&hs, ses.dh_K); | |
272 mp_clear(ses.dh_K); | |
273 m_free(ses.dh_K); | |
274 sha1_process(&hs, ses.hash, SHA1_HASH_SIZE); | |
275 m_burn(ses.hash, SHA1_HASH_SIZE); | |
276 | |
277 if (IS_DROPBEAR_CLIENT) { | |
278 trans_IV = C2S_IV; | |
279 recv_IV = S2C_IV; | |
280 trans_key = C2S_key; | |
281 recv_key = S2C_key; | |
282 C2S_keysize = ses.newkeys->trans_algo_crypt->keysize; | |
283 S2C_keysize = ses.newkeys->recv_algo_crypt->keysize; | |
284 mactransletter = 'E'; | |
285 macrecvletter = 'F'; | |
286 } else { | |
287 trans_IV = S2C_IV; | |
288 recv_IV = C2S_IV; | |
289 trans_key = S2C_key; | |
290 recv_key = C2S_key; | |
291 C2S_keysize = ses.newkeys->recv_algo_crypt->keysize; | |
292 S2C_keysize = ses.newkeys->trans_algo_crypt->keysize; | |
293 mactransletter = 'F'; | |
294 macrecvletter = 'E'; | |
295 } | |
296 | |
297 hashkeys(C2S_IV, SHA1_HASH_SIZE, &hs, 'A'); | |
298 hashkeys(S2C_IV, SHA1_HASH_SIZE, &hs, 'B'); | |
299 hashkeys(C2S_key, C2S_keysize, &hs, 'C'); | |
300 hashkeys(S2C_key, S2C_keysize, &hs, 'D'); | |
301 | |
302 recv_cipher = find_cipher(ses.newkeys->recv_algo_crypt->cipherdesc->name); | |
303 if (recv_cipher < 0) | |
304 dropbear_exit("crypto error"); | |
305 | |
306 if (cbc_start(recv_cipher, recv_IV, recv_key, | |
307 ses.newkeys->recv_algo_crypt->keysize, 0, | |
308 &ses.newkeys->recv_symmetric_struct) != CRYPT_OK) { | |
309 dropbear_exit("crypto error"); | |
310 } | |
311 trans_cipher = find_cipher(ses.newkeys->trans_algo_crypt->cipherdesc->name); | |
312 if (trans_cipher < 0) | |
313 dropbear_exit("crypto error"); | |
314 | |
315 if (cbc_start(trans_cipher, trans_IV, trans_key, | |
316 ses.newkeys->trans_algo_crypt->keysize, 0, | |
317 &ses.newkeys->trans_symmetric_struct) != CRYPT_OK) { | |
318 dropbear_exit("crypto error"); | |
319 } | |
320 | |
321 /* MAC keys */ | |
322 hashkeys(ses.newkeys->transmackey, | |
323 ses.newkeys->trans_algo_mac->keysize, &hs, mactransletter); | |
324 hashkeys(ses.newkeys->recvmackey, | |
325 ses.newkeys->recv_algo_mac->keysize, &hs, macrecvletter); | |
326 | |
327 #ifndef DISABLE_ZLIB | |
328 gen_new_zstreams(); | |
329 #endif | |
330 | |
331 /* Switch over to the new keys */ | |
332 m_burn(ses.keys, sizeof(struct key_context)); | |
333 m_free(ses.keys); | |
334 ses.keys = ses.newkeys; | |
335 ses.newkeys = NULL; | |
336 | |
337 TRACE(("leave gen_new_keys")) | |
338 } | |
339 | |
340 #ifndef DISABLE_ZLIB | |
341 /* Set up new zlib compression streams, close the old ones. Only | |
342 * called from gen_new_keys() */ | |
343 static void gen_new_zstreams() { | |
344 | |
345 /* create new zstreams */ | |
346 if (ses.newkeys->recv_algo_comp == DROPBEAR_COMP_ZLIB) { | |
347 ses.newkeys->recv_zstream = (z_streamp)m_malloc(sizeof(z_stream)); | |
348 ses.newkeys->recv_zstream->zalloc = Z_NULL; | |
349 ses.newkeys->recv_zstream->zfree = Z_NULL; | |
350 | |
351 if (inflateInit(ses.newkeys->recv_zstream) != Z_OK) { | |
352 dropbear_exit("zlib error"); | |
353 } | |
354 } else { | |
355 ses.newkeys->recv_zstream = NULL; | |
356 } | |
357 | |
358 if (ses.newkeys->trans_algo_comp == DROPBEAR_COMP_ZLIB) { | |
359 ses.newkeys->trans_zstream = (z_streamp)m_malloc(sizeof(z_stream)); | |
360 ses.newkeys->trans_zstream->zalloc = Z_NULL; | |
361 ses.newkeys->trans_zstream->zfree = Z_NULL; | |
362 | |
363 if (deflateInit(ses.newkeys->trans_zstream, Z_DEFAULT_COMPRESSION) | |
364 != Z_OK) { | |
365 dropbear_exit("zlib error"); | |
366 } | |
367 } else { | |
368 ses.newkeys->trans_zstream = NULL; | |
369 } | |
370 | |
371 /* clean up old keys */ | |
372 if (ses.keys->recv_zstream != NULL) { | |
373 if (inflateEnd(ses.keys->recv_zstream) == Z_STREAM_ERROR) { | |
374 /* Z_DATA_ERROR is ok, just means that stream isn't ended */ | |
375 dropbear_exit("crypto error"); | |
376 } | |
377 m_free(ses.keys->recv_zstream); | |
378 } | |
379 if (ses.keys->trans_zstream != NULL) { | |
380 if (deflateEnd(ses.keys->trans_zstream) == Z_STREAM_ERROR) { | |
381 /* Z_DATA_ERROR is ok, just means that stream isn't ended */ | |
382 dropbear_exit("crypto error"); | |
383 } | |
384 m_free(ses.keys->trans_zstream); | |
385 } | |
386 } | |
387 #endif | |
388 | |
389 | |
390 /* Executed upon receiving a kexinit message from the client to initiate | |
391 * key exchange. If we haven't already done so, we send the list of our | |
392 * preferred algorithms. The client's requested algorithms are processed, | |
393 * and we calculate the first portion of the key-exchange-hash for used | |
394 * later in the key exchange. No response is sent, as the client should | |
395 * initiate the diffie-hellman key exchange */ | |
396 | |
397 /* Originally from kex.c, generalized for cli/svr mode --mihnea */ | |
398 /* Belongs in common_kex.c where it should be moved after review */ | |
399 void recv_msg_kexinit() { | |
400 | |
401 unsigned int kexhashbuf_len = 0; | |
402 unsigned int remote_ident_len = 0; | |
403 unsigned int local_ident_len = 0; | |
404 | |
405 TRACE(("<- KEXINIT")) | |
406 TRACE(("enter recv_msg_kexinit")) | |
407 | |
408 if (!ses.kexstate.sentkexinit) { | |
409 /* we need to send a kex packet */ | |
410 send_msg_kexinit(); | |
411 TRACE(("continue recv_msg_kexinit: sent kexinit")) | |
412 } | |
413 | |
414 /* start the kex hash */ | |
415 local_ident_len = strlen(LOCAL_IDENT); | |
416 remote_ident_len = strlen((char*)ses.remoteident); | |
417 | |
418 kexhashbuf_len = local_ident_len + remote_ident_len | |
419 + ses.transkexinit->len + ses.payload->len | |
420 + KEXHASHBUF_MAX_INTS; | |
421 | |
422 ses.kexhashbuf = buf_new(kexhashbuf_len); | |
423 | |
424 if (IS_DROPBEAR_CLIENT) { | |
425 | |
426 /* read the peer's choice of algos */ | |
427 read_kex_algos(); | |
428 | |
429 /* V_C, the client's version string (CR and NL excluded) */ | |
430 buf_putstring(ses.kexhashbuf, | |
431 (unsigned char*)LOCAL_IDENT, local_ident_len); | |
432 /* V_S, the server's version string (CR and NL excluded) */ | |
433 buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len); | |
434 | |
435 /* I_C, the payload of the client's SSH_MSG_KEXINIT */ | |
436 buf_putstring(ses.kexhashbuf, | |
437 ses.transkexinit->data, ses.transkexinit->len); | |
438 /* I_S, the payload of the server's SSH_MSG_KEXINIT */ | |
439 buf_setpos(ses.payload, 0); | |
440 buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len); | |
441 | |
442 } else { | |
443 /* SERVER */ | |
444 | |
445 /* read the peer's choice of algos */ | |
446 read_kex_algos(); | |
447 /* V_C, the client's version string (CR and NL excluded) */ | |
448 buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len); | |
449 /* V_S, the server's version string (CR and NL excluded) */ | |
450 buf_putstring(ses.kexhashbuf, | |
451 (unsigned char*)LOCAL_IDENT, local_ident_len); | |
452 | |
453 /* I_C, the payload of the client's SSH_MSG_KEXINIT */ | |
454 buf_setpos(ses.payload, 0); | |
455 buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len); | |
456 | |
457 /* I_S, the payload of the server's SSH_MSG_KEXINIT */ | |
458 buf_putstring(ses.kexhashbuf, | |
459 ses.transkexinit->data, ses.transkexinit->len); | |
460 | |
461 ses.requirenext = SSH_MSG_KEXDH_INIT; | |
462 } | |
463 | |
464 buf_free(ses.transkexinit); | |
465 ses.transkexinit = NULL; | |
466 /* the rest of ses.kexhashbuf will be done after DH exchange */ | |
467 | |
468 ses.kexstate.recvkexinit = 1; | |
469 | |
470 TRACE(("leave recv_msg_kexinit")) | |
471 } | |
472 | |
473 /* Initialises and generate one side of the diffie-hellman key exchange values. | |
474 * See the ietf-secsh-transport draft, section 6, for details */ | |
475 /* dh_pub and dh_priv MUST be already initialised */ | |
476 void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) { | |
477 | |
478 DEF_MP_INT(dh_p); | |
479 DEF_MP_INT(dh_q); | |
480 DEF_MP_INT(dh_g); | |
481 | |
482 TRACE(("enter send_msg_kexdh_reply")) | |
483 | |
484 m_mp_init_multi(&dh_g, &dh_p, &dh_q, NULL); | |
485 | |
486 /* read the prime and generator*/ | |
487 bytes_to_mp(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN); | |
488 | |
489 if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) { | |
490 dropbear_exit("Diffie-Hellman error"); | |
491 } | |
492 | |
493 /* calculate q = (p-1)/2 */ | |
494 /* dh_priv is just a temp var here */ | |
495 if (mp_sub_d(&dh_p, 1, dh_priv) != MP_OKAY) { | |
496 dropbear_exit("Diffie-Hellman error"); | |
497 } | |
498 if (mp_div_2(dh_priv, &dh_q) != MP_OKAY) { | |
499 dropbear_exit("Diffie-Hellman error"); | |
500 } | |
501 | |
502 /* Generate a private portion 0 < dh_priv < dh_q */ | |
503 gen_random_mpint(&dh_q, dh_priv); | |
504 | |
505 /* f = g^y mod p */ | |
506 if (mp_exptmod(&dh_g, dh_priv, &dh_p, dh_pub) != MP_OKAY) { | |
507 dropbear_exit("Diffie-Hellman error"); | |
508 } | |
509 mp_clear_multi(&dh_g, &dh_p, &dh_q, NULL); | |
510 } | |
511 | |
512 /* This function is fairly common between client/server, with some substitution | |
513 * of dh_e/dh_f etc. Hence these arguments: | |
514 * dh_pub_us is 'e' for the client, 'f' for the server. dh_pub_them is | |
515 * vice-versa. dh_priv is the x/y value corresponding to dh_pub_us */ | |
516 void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them, | |
517 sign_key *hostkey) { | |
518 | |
519 mp_int dh_p; | |
520 mp_int *dh_e = NULL, *dh_f = NULL; | |
521 hash_state hs; | |
522 | |
523 /* read the prime and generator*/ | |
524 m_mp_init(&dh_p); | |
525 bytes_to_mp(&dh_p, dh_p_val, DH_P_LEN); | |
526 | |
527 /* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */ | |
528 if (mp_cmp(dh_pub_them, &dh_p) != MP_LT | |
529 || mp_cmp_d(dh_pub_them, 0) != MP_GT) { | |
530 dropbear_exit("Diffie-Hellman error"); | |
531 } | |
532 | |
533 /* K = e^y mod p = f^x mod p */ | |
534 ses.dh_K = (mp_int*)m_malloc(sizeof(mp_int)); | |
535 m_mp_init(ses.dh_K); | |
536 if (mp_exptmod(dh_pub_them, dh_priv, &dh_p, ses.dh_K) != MP_OKAY) { | |
537 dropbear_exit("Diffie-Hellman error"); | |
538 } | |
539 | |
540 /* clear no longer needed vars */ | |
541 mp_clear_multi(&dh_p, NULL); | |
542 | |
543 /* From here on, the code needs to work with the _same_ vars on each side, | |
544 * not vice-versaing for client/server */ | |
545 if (IS_DROPBEAR_CLIENT) { | |
546 dh_e = dh_pub_us; | |
547 dh_f = dh_pub_them; | |
548 } else { | |
549 dh_e = dh_pub_them; | |
550 dh_f = dh_pub_us; | |
551 } | |
552 | |
553 /* Create the remainder of the hash buffer, to generate the exchange hash */ | |
554 /* K_S, the host key */ | |
555 buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey); | |
556 /* e, exchange value sent by the client */ | |
557 buf_putmpint(ses.kexhashbuf, dh_e); | |
558 /* f, exchange value sent by the server */ | |
559 buf_putmpint(ses.kexhashbuf, dh_f); | |
560 /* K, the shared secret */ | |
561 buf_putmpint(ses.kexhashbuf, ses.dh_K); | |
562 | |
563 /* calculate the hash H to sign */ | |
564 sha1_init(&hs); | |
565 buf_setpos(ses.kexhashbuf, 0); | |
566 sha1_process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len), | |
567 ses.kexhashbuf->len); | |
568 sha1_done(&hs, ses.hash); | |
569 | |
570 buf_burn(ses.kexhashbuf); | |
571 buf_free(ses.kexhashbuf); | |
572 ses.kexhashbuf = NULL; | |
573 | |
574 /* first time around, we set the session_id to H */ | |
575 if (ses.session_id == NULL) { | |
576 /* create the session_id, this never needs freeing */ | |
577 ses.session_id = (unsigned char*)m_malloc(SHA1_HASH_SIZE); | |
578 memcpy(ses.session_id, ses.hash, SHA1_HASH_SIZE); | |
579 } | |
580 } | |
581 | |
582 /* read the other side's algo list. buf_match_algo is a callback to match | |
583 * algos for the client or server. */ | |
584 static void read_kex_algos() { | |
585 | |
586 /* for asymmetry */ | |
587 algo_type * c2s_hash_algo = NULL; | |
588 algo_type * s2c_hash_algo = NULL; | |
589 algo_type * c2s_cipher_algo = NULL; | |
590 algo_type * s2c_cipher_algo = NULL; | |
591 algo_type * c2s_comp_algo = NULL; | |
592 algo_type * s2c_comp_algo = NULL; | |
593 /* the generic one */ | |
594 algo_type * algo = NULL; | |
595 | |
596 /* which algo couldn't match */ | |
597 char * erralgo = NULL; | |
598 | |
599 int goodguess = 0; | |
600 int allgood = 1; /* we AND this with each goodguess and see if its still | |
601 true after */ | |
602 | |
603 buf_incrpos(ses.payload, 16); /* start after the cookie */ | |
604 | |
605 ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context)); | |
606 | |
607 /* kex_algorithms */ | |
608 algo = ses.buf_match_algo(ses.payload, sshkex, &goodguess); | |
609 allgood &= goodguess; | |
610 if (algo == NULL) { | |
611 erralgo = "kex"; | |
612 goto error; | |
613 } | |
614 TRACE(("kex algo %s", algo->name)) | |
615 ses.newkeys->algo_kex = algo->val; | |
616 | |
617 /* server_host_key_algorithms */ | |
618 algo = ses.buf_match_algo(ses.payload, sshhostkey, &goodguess); | |
619 allgood &= goodguess; | |
620 if (algo == NULL) { | |
621 erralgo = "hostkey"; | |
622 goto error; | |
623 } | |
624 TRACE(("hostkey algo %s", algo->name)) | |
625 ses.newkeys->algo_hostkey = algo->val; | |
626 | |
627 /* encryption_algorithms_client_to_server */ | |
628 c2s_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess); | |
629 if (c2s_cipher_algo == NULL) { | |
630 erralgo = "enc c->s"; | |
631 goto error; | |
632 } | |
633 TRACE(("enc c2s is %s", c2s_cipher_algo->name)) | |
634 | |
635 /* encryption_algorithms_server_to_client */ | |
636 s2c_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess); | |
637 if (s2c_cipher_algo == NULL) { | |
638 erralgo = "enc s->c"; | |
639 goto error; | |
640 } | |
641 TRACE(("enc s2c is %s", s2c_cipher_algo->name)) | |
642 | |
643 /* mac_algorithms_client_to_server */ | |
644 c2s_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess); | |
645 if (c2s_hash_algo == NULL) { | |
646 erralgo = "mac c->s"; | |
647 goto error; | |
648 } | |
649 TRACE(("hash c2s is %s", c2s_hash_algo->name)) | |
650 | |
651 /* mac_algorithms_server_to_client */ | |
652 s2c_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess); | |
653 if (s2c_hash_algo == NULL) { | |
654 erralgo = "mac s->c"; | |
655 goto error; | |
656 } | |
657 TRACE(("hash s2c is %s", s2c_hash_algo->name)) | |
658 | |
659 /* compression_algorithms_client_to_server */ | |
660 c2s_comp_algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess); | |
661 if (c2s_comp_algo == NULL) { | |
662 erralgo = "comp c->s"; | |
663 goto error; | |
664 } | |
665 TRACE(("hash c2s is %s", c2s_comp_algo->name)) | |
666 | |
667 /* compression_algorithms_server_to_client */ | |
668 s2c_comp_algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess); | |
669 if (s2c_comp_algo == NULL) { | |
670 erralgo = "comp s->c"; | |
671 goto error; | |
672 } | |
673 TRACE(("hash s2c is %s", s2c_comp_algo->name)) | |
674 | |
675 /* languages_client_to_server */ | |
676 buf_eatstring(ses.payload); | |
677 | |
678 /* languages_server_to_client */ | |
679 buf_eatstring(ses.payload); | |
680 | |
681 /* first_kex_packet_follows */ | |
682 if (buf_getbool(ses.payload)) { | |
683 ses.kexstate.firstfollows = 1; | |
684 /* if the guess wasn't good, we ignore the packet sent */ | |
685 if (!allgood) { | |
686 ses.ignorenext = 1; | |
687 } | |
688 } | |
689 | |
690 /* Handle the asymmetry */ | |
691 if (IS_DROPBEAR_CLIENT) { | |
692 ses.newkeys->recv_algo_crypt = | |
693 (struct dropbear_cipher*)s2c_cipher_algo->data; | |
694 ses.newkeys->trans_algo_crypt = | |
695 (struct dropbear_cipher*)c2s_cipher_algo->data; | |
696 ses.newkeys->recv_algo_mac = | |
697 (struct dropbear_hash*)s2c_hash_algo->data; | |
698 ses.newkeys->trans_algo_mac = | |
699 (struct dropbear_hash*)c2s_hash_algo->data; | |
700 ses.newkeys->recv_algo_comp = s2c_comp_algo->val; | |
701 ses.newkeys->trans_algo_comp = c2s_comp_algo->val; | |
702 } else { | |
703 /* SERVER */ | |
704 ses.newkeys->recv_algo_crypt = | |
705 (struct dropbear_cipher*)c2s_cipher_algo->data; | |
706 ses.newkeys->trans_algo_crypt = | |
707 (struct dropbear_cipher*)s2c_cipher_algo->data; | |
708 ses.newkeys->recv_algo_mac = | |
709 (struct dropbear_hash*)c2s_hash_algo->data; | |
710 ses.newkeys->trans_algo_mac = | |
711 (struct dropbear_hash*)s2c_hash_algo->data; | |
712 ses.newkeys->recv_algo_comp = c2s_comp_algo->val; | |
713 ses.newkeys->trans_algo_comp = s2c_comp_algo->val; | |
714 } | |
715 | |
716 /* reserved for future extensions */ | |
717 buf_getint(ses.payload); | |
718 return; | |
719 | |
720 error: | |
721 dropbear_exit("no matching algo %s", erralgo); | |
722 } |