/src/dropbear/src/common-kex.c
Line | Count | Source |
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 "dbrandom.h" |
36 | | #include "runopts.h" |
37 | | |
38 | | static void kexinitialise(void); |
39 | | static void gen_new_keys(void); |
40 | | #ifndef DISABLE_ZLIB |
41 | | static void gen_new_zstream_recv(void); |
42 | | static void gen_new_zstream_trans(void); |
43 | | #endif |
44 | | static void read_kex_algos(void); |
45 | | /* helper function for gen_new_keys */ |
46 | | static void hashkeys(unsigned char *out, unsigned int outlen, |
47 | | const hash_state * hs, const unsigned char X); |
48 | | |
49 | | |
50 | | /* Send our list of algorithms we can use */ |
51 | 0 | void send_msg_kexinit() { |
52 | |
|
53 | 0 | CHECKCLEARTOWRITE(); |
54 | 0 | buf_putbyte(ses.writepayload, SSH_MSG_KEXINIT); |
55 | | |
56 | | /* cookie */ |
57 | 0 | genrandom(buf_getwriteptr(ses.writepayload, 16), 16); |
58 | 0 | buf_incrwritepos(ses.writepayload, 16); |
59 | | |
60 | | /* kex algos */ |
61 | 0 | buf_put_algolist(ses.writepayload, sshkex); |
62 | | |
63 | | /* server_host_key_algorithms */ |
64 | 0 | buf_put_algolist(ses.writepayload, sigalgs); |
65 | | |
66 | | /* encryption_algorithms_client_to_server */ |
67 | 0 | buf_put_algolist(ses.writepayload, sshciphers); |
68 | | |
69 | | /* encryption_algorithms_server_to_client */ |
70 | 0 | buf_put_algolist(ses.writepayload, sshciphers); |
71 | | |
72 | | /* mac_algorithms_client_to_server */ |
73 | 0 | buf_put_algolist(ses.writepayload, sshhashes); |
74 | | |
75 | | /* mac_algorithms_server_to_client */ |
76 | 0 | buf_put_algolist(ses.writepayload, sshhashes); |
77 | | |
78 | | |
79 | | /* compression_algorithms_client_to_server */ |
80 | 0 | buf_put_algolist(ses.writepayload, ses.compress_algos_c2s); |
81 | | |
82 | | /* compression_algorithms_server_to_client */ |
83 | 0 | buf_put_algolist(ses.writepayload, ses.compress_algos_s2c); |
84 | | |
85 | | /* languages_client_to_server */ |
86 | 0 | buf_putstring(ses.writepayload, "", 0); |
87 | | |
88 | | /* languages_server_to_client */ |
89 | 0 | buf_putstring(ses.writepayload, "", 0); |
90 | | |
91 | | /* first_kex_packet_follows */ |
92 | 0 | buf_putbyte(ses.writepayload, (ses.send_kex_first_guess != NULL)); |
93 | | |
94 | | /* reserved unit32 */ |
95 | 0 | buf_putint(ses.writepayload, 0); |
96 | | |
97 | | /* set up transmitted kex packet buffer for hashing. |
98 | | * This is freed after the end of the kex */ |
99 | 0 | ses.transkexinit = buf_newcopy(ses.writepayload); |
100 | |
|
101 | 0 | encrypt_packet(); |
102 | 0 | ses.dataallowed = 0; /* don't send other packets during kex */ |
103 | |
|
104 | 0 | ses.kexstate.sentkexinit = 1; |
105 | |
|
106 | 0 | ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context)); |
107 | |
|
108 | 0 | if (ses.send_kex_first_guess) { |
109 | 0 | ses.newkeys->algo_kex = first_usable_algo(sshkex)->data; |
110 | 0 | ses.newkeys->algo_signature = first_usable_algo(sigalgs)->val; |
111 | 0 | ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature); |
112 | 0 | ses.send_kex_first_guess(); |
113 | 0 | } |
114 | |
|
115 | 0 | TRACE(("DATAALLOWED=0")) |
116 | 0 | TRACE(("-> KEXINIT")) |
117 | |
|
118 | 0 | } |
119 | | |
120 | 0 | static void switch_keys() { |
121 | 0 | TRACE2(("enter switch_keys")) |
122 | 0 | if (!(ses.kexstate.sentkexinit && ses.kexstate.recvkexinit)) { |
123 | 0 | dropbear_exit("Unexpected newkeys message"); |
124 | 0 | } |
125 | | |
126 | 0 | if (!ses.keys) { |
127 | 0 | ses.keys = m_malloc(sizeof(*ses.newkeys)); |
128 | 0 | } |
129 | 0 | if (ses.kexstate.recvnewkeys && ses.newkeys->recv.valid) { |
130 | 0 | TRACE(("switch_keys recv")) |
131 | | #ifndef DISABLE_ZLIB |
132 | | gen_new_zstream_recv(); |
133 | | #endif |
134 | 0 | ses.keys->recv = ses.newkeys->recv; |
135 | 0 | m_burn(&ses.newkeys->recv, sizeof(ses.newkeys->recv)); |
136 | 0 | ses.newkeys->recv.valid = 0; |
137 | 0 | } |
138 | 0 | if (ses.kexstate.sentnewkeys && ses.newkeys->trans.valid) { |
139 | 0 | TRACE(("switch_keys trans")) |
140 | | #ifndef DISABLE_ZLIB |
141 | | gen_new_zstream_trans(); |
142 | | #endif |
143 | 0 | ses.keys->trans = ses.newkeys->trans; |
144 | 0 | m_burn(&ses.newkeys->trans, sizeof(ses.newkeys->trans)); |
145 | 0 | ses.newkeys->trans.valid = 0; |
146 | 0 | } |
147 | 0 | if (ses.kexstate.sentnewkeys && ses.kexstate.recvnewkeys) |
148 | 0 | { |
149 | 0 | TRACE(("switch_keys done")) |
150 | 0 | ses.keys->algo_kex = ses.newkeys->algo_kex; |
151 | 0 | ses.keys->algo_hostkey = ses.newkeys->algo_hostkey; |
152 | 0 | ses.keys->algo_signature = ses.newkeys->algo_signature; |
153 | 0 | m_free(ses.newkeys); |
154 | 0 | ses.newkeys = NULL; |
155 | 0 | kexinitialise(); |
156 | 0 | } |
157 | 0 | TRACE2(("leave switch_keys")) |
158 | 0 | } |
159 | | |
160 | | /* Bring new keys into use after a key exchange, and let the client know*/ |
161 | 0 | void send_msg_newkeys() { |
162 | |
|
163 | 0 | TRACE(("enter send_msg_newkeys")) |
164 | | |
165 | | /* generate the kexinit request */ |
166 | 0 | CHECKCLEARTOWRITE(); |
167 | 0 | buf_putbyte(ses.writepayload, SSH_MSG_NEWKEYS); |
168 | 0 | encrypt_packet(); |
169 | | |
170 | | |
171 | | /* set up our state */ |
172 | 0 | ses.kexstate.sentnewkeys = 1; |
173 | 0 | if (ses.kexstate.donefirstkex) { |
174 | 0 | ses.kexstate.donesecondkex = 1; |
175 | 0 | } |
176 | 0 | ses.kexstate.donefirstkex = 1; |
177 | 0 | ses.dataallowed = 1; /* we can send other packets again now */ |
178 | 0 | gen_new_keys(); |
179 | 0 | switch_keys(); |
180 | |
|
181 | 0 | if (ses.kexstate.strict_kex) { |
182 | 0 | ses.transseq = 0; |
183 | 0 | } |
184 | |
|
185 | 0 | TRACE(("leave send_msg_newkeys")) |
186 | 0 | } |
187 | | |
188 | | /* Bring the new keys into use after a key exchange */ |
189 | 0 | void recv_msg_newkeys() { |
190 | |
|
191 | 0 | TRACE(("enter recv_msg_newkeys")) |
192 | |
|
193 | 0 | ses.kexstate.recvnewkeys = 1; |
194 | 0 | switch_keys(); |
195 | |
|
196 | 0 | if (ses.kexstate.strict_kex) { |
197 | 0 | ses.recvseq = 0; |
198 | 0 | } |
199 | 0 | ses.kexstate.recvfirstnewkeys = 1; |
200 | |
|
201 | 0 | TRACE(("leave recv_msg_newkeys")) |
202 | 0 | } |
203 | | |
204 | 0 | static void kex_setup_compress(void) { |
205 | 0 | #ifdef DISABLE_ZLIB |
206 | 0 | ses.compress_algos_c2s = ssh_nocompress; |
207 | 0 | ses.compress_algos_s2c = ssh_nocompress; |
208 | | #else |
209 | | |
210 | | if (!opts.compression) { |
211 | | ses.compress_algos_c2s = ssh_nocompress; |
212 | | ses.compress_algos_s2c = ssh_nocompress; |
213 | | return; |
214 | | } |
215 | | |
216 | | if (IS_DROPBEAR_CLIENT) { |
217 | | /* TODO: should c2s in dbclient be disabled? |
218 | | * Current Dropbear server disables it. Disabling it also |
219 | | * lets DROPBEAR_CLI_IMMEDIATE_AUTH work (see comment there) */ |
220 | | ses.compress_algos_c2s = ssh_compress; |
221 | | ses.compress_algos_s2c = ssh_compress; |
222 | | } else { |
223 | | ses.compress_algos_c2s = ssh_nocompress; |
224 | | ses.compress_algos_s2c = ssh_compress; |
225 | | } |
226 | | #endif |
227 | 0 | } |
228 | | |
229 | | /* Set up the kex for the first time */ |
230 | 0 | void kexfirstinitialise() { |
231 | 0 | kex_setup_compress(); |
232 | 0 | kexinitialise(); |
233 | 0 | } |
234 | | |
235 | | /* Reset the kex state, ready for a new negotiation */ |
236 | 0 | static void kexinitialise() { |
237 | |
|
238 | 0 | TRACE(("kexinitialise()")) |
239 | | |
240 | | /* sent/recv'd MSG_KEXINIT */ |
241 | 0 | ses.kexstate.sentkexinit = 0; |
242 | 0 | ses.kexstate.recvkexinit = 0; |
243 | | |
244 | | /* sent/recv'd MSG_NEWKEYS */ |
245 | 0 | ses.kexstate.recvnewkeys = 0; |
246 | 0 | ses.kexstate.sentnewkeys = 0; |
247 | | |
248 | | /* first_packet_follows */ |
249 | 0 | ses.kexstate.them_firstfollows = 0; |
250 | |
|
251 | 0 | ses.kexstate.datatrans = 0; |
252 | 0 | ses.kexstate.datarecv = 0; |
253 | |
|
254 | 0 | ses.kexstate.our_first_follows_matches = 0; |
255 | |
|
256 | 0 | ses.kexstate.lastkextime = monotonic_now(); |
257 | |
|
258 | 0 | } |
259 | | |
260 | | /* Helper function for gen_new_keys, creates a hash. It makes a copy of the |
261 | | * already initialised hash_state hs, which should already have processed |
262 | | * the dh_K and hash, since these are common. X is the letter 'A', 'B' etc. |
263 | | * out must have at least min(hash_size, outlen) bytes allocated. |
264 | | * |
265 | | * See Section 7.2 of rfc4253 (ssh transport) for details */ |
266 | | static void hashkeys(unsigned char *out, unsigned int outlen, |
267 | 0 | const hash_state * hs, const unsigned char X) { |
268 | |
|
269 | 0 | const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc; |
270 | 0 | hash_state hs2; |
271 | 0 | unsigned int offset; |
272 | 0 | unsigned char tmpout[MAX_HASH_SIZE]; |
273 | |
|
274 | 0 | memcpy(&hs2, hs, sizeof(hash_state)); |
275 | 0 | hash_desc->process(&hs2, &X, 1); |
276 | 0 | hash_desc->process(&hs2, ses.session_id->data, ses.session_id->len); |
277 | 0 | hash_desc->done(&hs2, tmpout); |
278 | 0 | memcpy(out, tmpout, MIN(hash_desc->hashsize, outlen)); |
279 | 0 | for (offset = hash_desc->hashsize; |
280 | 0 | offset < outlen; |
281 | 0 | offset += hash_desc->hashsize) |
282 | 0 | { |
283 | | /* need to extend */ |
284 | 0 | memcpy(&hs2, hs, sizeof(hash_state)); |
285 | 0 | hash_desc->process(&hs2, out, offset); |
286 | 0 | hash_desc->done(&hs2, tmpout); |
287 | 0 | memcpy(&out[offset], tmpout, MIN(outlen - offset, hash_desc->hashsize)); |
288 | 0 | } |
289 | 0 | m_burn(&hs2, sizeof(hash_state)); |
290 | 0 | } |
291 | | |
292 | | /* Generate the actual encryption/integrity keys, using the results of the |
293 | | * key exchange, as specified in section 7.2 of the transport rfc 4253. |
294 | | * This occurs after the DH key-exchange. |
295 | | * |
296 | | * ses.newkeys is the new set of keys which are generated, these are only |
297 | | * taken into use after both sides have sent a newkeys message */ |
298 | | |
299 | 0 | static void gen_new_keys() { |
300 | |
|
301 | 0 | unsigned char C2S_IV[MAX_IV_LEN]; |
302 | 0 | unsigned char C2S_key[MAX_KEY_LEN]; |
303 | 0 | unsigned char S2C_IV[MAX_IV_LEN]; |
304 | 0 | unsigned char S2C_key[MAX_KEY_LEN]; |
305 | | /* unsigned char key[MAX_KEY_LEN]; */ |
306 | 0 | unsigned char *trans_IV, *trans_key, *recv_IV, *recv_key; |
307 | |
|
308 | 0 | hash_state hs; |
309 | 0 | const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc; |
310 | 0 | char mactransletter, macrecvletter; /* Client or server specific */ |
311 | |
|
312 | 0 | TRACE(("enter gen_new_keys")) |
313 | | /* the dh_K and hash are the start of all hashes, we make use of that */ |
314 | |
|
315 | 0 | hash_desc->init(&hs); |
316 | 0 | if (ses.dh_K) { |
317 | 0 | hash_process_mp(hash_desc, &hs, ses.dh_K); |
318 | 0 | mp_clear(ses.dh_K); |
319 | 0 | m_free(ses.dh_K); |
320 | 0 | } |
321 | 0 | if (ses.dh_K_bytes) { |
322 | 0 | hash_desc->process(&hs, ses.dh_K_bytes->data, ses.dh_K_bytes->len); |
323 | 0 | buf_burn_free(ses.dh_K_bytes); |
324 | 0 | ses.dh_K_bytes = NULL; |
325 | 0 | } |
326 | 0 | hash_desc->process(&hs, ses.hash->data, ses.hash->len); |
327 | 0 | buf_burn_free(ses.hash); |
328 | 0 | ses.hash = NULL; |
329 | |
|
330 | 0 | if (IS_DROPBEAR_CLIENT) { |
331 | 0 | trans_IV = C2S_IV; |
332 | 0 | recv_IV = S2C_IV; |
333 | 0 | trans_key = C2S_key; |
334 | 0 | recv_key = S2C_key; |
335 | 0 | mactransletter = 'E'; |
336 | 0 | macrecvletter = 'F'; |
337 | 0 | } else { |
338 | 0 | trans_IV = S2C_IV; |
339 | 0 | recv_IV = C2S_IV; |
340 | 0 | trans_key = S2C_key; |
341 | 0 | recv_key = C2S_key; |
342 | 0 | mactransletter = 'F'; |
343 | 0 | macrecvletter = 'E'; |
344 | 0 | } |
345 | |
|
346 | 0 | hashkeys(C2S_IV, sizeof(C2S_IV), &hs, 'A'); |
347 | 0 | hashkeys(S2C_IV, sizeof(S2C_IV), &hs, 'B'); |
348 | 0 | hashkeys(C2S_key, sizeof(C2S_key), &hs, 'C'); |
349 | 0 | hashkeys(S2C_key, sizeof(S2C_key), &hs, 'D'); |
350 | |
|
351 | 0 | if (ses.newkeys->recv.algo_crypt->cipherdesc != NULL) { |
352 | 0 | int recv_cipher = -1; |
353 | 0 | if (ses.newkeys->recv.algo_crypt->cipherdesc->name != NULL) { |
354 | 0 | recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name); |
355 | 0 | if (recv_cipher < 0) { |
356 | 0 | dropbear_exit("Crypto error"); |
357 | 0 | } |
358 | 0 | } |
359 | 0 | if (ses.newkeys->recv.crypt_mode->start(recv_cipher, |
360 | 0 | recv_IV, recv_key, |
361 | 0 | ses.newkeys->recv.algo_crypt->keysize, 0, |
362 | 0 | &ses.newkeys->recv.cipher_state) != CRYPT_OK) { |
363 | 0 | dropbear_exit("Crypto error"); |
364 | 0 | } |
365 | 0 | } |
366 | | |
367 | 0 | if (ses.newkeys->trans.algo_crypt->cipherdesc != NULL) { |
368 | 0 | int trans_cipher = -1; |
369 | 0 | if (ses.newkeys->trans.algo_crypt->cipherdesc->name != NULL) { |
370 | 0 | trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name); |
371 | 0 | if (trans_cipher < 0) { |
372 | 0 | dropbear_exit("Crypto error"); |
373 | 0 | } |
374 | 0 | } |
375 | 0 | if (ses.newkeys->trans.crypt_mode->start(trans_cipher, |
376 | 0 | trans_IV, trans_key, |
377 | 0 | ses.newkeys->trans.algo_crypt->keysize, 0, |
378 | 0 | &ses.newkeys->trans.cipher_state) != CRYPT_OK) { |
379 | 0 | dropbear_exit("Crypto error"); |
380 | 0 | } |
381 | 0 | } |
382 | | |
383 | 0 | if (ses.newkeys->trans.algo_mac->hash_desc != NULL) { |
384 | 0 | hashkeys(ses.newkeys->trans.mackey, |
385 | 0 | ses.newkeys->trans.algo_mac->keysize, &hs, mactransletter); |
386 | 0 | ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hash_desc->name); |
387 | 0 | } |
388 | |
|
389 | 0 | if (ses.newkeys->recv.algo_mac->hash_desc != NULL) { |
390 | 0 | hashkeys(ses.newkeys->recv.mackey, |
391 | 0 | ses.newkeys->recv.algo_mac->keysize, &hs, macrecvletter); |
392 | 0 | ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hash_desc->name); |
393 | 0 | } |
394 | | |
395 | | /* Ready to switch over */ |
396 | 0 | ses.newkeys->trans.valid = 1; |
397 | 0 | ses.newkeys->recv.valid = 1; |
398 | |
|
399 | 0 | m_burn(C2S_IV, sizeof(C2S_IV)); |
400 | 0 | m_burn(C2S_key, sizeof(C2S_key)); |
401 | 0 | m_burn(S2C_IV, sizeof(S2C_IV)); |
402 | 0 | m_burn(S2C_key, sizeof(S2C_key)); |
403 | 0 | m_burn(&hs, sizeof(hash_state)); |
404 | |
|
405 | 0 | TRACE(("leave gen_new_keys")) |
406 | 0 | } |
407 | | |
408 | | #ifndef DISABLE_ZLIB |
409 | | |
410 | | int is_compress_trans() { |
411 | | return ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB |
412 | | || (ses.authstate.authdone |
413 | | && ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY); |
414 | | } |
415 | | |
416 | | int is_compress_recv() { |
417 | | return ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB |
418 | | || (ses.authstate.authdone |
419 | | && ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY); |
420 | | } |
421 | | |
422 | | static void* dropbear_zalloc(void* UNUSED(opaque), uInt items, uInt size) { |
423 | | return m_calloc(items, size); |
424 | | } |
425 | | |
426 | | static void dropbear_zfree(void* UNUSED(opaque), void* ptr) { |
427 | | m_free(ptr); |
428 | | } |
429 | | |
430 | | /* Set up new zlib compression streams, close the old ones. Only |
431 | | * called from gen_new_keys() */ |
432 | | static void gen_new_zstream_recv() { |
433 | | |
434 | | /* create new zstreams */ |
435 | | if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB |
436 | | || ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) { |
437 | | ses.newkeys->recv.zstream = (z_streamp)m_malloc(sizeof(z_stream)); |
438 | | ses.newkeys->recv.zstream->zalloc = dropbear_zalloc; |
439 | | ses.newkeys->recv.zstream->zfree = dropbear_zfree; |
440 | | |
441 | | if (inflateInit(ses.newkeys->recv.zstream) != Z_OK) { |
442 | | dropbear_exit("zlib error"); |
443 | | } |
444 | | } else { |
445 | | ses.newkeys->recv.zstream = NULL; |
446 | | } |
447 | | /* clean up old keys */ |
448 | | if (ses.keys->recv.zstream != NULL) { |
449 | | if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) { |
450 | | /* Z_DATA_ERROR is ok, just means that stream isn't ended */ |
451 | | dropbear_exit("Crypto error"); |
452 | | } |
453 | | m_free(ses.keys->recv.zstream); |
454 | | } |
455 | | } |
456 | | |
457 | | static void gen_new_zstream_trans() { |
458 | | |
459 | | if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB |
460 | | || ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) { |
461 | | ses.newkeys->trans.zstream = (z_streamp)m_malloc(sizeof(z_stream)); |
462 | | ses.newkeys->trans.zstream->zalloc = dropbear_zalloc; |
463 | | ses.newkeys->trans.zstream->zfree = dropbear_zfree; |
464 | | |
465 | | if (deflateInit2(ses.newkeys->trans.zstream, Z_DEFAULT_COMPRESSION, |
466 | | Z_DEFLATED, DROPBEAR_ZLIB_WINDOW_BITS, |
467 | | DROPBEAR_ZLIB_MEM_LEVEL, Z_DEFAULT_STRATEGY) |
468 | | != Z_OK) { |
469 | | dropbear_exit("zlib error"); |
470 | | } |
471 | | } else { |
472 | | ses.newkeys->trans.zstream = NULL; |
473 | | } |
474 | | |
475 | | if (ses.keys->trans.zstream != NULL) { |
476 | | if (deflateEnd(ses.keys->trans.zstream) == Z_STREAM_ERROR) { |
477 | | /* Z_DATA_ERROR is ok, just means that stream isn't ended */ |
478 | | dropbear_exit("Crypto error"); |
479 | | } |
480 | | m_free(ses.keys->trans.zstream); |
481 | | } |
482 | | } |
483 | | #endif /* DISABLE_ZLIB */ |
484 | | |
485 | | |
486 | | /* Executed upon receiving a kexinit message from the client to initiate |
487 | | * key exchange. If we haven't already done so, we send the list of our |
488 | | * preferred algorithms. The client's requested algorithms are processed, |
489 | | * and we calculate the first portion of the key-exchange-hash for used |
490 | | * later in the key exchange. No response is sent, as the client should |
491 | | * initiate the diffie-hellman key exchange */ |
492 | 0 | void recv_msg_kexinit() { |
493 | | |
494 | 0 | unsigned int kexhashbuf_len = 0; |
495 | 0 | unsigned int remote_ident_len = 0; |
496 | 0 | unsigned int local_ident_len = 0; |
497 | |
|
498 | 0 | TRACE(("<- KEXINIT")) |
499 | 0 | TRACE(("enter recv_msg_kexinit")) |
500 | | |
501 | 0 | if (!ses.kexstate.sentkexinit) { |
502 | | /* we need to send a kex packet */ |
503 | 0 | send_msg_kexinit(); |
504 | 0 | TRACE(("continue recv_msg_kexinit: sent kexinit")) |
505 | 0 | } |
506 | | |
507 | | /* "Once a party has sent a SSH_MSG_KEXINIT message ... |
508 | | further SSH_MSG_KEXINIT messages MUST NOT be sent" */ |
509 | 0 | if (ses.kexstate.recvkexinit) { |
510 | 0 | dropbear_exit("Unexpected KEXINIT"); |
511 | 0 | } |
512 | | |
513 | | /* start the kex hash */ |
514 | 0 | local_ident_len = strlen(LOCAL_IDENT); |
515 | 0 | remote_ident_len = strlen(ses.remoteident); |
516 | |
|
517 | 0 | kexhashbuf_len = local_ident_len + remote_ident_len |
518 | 0 | + ses.transkexinit->len + ses.payload->len |
519 | 0 | + KEXHASHBUF_MAX_INTS; |
520 | |
|
521 | 0 | ses.kexhashbuf = buf_new(kexhashbuf_len); |
522 | |
|
523 | 0 | if (IS_DROPBEAR_CLIENT) { |
524 | | |
525 | | /* read the peer's choice of algos */ |
526 | 0 | read_kex_algos(); |
527 | | |
528 | | /* V_C, the client's version string (CR and NL excluded) */ |
529 | 0 | buf_putstring(ses.kexhashbuf, LOCAL_IDENT, local_ident_len); |
530 | | /* V_S, the server's version string (CR and NL excluded) */ |
531 | 0 | buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len); |
532 | | |
533 | | /* I_C, the payload of the client's SSH_MSG_KEXINIT */ |
534 | 0 | buf_putstring(ses.kexhashbuf, |
535 | 0 | (const char*)ses.transkexinit->data, ses.transkexinit->len); |
536 | | /* I_S, the payload of the server's SSH_MSG_KEXINIT */ |
537 | 0 | buf_setpos(ses.payload, ses.payload_beginning); |
538 | 0 | buf_putstring(ses.kexhashbuf, |
539 | 0 | (const char*)buf_getptr(ses.payload, ses.payload->len-ses.payload->pos), |
540 | 0 | ses.payload->len-ses.payload->pos); |
541 | 0 | ses.requirenext = SSH_MSG_KEXDH_REPLY; |
542 | 0 | } else { |
543 | | /* SERVER */ |
544 | | |
545 | | /* read the peer's choice of algos */ |
546 | 0 | read_kex_algos(); |
547 | | /* V_C, the client's version string (CR and NL excluded) */ |
548 | 0 | buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len); |
549 | | /* V_S, the server's version string (CR and NL excluded) */ |
550 | 0 | buf_putstring(ses.kexhashbuf, LOCAL_IDENT, local_ident_len); |
551 | | |
552 | | /* I_C, the payload of the client's SSH_MSG_KEXINIT */ |
553 | 0 | buf_setpos(ses.payload, ses.payload_beginning); |
554 | 0 | buf_putstring(ses.kexhashbuf, |
555 | 0 | (const char*)buf_getptr(ses.payload, ses.payload->len-ses.payload->pos), |
556 | 0 | ses.payload->len-ses.payload->pos); |
557 | | |
558 | | /* I_S, the payload of the server's SSH_MSG_KEXINIT */ |
559 | 0 | buf_putstring(ses.kexhashbuf, |
560 | 0 | (const char*)ses.transkexinit->data, ses.transkexinit->len); |
561 | |
|
562 | 0 | ses.requirenext = SSH_MSG_KEXDH_INIT; |
563 | 0 | } |
564 | |
|
565 | 0 | buf_free(ses.transkexinit); |
566 | 0 | ses.transkexinit = NULL; |
567 | | /* the rest of ses.kexhashbuf will be done after DH exchange */ |
568 | |
|
569 | 0 | ses.kexstate.recvkexinit = 1; |
570 | |
|
571 | 0 | if (ses.kexstate.strict_kex && !ses.kexstate.donefirstkex && ses.recvseq != 1) { |
572 | 0 | dropbear_exit("First packet wasn't kexinit"); |
573 | 0 | } |
574 | |
|
575 | 0 | TRACE(("leave recv_msg_kexinit")) |
576 | 0 | } |
577 | | |
578 | | |
579 | 206 | void finish_kexhashbuf(void) { |
580 | 206 | hash_state hs; |
581 | 206 | const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc; |
582 | | |
583 | 206 | hash_desc->init(&hs); |
584 | 206 | buf_setpos(ses.kexhashbuf, 0); |
585 | 206 | hash_desc->process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len), |
586 | 206 | ses.kexhashbuf->len); |
587 | 206 | ses.hash = buf_new(hash_desc->hashsize); |
588 | 206 | hash_desc->done(&hs, buf_getwriteptr(ses.hash, hash_desc->hashsize)); |
589 | 206 | buf_setlen(ses.hash, hash_desc->hashsize); |
590 | | |
591 | | #if defined(DEBUG_KEXHASH) && DEBUG_TRACE |
592 | | if (!debug_trace) { |
593 | | printhex("kexhashbuf", ses.kexhashbuf->data, ses.kexhashbuf->len); |
594 | | printhex("kexhash", ses.hash->data, ses.hash->len); |
595 | | } |
596 | | #endif |
597 | | |
598 | 206 | buf_burn_free(ses.kexhashbuf); |
599 | 206 | m_burn(&hs, sizeof(hash_state)); |
600 | 206 | ses.kexhashbuf = NULL; |
601 | | |
602 | | /* first time around, we set the session_id to H */ |
603 | 206 | if (ses.session_id == NULL) { |
604 | | /* create the session_id, this never needs freeing */ |
605 | 206 | ses.session_id = buf_newcopy(ses.hash); |
606 | 206 | } |
607 | 206 | } |
608 | | |
609 | | /* read the other side's algo list. buf_match_algo is a callback to match |
610 | | * algos for the client or server. */ |
611 | 0 | static void read_kex_algos() { |
612 | | |
613 | | /* for asymmetry */ |
614 | 0 | algo_type * c2s_hash_algo = NULL; |
615 | 0 | algo_type * s2c_hash_algo = NULL; |
616 | 0 | algo_type * c2s_cipher_algo = NULL; |
617 | 0 | algo_type * s2c_cipher_algo = NULL; |
618 | 0 | algo_type * c2s_comp_algo = NULL; |
619 | 0 | algo_type * s2c_comp_algo = NULL; |
620 | | /* the generic one */ |
621 | 0 | algo_type * algo = NULL; |
622 | | |
623 | | /* which algo couldn't match */ |
624 | 0 | char * erralgo = NULL; |
625 | |
|
626 | 0 | int goodguess = 0; |
627 | 0 | int allgood = 1; /* we AND this with each goodguess and see if its still |
628 | | true after */ |
629 | 0 | int kexguess2 = 0; |
630 | |
|
631 | 0 | buf_incrpos(ses.payload, 16); /* start after the cookie */ |
632 | |
|
633 | 0 | memset(ses.newkeys, 0x0, sizeof(*ses.newkeys)); |
634 | | |
635 | | /* kex_algorithms */ |
636 | 0 | #if DROPBEAR_KEXGUESS2 |
637 | 0 | if (buf_has_algo(ses.payload, KEXGUESS2_ALGO_NAME) == DROPBEAR_SUCCESS) { |
638 | 0 | kexguess2 = 1; |
639 | 0 | } |
640 | 0 | #endif |
641 | |
|
642 | 0 | #if DROPBEAR_EXT_INFO |
643 | | /* Determine if SSH_MSG_EXT_INFO messages should be sent. |
644 | | Should be done for the first key exchange. Only required on server side |
645 | | for server-sig-algs */ |
646 | 0 | if (IS_DROPBEAR_SERVER) { |
647 | 0 | if (!ses.kexstate.donefirstkex) { |
648 | 0 | if (buf_has_algo(ses.payload, SSH_EXT_INFO_C) == DROPBEAR_SUCCESS) { |
649 | 0 | ses.allow_ext_info = 1; |
650 | 0 | } |
651 | 0 | } |
652 | 0 | } |
653 | 0 | #endif |
654 | |
|
655 | 0 | if (!ses.kexstate.donefirstkex) { |
656 | 0 | const char* strict_name; |
657 | 0 | if (IS_DROPBEAR_CLIENT) { |
658 | 0 | strict_name = SSH_STRICT_KEX_S; |
659 | 0 | } else { |
660 | 0 | strict_name = SSH_STRICT_KEX_C; |
661 | 0 | } |
662 | 0 | if (buf_has_algo(ses.payload, strict_name) == DROPBEAR_SUCCESS) { |
663 | 0 | ses.kexstate.strict_kex = 1; |
664 | 0 | } |
665 | 0 | } |
666 | |
|
667 | 0 | algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess); |
668 | 0 | allgood &= goodguess; |
669 | 0 | if (algo == NULL || algo->data == NULL) { |
670 | | /* kexguess2, ext-info-c, ext-info-s should not match negotiation */ |
671 | 0 | erralgo = "kex"; |
672 | 0 | goto error; |
673 | 0 | } |
674 | 0 | TRACE(("kexguess2 %d", kexguess2)) |
675 | 0 | DEBUG3(("kex algo %s", algo->name)) |
676 | 0 | ses.newkeys->algo_kex = algo->data; |
677 | | |
678 | | /* server_host_key_algorithms */ |
679 | 0 | algo = buf_match_algo(ses.payload, sigalgs, kexguess2, &goodguess); |
680 | 0 | allgood &= goodguess; |
681 | 0 | if (algo == NULL) { |
682 | 0 | erralgo = "hostkey"; |
683 | 0 | goto error; |
684 | 0 | } |
685 | 0 | DEBUG2(("hostkey algo %s", algo->name)) |
686 | 0 | ses.newkeys->algo_signature = algo->val; |
687 | 0 | ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature); |
688 | | |
689 | | /* encryption_algorithms_client_to_server */ |
690 | 0 | c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL); |
691 | 0 | if (c2s_cipher_algo == NULL) { |
692 | 0 | erralgo = "enc c->s"; |
693 | 0 | goto error; |
694 | 0 | } |
695 | 0 | DEBUG2(("enc c2s is %s", c2s_cipher_algo->name)) |
696 | | |
697 | | /* encryption_algorithms_server_to_client */ |
698 | 0 | s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL); |
699 | 0 | if (s2c_cipher_algo == NULL) { |
700 | 0 | erralgo = "enc s->c"; |
701 | 0 | goto error; |
702 | 0 | } |
703 | 0 | DEBUG2(("enc s2c is %s", s2c_cipher_algo->name)) |
704 | | |
705 | | /* mac_algorithms_client_to_server */ |
706 | 0 | c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL); |
707 | 0 | #if DROPBEAR_AEAD_MODE |
708 | 0 | if (((struct dropbear_cipher_mode*)c2s_cipher_algo->mode)->aead_crypt != NULL) { |
709 | 0 | c2s_hash_algo = NULL; |
710 | 0 | } else |
711 | 0 | #endif |
712 | 0 | if (c2s_hash_algo == NULL) { |
713 | 0 | erralgo = "mac c->s"; |
714 | 0 | goto error; |
715 | 0 | } |
716 | 0 | DEBUG2(("hmac c2s is %s", c2s_hash_algo ? c2s_hash_algo->name : "<implicit>")) |
717 | | |
718 | | /* mac_algorithms_server_to_client */ |
719 | 0 | s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL); |
720 | 0 | #if DROPBEAR_AEAD_MODE |
721 | 0 | if (((struct dropbear_cipher_mode*)s2c_cipher_algo->mode)->aead_crypt != NULL) { |
722 | 0 | s2c_hash_algo = NULL; |
723 | 0 | } else |
724 | 0 | #endif |
725 | 0 | if (s2c_hash_algo == NULL) { |
726 | 0 | erralgo = "mac s->c"; |
727 | 0 | goto error; |
728 | 0 | } |
729 | 0 | DEBUG2(("hmac s2c is %s", s2c_hash_algo ? s2c_hash_algo->name : "<implicit>")) |
730 | | |
731 | | /* compression_algorithms_client_to_server */ |
732 | 0 | c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos_c2s, 0, NULL); |
733 | 0 | if (c2s_comp_algo == NULL) { |
734 | 0 | erralgo = "comp c->s"; |
735 | 0 | goto error; |
736 | 0 | } |
737 | 0 | DEBUG2(("comp c2s is %s", c2s_comp_algo->name)) |
738 | | |
739 | | /* compression_algorithms_server_to_client */ |
740 | 0 | s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos_s2c, 0, NULL); |
741 | 0 | if (s2c_comp_algo == NULL) { |
742 | 0 | erralgo = "comp s->c"; |
743 | 0 | goto error; |
744 | 0 | } |
745 | 0 | DEBUG2(("comp s2c is %s", s2c_comp_algo->name)) |
746 | | |
747 | | /* languages_client_to_server */ |
748 | 0 | buf_eatstring(ses.payload); |
749 | | |
750 | | /* languages_server_to_client */ |
751 | 0 | buf_eatstring(ses.payload); |
752 | | |
753 | | /* their first_kex_packet_follows */ |
754 | 0 | if (buf_getbool(ses.payload)) { |
755 | 0 | TRACE(("them kex firstfollows. allgood %d", allgood)) |
756 | 0 | ses.kexstate.them_firstfollows = 1; |
757 | | /* if the guess wasn't good, we ignore the packet sent */ |
758 | 0 | if (!allgood) { |
759 | 0 | ses.ignorenext = 1; |
760 | 0 | } |
761 | 0 | } |
762 | | |
763 | | /* Handle the asymmetry */ |
764 | 0 | if (IS_DROPBEAR_CLIENT) { |
765 | 0 | ses.newkeys->recv.algo_crypt = |
766 | 0 | (struct dropbear_cipher*)s2c_cipher_algo->data; |
767 | 0 | ses.newkeys->trans.algo_crypt = |
768 | 0 | (struct dropbear_cipher*)c2s_cipher_algo->data; |
769 | 0 | ses.newkeys->recv.crypt_mode = |
770 | 0 | (struct dropbear_cipher_mode*)s2c_cipher_algo->mode; |
771 | 0 | ses.newkeys->trans.crypt_mode = |
772 | 0 | (struct dropbear_cipher_mode*)c2s_cipher_algo->mode; |
773 | 0 | ses.newkeys->recv.algo_mac = |
774 | 0 | #if DROPBEAR_AEAD_MODE |
775 | 0 | s2c_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac : |
776 | 0 | #endif |
777 | 0 | (struct dropbear_hash*)s2c_hash_algo->data; |
778 | 0 | ses.newkeys->trans.algo_mac = |
779 | 0 | #if DROPBEAR_AEAD_MODE |
780 | 0 | c2s_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac : |
781 | 0 | #endif |
782 | 0 | (struct dropbear_hash*)c2s_hash_algo->data; |
783 | 0 | ses.newkeys->recv.algo_comp = s2c_comp_algo->val; |
784 | 0 | ses.newkeys->trans.algo_comp = c2s_comp_algo->val; |
785 | 0 | } else { |
786 | | /* SERVER */ |
787 | 0 | ses.newkeys->recv.algo_crypt = |
788 | 0 | (struct dropbear_cipher*)c2s_cipher_algo->data; |
789 | 0 | ses.newkeys->trans.algo_crypt = |
790 | 0 | (struct dropbear_cipher*)s2c_cipher_algo->data; |
791 | 0 | ses.newkeys->recv.crypt_mode = |
792 | 0 | (struct dropbear_cipher_mode*)c2s_cipher_algo->mode; |
793 | 0 | ses.newkeys->trans.crypt_mode = |
794 | 0 | (struct dropbear_cipher_mode*)s2c_cipher_algo->mode; |
795 | 0 | ses.newkeys->recv.algo_mac = |
796 | 0 | #if DROPBEAR_AEAD_MODE |
797 | 0 | c2s_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac : |
798 | 0 | #endif |
799 | 0 | (struct dropbear_hash*)c2s_hash_algo->data; |
800 | 0 | ses.newkeys->trans.algo_mac = |
801 | 0 | #if DROPBEAR_AEAD_MODE |
802 | 0 | s2c_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac : |
803 | 0 | #endif |
804 | 0 | (struct dropbear_hash*)s2c_hash_algo->data; |
805 | 0 | ses.newkeys->recv.algo_comp = c2s_comp_algo->val; |
806 | 0 | ses.newkeys->trans.algo_comp = s2c_comp_algo->val; |
807 | 0 | } |
808 | |
|
809 | 0 | #if DROPBEAR_FUZZ |
810 | 0 | if (fuzz.fuzzing) { |
811 | 0 | fuzz_kex_fakealgos(); |
812 | 0 | } |
813 | 0 | #endif |
814 | | |
815 | | /* reserved for future extensions */ |
816 | 0 | buf_getint(ses.payload); |
817 | |
|
818 | 0 | if (ses.send_kex_first_guess && allgood) { |
819 | 0 | TRACE(("our_first_follows_matches 1")) |
820 | 0 | ses.kexstate.our_first_follows_matches = 1; |
821 | 0 | } |
822 | 0 | return; |
823 | | |
824 | 0 | error: |
825 | 0 | dropbear_exit("No matching algo %s", erralgo); |
826 | 0 | } |