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