/src/dropbear/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 "dh_groups.h" |
33 | | #include "ssh.h" |
34 | | #include "packet.h" |
35 | | #include "bignum.h" |
36 | | #include "dbrandom.h" |
37 | | #include "runopts.h" |
38 | | #include "ecc.h" |
39 | | #include "curve25519.h" |
40 | | #include "crypto_desc.h" |
41 | | |
42 | | static void kexinitialise(void); |
43 | | static void gen_new_keys(void); |
44 | | #ifndef DISABLE_ZLIB |
45 | | static void gen_new_zstream_recv(void); |
46 | | static void gen_new_zstream_trans(void); |
47 | | #endif |
48 | | static void read_kex_algos(void); |
49 | | /* helper function for gen_new_keys */ |
50 | | static void hashkeys(unsigned char *out, unsigned int outlen, |
51 | | const hash_state * hs, const unsigned char X); |
52 | | |
53 | | |
54 | | /* Send our list of algorithms we can use */ |
55 | 2.14k | void send_msg_kexinit() { |
56 | | |
57 | 2.14k | CHECKCLEARTOWRITE(); |
58 | 2.14k | buf_putbyte(ses.writepayload, SSH_MSG_KEXINIT); |
59 | | |
60 | | /* cookie */ |
61 | 2.14k | genrandom(buf_getwriteptr(ses.writepayload, 16), 16); |
62 | 2.14k | buf_incrwritepos(ses.writepayload, 16); |
63 | | |
64 | | /* kex algos */ |
65 | 2.14k | buf_put_algolist(ses.writepayload, sshkex); |
66 | | |
67 | | /* server_host_key_algorithms */ |
68 | 2.14k | buf_put_algolist(ses.writepayload, sigalgs); |
69 | | |
70 | | /* encryption_algorithms_client_to_server */ |
71 | 2.14k | buf_put_algolist(ses.writepayload, sshciphers); |
72 | | |
73 | | /* encryption_algorithms_server_to_client */ |
74 | 2.14k | buf_put_algolist(ses.writepayload, sshciphers); |
75 | | |
76 | | /* mac_algorithms_client_to_server */ |
77 | 2.14k | buf_put_algolist(ses.writepayload, sshhashes); |
78 | | |
79 | | /* mac_algorithms_server_to_client */ |
80 | 2.14k | buf_put_algolist(ses.writepayload, sshhashes); |
81 | | |
82 | | |
83 | | /* compression_algorithms_client_to_server */ |
84 | 2.14k | buf_put_algolist(ses.writepayload, ses.compress_algos); |
85 | | |
86 | | /* compression_algorithms_server_to_client */ |
87 | 2.14k | buf_put_algolist(ses.writepayload, ses.compress_algos); |
88 | | |
89 | | /* languages_client_to_server */ |
90 | 2.14k | buf_putstring(ses.writepayload, "", 0); |
91 | | |
92 | | /* languages_server_to_client */ |
93 | 2.14k | buf_putstring(ses.writepayload, "", 0); |
94 | | |
95 | | /* first_kex_packet_follows */ |
96 | 2.14k | buf_putbyte(ses.writepayload, (ses.send_kex_first_guess != NULL)); |
97 | | |
98 | | /* reserved unit32 */ |
99 | 2.14k | buf_putint(ses.writepayload, 0); |
100 | | |
101 | | /* set up transmitted kex packet buffer for hashing. |
102 | | * This is freed after the end of the kex */ |
103 | 2.14k | ses.transkexinit = buf_newcopy(ses.writepayload); |
104 | | |
105 | 2.14k | encrypt_packet(); |
106 | 2.14k | ses.dataallowed = 0; /* don't send other packets during kex */ |
107 | | |
108 | 2.14k | ses.kexstate.sentkexinit = 1; |
109 | | |
110 | 2.14k | ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context)); |
111 | | |
112 | 2.14k | if (ses.send_kex_first_guess) { |
113 | 0 | ses.newkeys->algo_kex = first_usable_algo(sshkex)->data; |
114 | 0 | ses.newkeys->algo_signature = first_usable_algo(sigalgs)->val; |
115 | 0 | ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature); |
116 | 0 | ses.send_kex_first_guess(); |
117 | 0 | } |
118 | | |
119 | 2.14k | TRACE(("DATAALLOWED=0")) |
120 | 2.14k | TRACE(("-> KEXINIT")) |
121 | | |
122 | 2.14k | } |
123 | | |
124 | 0 | static void switch_keys() { |
125 | 0 | TRACE2(("enter switch_keys")) |
126 | 0 | if (!(ses.kexstate.sentkexinit && ses.kexstate.recvkexinit)) { |
127 | 0 | dropbear_exit("Unexpected newkeys message"); |
128 | 0 | } |
129 | | |
130 | 0 | if (!ses.keys) { |
131 | 0 | ses.keys = m_malloc(sizeof(*ses.newkeys)); |
132 | 0 | } |
133 | 0 | if (ses.kexstate.recvnewkeys && ses.newkeys->recv.valid) { |
134 | 0 | TRACE(("switch_keys recv")) |
135 | | #ifndef DISABLE_ZLIB |
136 | | gen_new_zstream_recv(); |
137 | | #endif |
138 | 0 | ses.keys->recv = ses.newkeys->recv; |
139 | 0 | m_burn(&ses.newkeys->recv, sizeof(ses.newkeys->recv)); |
140 | 0 | ses.newkeys->recv.valid = 0; |
141 | 0 | } |
142 | 0 | if (ses.kexstate.sentnewkeys && ses.newkeys->trans.valid) { |
143 | 0 | TRACE(("switch_keys trans")) |
144 | | #ifndef DISABLE_ZLIB |
145 | | gen_new_zstream_trans(); |
146 | | #endif |
147 | 0 | ses.keys->trans = ses.newkeys->trans; |
148 | 0 | m_burn(&ses.newkeys->trans, sizeof(ses.newkeys->trans)); |
149 | 0 | ses.newkeys->trans.valid = 0; |
150 | 0 | } |
151 | 0 | if (ses.kexstate.sentnewkeys && ses.kexstate.recvnewkeys) |
152 | 0 | { |
153 | 0 | TRACE(("switch_keys done")) |
154 | 0 | ses.keys->algo_kex = ses.newkeys->algo_kex; |
155 | 0 | ses.keys->algo_hostkey = ses.newkeys->algo_hostkey; |
156 | 0 | ses.keys->algo_signature = ses.newkeys->algo_signature; |
157 | 0 | ses.keys->allow_compress = 0; |
158 | 0 | m_free(ses.newkeys); |
159 | 0 | ses.newkeys = NULL; |
160 | 0 | kexinitialise(); |
161 | 0 | } |
162 | 0 | TRACE2(("leave switch_keys")) |
163 | 0 | } |
164 | | |
165 | | /* Bring new keys into use after a key exchange, and let the client know*/ |
166 | 0 | void send_msg_newkeys() { |
167 | |
|
168 | 0 | TRACE(("enter send_msg_newkeys")) |
169 | | |
170 | | /* generate the kexinit request */ |
171 | 0 | CHECKCLEARTOWRITE(); |
172 | 0 | buf_putbyte(ses.writepayload, SSH_MSG_NEWKEYS); |
173 | 0 | encrypt_packet(); |
174 | | |
175 | | |
176 | | /* set up our state */ |
177 | 0 | ses.kexstate.sentnewkeys = 1; |
178 | 0 | if (ses.kexstate.donefirstkex) { |
179 | 0 | ses.kexstate.donesecondkex = 1; |
180 | 0 | } |
181 | 0 | ses.kexstate.donefirstkex = 1; |
182 | 0 | ses.dataallowed = 1; /* we can send other packets again now */ |
183 | 0 | gen_new_keys(); |
184 | 0 | switch_keys(); |
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 | TRACE(("leave recv_msg_newkeys")) |
198 | 0 | } |
199 | | |
200 | | |
201 | | /* Set up the kex for the first time */ |
202 | 2.14k | void kexfirstinitialise() { |
203 | 2.14k | #ifdef DISABLE_ZLIB |
204 | 2.14k | ses.compress_algos = ssh_nocompress; |
205 | | #else |
206 | | switch (opts.compress_mode) |
207 | | { |
208 | | case DROPBEAR_COMPRESS_DELAYED: |
209 | | ses.compress_algos = ssh_delaycompress; |
210 | | break; |
211 | | |
212 | | case DROPBEAR_COMPRESS_ON: |
213 | | ses.compress_algos = ssh_compress; |
214 | | break; |
215 | | |
216 | | case DROPBEAR_COMPRESS_OFF: |
217 | | ses.compress_algos = ssh_nocompress; |
218 | | break; |
219 | | } |
220 | | #endif |
221 | 2.14k | kexinitialise(); |
222 | 2.14k | } |
223 | | |
224 | | /* Reset the kex state, ready for a new negotiation */ |
225 | 2.14k | static void kexinitialise() { |
226 | | |
227 | 2.14k | TRACE(("kexinitialise()")) |
228 | | |
229 | | /* sent/recv'd MSG_KEXINIT */ |
230 | 2.14k | ses.kexstate.sentkexinit = 0; |
231 | 2.14k | ses.kexstate.recvkexinit = 0; |
232 | | |
233 | | /* sent/recv'd MSG_NEWKEYS */ |
234 | 2.14k | ses.kexstate.recvnewkeys = 0; |
235 | 2.14k | ses.kexstate.sentnewkeys = 0; |
236 | | |
237 | | /* first_packet_follows */ |
238 | 2.14k | ses.kexstate.them_firstfollows = 0; |
239 | | |
240 | 2.14k | ses.kexstate.datatrans = 0; |
241 | 2.14k | ses.kexstate.datarecv = 0; |
242 | | |
243 | 2.14k | ses.kexstate.our_first_follows_matches = 0; |
244 | | |
245 | 2.14k | ses.kexstate.lastkextime = monotonic_now(); |
246 | | |
247 | 2.14k | } |
248 | | |
249 | | /* Helper function for gen_new_keys, creates a hash. It makes a copy of the |
250 | | * already initialised hash_state hs, which should already have processed |
251 | | * the dh_K and hash, since these are common. X is the letter 'A', 'B' etc. |
252 | | * out must have at least min(hash_size, outlen) bytes allocated. |
253 | | * |
254 | | * See Section 7.2 of rfc4253 (ssh transport) for details */ |
255 | | static void hashkeys(unsigned char *out, unsigned int outlen, |
256 | 0 | const hash_state * hs, const unsigned char X) { |
257 | |
|
258 | 0 | const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc; |
259 | 0 | hash_state hs2; |
260 | 0 | unsigned int offset; |
261 | 0 | unsigned char tmpout[MAX_HASH_SIZE]; |
262 | |
|
263 | 0 | memcpy(&hs2, hs, sizeof(hash_state)); |
264 | 0 | hash_desc->process(&hs2, &X, 1); |
265 | 0 | hash_desc->process(&hs2, ses.session_id->data, ses.session_id->len); |
266 | 0 | hash_desc->done(&hs2, tmpout); |
267 | 0 | memcpy(out, tmpout, MIN(hash_desc->hashsize, outlen)); |
268 | 0 | for (offset = hash_desc->hashsize; |
269 | 0 | offset < outlen; |
270 | 0 | offset += hash_desc->hashsize) |
271 | 0 | { |
272 | | /* need to extend */ |
273 | 0 | memcpy(&hs2, hs, sizeof(hash_state)); |
274 | 0 | hash_desc->process(&hs2, out, offset); |
275 | 0 | hash_desc->done(&hs2, tmpout); |
276 | 0 | memcpy(&out[offset], tmpout, MIN(outlen - offset, hash_desc->hashsize)); |
277 | 0 | } |
278 | 0 | m_burn(&hs2, sizeof(hash_state)); |
279 | 0 | } |
280 | | |
281 | | /* Generate the actual encryption/integrity keys, using the results of the |
282 | | * key exchange, as specified in section 7.2 of the transport rfc 4253. |
283 | | * This occurs after the DH key-exchange. |
284 | | * |
285 | | * ses.newkeys is the new set of keys which are generated, these are only |
286 | | * taken into use after both sides have sent a newkeys message */ |
287 | | |
288 | 0 | static void gen_new_keys() { |
289 | |
|
290 | 0 | unsigned char C2S_IV[MAX_IV_LEN]; |
291 | 0 | unsigned char C2S_key[MAX_KEY_LEN]; |
292 | 0 | unsigned char S2C_IV[MAX_IV_LEN]; |
293 | 0 | unsigned char S2C_key[MAX_KEY_LEN]; |
294 | | /* unsigned char key[MAX_KEY_LEN]; */ |
295 | 0 | unsigned char *trans_IV, *trans_key, *recv_IV, *recv_key; |
296 | |
|
297 | 0 | hash_state hs; |
298 | 0 | const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc; |
299 | 0 | char mactransletter, macrecvletter; /* Client or server specific */ |
300 | |
|
301 | 0 | TRACE(("enter gen_new_keys")) |
302 | | /* the dh_K and hash are the start of all hashes, we make use of that */ |
303 | |
|
304 | 0 | hash_desc->init(&hs); |
305 | 0 | hash_process_mp(hash_desc, &hs, ses.dh_K); |
306 | 0 | mp_clear(ses.dh_K); |
307 | 0 | m_free(ses.dh_K); |
308 | 0 | hash_desc->process(&hs, ses.hash->data, ses.hash->len); |
309 | 0 | buf_burn_free(ses.hash); |
310 | 0 | ses.hash = NULL; |
311 | |
|
312 | 0 | if (IS_DROPBEAR_CLIENT) { |
313 | 0 | trans_IV = C2S_IV; |
314 | 0 | recv_IV = S2C_IV; |
315 | 0 | trans_key = C2S_key; |
316 | 0 | recv_key = S2C_key; |
317 | 0 | mactransletter = 'E'; |
318 | 0 | macrecvletter = 'F'; |
319 | 0 | } else { |
320 | 0 | trans_IV = S2C_IV; |
321 | 0 | recv_IV = C2S_IV; |
322 | 0 | trans_key = S2C_key; |
323 | 0 | recv_key = C2S_key; |
324 | 0 | mactransletter = 'F'; |
325 | 0 | macrecvletter = 'E'; |
326 | 0 | } |
327 | |
|
328 | 0 | hashkeys(C2S_IV, sizeof(C2S_IV), &hs, 'A'); |
329 | 0 | hashkeys(S2C_IV, sizeof(S2C_IV), &hs, 'B'); |
330 | 0 | hashkeys(C2S_key, sizeof(C2S_key), &hs, 'C'); |
331 | 0 | hashkeys(S2C_key, sizeof(S2C_key), &hs, 'D'); |
332 | |
|
333 | 0 | if (ses.newkeys->recv.algo_crypt->cipherdesc != NULL) { |
334 | 0 | int recv_cipher = -1; |
335 | 0 | if (ses.newkeys->recv.algo_crypt->cipherdesc->name != NULL) { |
336 | 0 | recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name); |
337 | 0 | if (recv_cipher < 0) { |
338 | 0 | dropbear_exit("Crypto error"); |
339 | 0 | } |
340 | 0 | } |
341 | 0 | if (ses.newkeys->recv.crypt_mode->start(recv_cipher, |
342 | 0 | recv_IV, recv_key, |
343 | 0 | ses.newkeys->recv.algo_crypt->keysize, 0, |
344 | 0 | &ses.newkeys->recv.cipher_state) != CRYPT_OK) { |
345 | 0 | dropbear_exit("Crypto error"); |
346 | 0 | } |
347 | 0 | } |
348 | | |
349 | 0 | if (ses.newkeys->trans.algo_crypt->cipherdesc != NULL) { |
350 | 0 | int trans_cipher = -1; |
351 | 0 | if (ses.newkeys->trans.algo_crypt->cipherdesc->name != NULL) { |
352 | 0 | trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name); |
353 | 0 | if (trans_cipher < 0) { |
354 | 0 | dropbear_exit("Crypto error"); |
355 | 0 | } |
356 | 0 | } |
357 | 0 | if (ses.newkeys->trans.crypt_mode->start(trans_cipher, |
358 | 0 | trans_IV, trans_key, |
359 | 0 | ses.newkeys->trans.algo_crypt->keysize, 0, |
360 | 0 | &ses.newkeys->trans.cipher_state) != CRYPT_OK) { |
361 | 0 | dropbear_exit("Crypto error"); |
362 | 0 | } |
363 | 0 | } |
364 | | |
365 | 0 | if (ses.newkeys->trans.algo_mac->hash_desc != NULL) { |
366 | 0 | hashkeys(ses.newkeys->trans.mackey, |
367 | 0 | ses.newkeys->trans.algo_mac->keysize, &hs, mactransletter); |
368 | 0 | ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hash_desc->name); |
369 | 0 | } |
370 | |
|
371 | 0 | if (ses.newkeys->recv.algo_mac->hash_desc != NULL) { |
372 | 0 | hashkeys(ses.newkeys->recv.mackey, |
373 | 0 | ses.newkeys->recv.algo_mac->keysize, &hs, macrecvletter); |
374 | 0 | ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hash_desc->name); |
375 | 0 | } |
376 | | |
377 | | /* Ready to switch over */ |
378 | 0 | ses.newkeys->trans.valid = 1; |
379 | 0 | ses.newkeys->recv.valid = 1; |
380 | |
|
381 | 0 | m_burn(C2S_IV, sizeof(C2S_IV)); |
382 | 0 | m_burn(C2S_key, sizeof(C2S_key)); |
383 | 0 | m_burn(S2C_IV, sizeof(S2C_IV)); |
384 | 0 | m_burn(S2C_key, sizeof(S2C_key)); |
385 | 0 | m_burn(&hs, sizeof(hash_state)); |
386 | |
|
387 | 0 | TRACE(("leave gen_new_keys")) |
388 | 0 | } |
389 | | |
390 | | #ifndef DISABLE_ZLIB |
391 | | |
392 | | int is_compress_trans() { |
393 | | return ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB |
394 | | || (ses.authstate.authdone |
395 | | && ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY); |
396 | | } |
397 | | |
398 | | int is_compress_recv() { |
399 | | return ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB |
400 | | || (ses.authstate.authdone |
401 | | && ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY); |
402 | | } |
403 | | |
404 | | static void* dropbear_zalloc(void* UNUSED(opaque), uInt items, uInt size) { |
405 | | return m_calloc(items, size); |
406 | | } |
407 | | |
408 | | static void dropbear_zfree(void* UNUSED(opaque), void* ptr) { |
409 | | m_free(ptr); |
410 | | } |
411 | | |
412 | | /* Set up new zlib compression streams, close the old ones. Only |
413 | | * called from gen_new_keys() */ |
414 | | static void gen_new_zstream_recv() { |
415 | | |
416 | | /* create new zstreams */ |
417 | | if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB |
418 | | || ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) { |
419 | | ses.newkeys->recv.zstream = (z_streamp)m_malloc(sizeof(z_stream)); |
420 | | ses.newkeys->recv.zstream->zalloc = dropbear_zalloc; |
421 | | ses.newkeys->recv.zstream->zfree = dropbear_zfree; |
422 | | |
423 | | if (inflateInit(ses.newkeys->recv.zstream) != Z_OK) { |
424 | | dropbear_exit("zlib error"); |
425 | | } |
426 | | } else { |
427 | | ses.newkeys->recv.zstream = NULL; |
428 | | } |
429 | | /* clean up old keys */ |
430 | | if (ses.keys->recv.zstream != NULL) { |
431 | | if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) { |
432 | | /* Z_DATA_ERROR is ok, just means that stream isn't ended */ |
433 | | dropbear_exit("Crypto error"); |
434 | | } |
435 | | m_free(ses.keys->recv.zstream); |
436 | | } |
437 | | } |
438 | | |
439 | | static void gen_new_zstream_trans() { |
440 | | |
441 | | if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB |
442 | | || ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) { |
443 | | ses.newkeys->trans.zstream = (z_streamp)m_malloc(sizeof(z_stream)); |
444 | | ses.newkeys->trans.zstream->zalloc = dropbear_zalloc; |
445 | | ses.newkeys->trans.zstream->zfree = dropbear_zfree; |
446 | | |
447 | | if (deflateInit2(ses.newkeys->trans.zstream, Z_DEFAULT_COMPRESSION, |
448 | | Z_DEFLATED, DROPBEAR_ZLIB_WINDOW_BITS, |
449 | | DROPBEAR_ZLIB_MEM_LEVEL, Z_DEFAULT_STRATEGY) |
450 | | != Z_OK) { |
451 | | dropbear_exit("zlib error"); |
452 | | } |
453 | | } else { |
454 | | ses.newkeys->trans.zstream = NULL; |
455 | | } |
456 | | |
457 | | if (ses.keys->trans.zstream != NULL) { |
458 | | if (deflateEnd(ses.keys->trans.zstream) == Z_STREAM_ERROR) { |
459 | | /* Z_DATA_ERROR is ok, just means that stream isn't ended */ |
460 | | dropbear_exit("Crypto error"); |
461 | | } |
462 | | m_free(ses.keys->trans.zstream); |
463 | | } |
464 | | } |
465 | | #endif /* DISABLE_ZLIB */ |
466 | | |
467 | | |
468 | | /* Executed upon receiving a kexinit message from the client to initiate |
469 | | * key exchange. If we haven't already done so, we send the list of our |
470 | | * preferred algorithms. The client's requested algorithms are processed, |
471 | | * and we calculate the first portion of the key-exchange-hash for used |
472 | | * later in the key exchange. No response is sent, as the client should |
473 | | * initiate the diffie-hellman key exchange */ |
474 | 330 | void recv_msg_kexinit() { |
475 | | |
476 | 330 | unsigned int kexhashbuf_len = 0; |
477 | 330 | unsigned int remote_ident_len = 0; |
478 | 330 | unsigned int local_ident_len = 0; |
479 | | |
480 | 330 | TRACE(("<- KEXINIT")) |
481 | 330 | TRACE(("enter recv_msg_kexinit")) |
482 | | |
483 | 330 | if (!ses.kexstate.sentkexinit) { |
484 | | /* we need to send a kex packet */ |
485 | 0 | send_msg_kexinit(); |
486 | 0 | TRACE(("continue recv_msg_kexinit: sent kexinit")) |
487 | 0 | } |
488 | | |
489 | | /* "Once a party has sent a SSH_MSG_KEXINIT message ... |
490 | | further SSH_MSG_KEXINIT messages MUST NOT be sent" */ |
491 | 330 | if (ses.kexstate.recvkexinit) { |
492 | 0 | dropbear_exit("Unexpected KEXINIT"); |
493 | 0 | } |
494 | | |
495 | | /* start the kex hash */ |
496 | 330 | local_ident_len = strlen(LOCAL_IDENT); |
497 | 330 | remote_ident_len = strlen(ses.remoteident); |
498 | | |
499 | 330 | kexhashbuf_len = local_ident_len + remote_ident_len |
500 | 330 | + ses.transkexinit->len + ses.payload->len |
501 | 330 | + KEXHASHBUF_MAX_INTS; |
502 | | |
503 | 330 | ses.kexhashbuf = buf_new(kexhashbuf_len); |
504 | | |
505 | 330 | if (IS_DROPBEAR_CLIENT) { |
506 | | |
507 | | /* read the peer's choice of algos */ |
508 | 0 | read_kex_algos(); |
509 | | |
510 | | /* V_C, the client's version string (CR and NL excluded) */ |
511 | 0 | buf_putstring(ses.kexhashbuf, LOCAL_IDENT, local_ident_len); |
512 | | /* V_S, the server's version string (CR and NL excluded) */ |
513 | 0 | buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len); |
514 | | |
515 | | /* I_C, the payload of the client's SSH_MSG_KEXINIT */ |
516 | 0 | buf_putstring(ses.kexhashbuf, |
517 | 0 | (const char*)ses.transkexinit->data, ses.transkexinit->len); |
518 | | /* I_S, the payload of the server's SSH_MSG_KEXINIT */ |
519 | 0 | buf_setpos(ses.payload, ses.payload_beginning); |
520 | 0 | buf_putstring(ses.kexhashbuf, |
521 | 0 | (const char*)buf_getptr(ses.payload, ses.payload->len-ses.payload->pos), |
522 | 0 | ses.payload->len-ses.payload->pos); |
523 | 0 | ses.requirenext = SSH_MSG_KEXDH_REPLY; |
524 | 330 | } else { |
525 | | /* SERVER */ |
526 | | |
527 | | /* read the peer's choice of algos */ |
528 | 330 | read_kex_algos(); |
529 | | /* V_C, the client's version string (CR and NL excluded) */ |
530 | 330 | buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len); |
531 | | /* V_S, the server's version string (CR and NL excluded) */ |
532 | 330 | buf_putstring(ses.kexhashbuf, LOCAL_IDENT, local_ident_len); |
533 | | |
534 | | /* I_C, the payload of the client's SSH_MSG_KEXINIT */ |
535 | 330 | buf_setpos(ses.payload, ses.payload_beginning); |
536 | 330 | buf_putstring(ses.kexhashbuf, |
537 | 330 | (const char*)buf_getptr(ses.payload, ses.payload->len-ses.payload->pos), |
538 | 330 | ses.payload->len-ses.payload->pos); |
539 | | |
540 | | /* I_S, the payload of the server's SSH_MSG_KEXINIT */ |
541 | 330 | buf_putstring(ses.kexhashbuf, |
542 | 330 | (const char*)ses.transkexinit->data, ses.transkexinit->len); |
543 | | |
544 | 330 | ses.requirenext = SSH_MSG_KEXDH_INIT; |
545 | 330 | } |
546 | | |
547 | 330 | buf_free(ses.transkexinit); |
548 | 330 | ses.transkexinit = NULL; |
549 | | /* the rest of ses.kexhashbuf will be done after DH exchange */ |
550 | | |
551 | 330 | ses.kexstate.recvkexinit = 1; |
552 | | |
553 | 330 | TRACE(("leave recv_msg_kexinit")) |
554 | 330 | } |
555 | | |
556 | | #if DROPBEAR_NORMAL_DH |
557 | | static void load_dh_p(mp_int * dh_p) |
558 | 0 | { |
559 | 0 | bytes_to_mp(dh_p, ses.newkeys->algo_kex->dh_p_bytes, |
560 | 0 | ses.newkeys->algo_kex->dh_p_len); |
561 | 0 | } |
562 | | |
563 | | /* Initialises and generate one side of the diffie-hellman key exchange values. |
564 | | * See the transport rfc 4253 section 8 for details */ |
565 | | /* dh_pub and dh_priv MUST be already initialised */ |
566 | 0 | struct kex_dh_param *gen_kexdh_param() { |
567 | 0 | struct kex_dh_param *param = NULL; |
568 | |
|
569 | 0 | DEF_MP_INT(dh_p); |
570 | 0 | DEF_MP_INT(dh_q); |
571 | 0 | DEF_MP_INT(dh_g); |
572 | |
|
573 | 0 | TRACE(("enter gen_kexdh_vals")) |
574 | |
|
575 | 0 | param = m_malloc(sizeof(*param)); |
576 | 0 | m_mp_init_multi(¶m->pub, ¶m->priv, &dh_g, &dh_p, &dh_q, NULL); |
577 | | |
578 | | /* read the prime and generator*/ |
579 | 0 | load_dh_p(&dh_p); |
580 | | |
581 | 0 | mp_set_ul(&dh_g, DH_G_VAL); |
582 | | |
583 | | /* calculate q = (p-1)/2 */ |
584 | | /* dh_priv is just a temp var here */ |
585 | 0 | if (mp_sub_d(&dh_p, 1, ¶m->priv) != MP_OKAY) { |
586 | 0 | dropbear_exit("Diffie-Hellman error"); |
587 | 0 | } |
588 | 0 | if (mp_div_2(¶m->priv, &dh_q) != MP_OKAY) { |
589 | 0 | dropbear_exit("Diffie-Hellman error"); |
590 | 0 | } |
591 | | |
592 | | /* Generate a private portion 0 < dh_priv < dh_q */ |
593 | 0 | gen_random_mpint(&dh_q, ¶m->priv); |
594 | | |
595 | | /* f = g^y mod p */ |
596 | 0 | if (mp_exptmod(&dh_g, ¶m->priv, &dh_p, ¶m->pub) != MP_OKAY) { |
597 | 0 | dropbear_exit("Diffie-Hellman error"); |
598 | 0 | } |
599 | 0 | mp_clear_multi(&dh_g, &dh_p, &dh_q, NULL); |
600 | 0 | return param; |
601 | 0 | } |
602 | | |
603 | | void free_kexdh_param(struct kex_dh_param *param) |
604 | 0 | { |
605 | 0 | mp_clear_multi(¶m->pub, ¶m->priv, NULL); |
606 | 0 | m_free(param); |
607 | 0 | } |
608 | | |
609 | | /* This function is fairly common between client/server, with some substitution |
610 | | * of dh_e/dh_f etc. Hence these arguments: |
611 | | * dh_pub_us is 'e' for the client, 'f' for the server. dh_pub_them is |
612 | | * vice-versa. dh_priv is the x/y value corresponding to dh_pub_us */ |
613 | | void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them, |
614 | 0 | sign_key *hostkey) { |
615 | |
|
616 | 0 | DEF_MP_INT(dh_p); |
617 | 0 | DEF_MP_INT(dh_p_min1); |
618 | 0 | mp_int *dh_e = NULL, *dh_f = NULL; |
619 | |
|
620 | 0 | m_mp_init_multi(&dh_p, &dh_p_min1, NULL); |
621 | 0 | load_dh_p(&dh_p); |
622 | |
|
623 | 0 | if (mp_sub_d(&dh_p, 1, &dh_p_min1) != MP_OKAY) { |
624 | 0 | dropbear_exit("Diffie-Hellman error"); |
625 | 0 | } |
626 | | |
627 | | /* Check that dh_pub_them (dh_e or dh_f) is in the range [2, p-2] */ |
628 | 0 | if (mp_cmp(dh_pub_them, &dh_p_min1) != MP_LT |
629 | 0 | || mp_cmp_d(dh_pub_them, 1) != MP_GT) { |
630 | 0 | dropbear_exit("Diffie-Hellman error"); |
631 | 0 | } |
632 | | |
633 | | /* K = e^y mod p = f^x mod p */ |
634 | 0 | m_mp_alloc_init_multi(&ses.dh_K, NULL); |
635 | 0 | if (mp_exptmod(dh_pub_them, ¶m->priv, &dh_p, ses.dh_K) != MP_OKAY) { |
636 | 0 | dropbear_exit("Diffie-Hellman error"); |
637 | 0 | } |
638 | | |
639 | | /* clear no longer needed vars */ |
640 | 0 | mp_clear_multi(&dh_p, &dh_p_min1, NULL); |
641 | | |
642 | | /* From here on, the code needs to work with the _same_ vars on each side, |
643 | | * not vice-versaing for client/server */ |
644 | 0 | if (IS_DROPBEAR_CLIENT) { |
645 | 0 | dh_e = ¶m->pub; |
646 | 0 | dh_f = dh_pub_them; |
647 | 0 | } else { |
648 | 0 | dh_e = dh_pub_them; |
649 | 0 | dh_f = ¶m->pub; |
650 | 0 | } |
651 | | |
652 | | /* Create the remainder of the hash buffer, to generate the exchange hash */ |
653 | | /* K_S, the host key */ |
654 | 0 | buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey); |
655 | | /* e, exchange value sent by the client */ |
656 | 0 | buf_putmpint(ses.kexhashbuf, dh_e); |
657 | | /* f, exchange value sent by the server */ |
658 | 0 | buf_putmpint(ses.kexhashbuf, dh_f); |
659 | | /* K, the shared secret */ |
660 | 0 | buf_putmpint(ses.kexhashbuf, ses.dh_K); |
661 | | |
662 | | /* calculate the hash H to sign */ |
663 | 0 | finish_kexhashbuf(); |
664 | 0 | } |
665 | | #endif |
666 | | |
667 | | #if DROPBEAR_ECDH |
668 | 0 | struct kex_ecdh_param *gen_kexecdh_param() { |
669 | 0 | struct kex_ecdh_param *param = m_malloc(sizeof(*param)); |
670 | 0 | if (ecc_make_key_ex(NULL, dropbear_ltc_prng, |
671 | 0 | ¶m->key, ses.newkeys->algo_kex->ecc_curve->dp) != CRYPT_OK) { |
672 | 0 | dropbear_exit("ECC error"); |
673 | 0 | } |
674 | 0 | return param; |
675 | 0 | } |
676 | | |
677 | 0 | void free_kexecdh_param(struct kex_ecdh_param *param) { |
678 | 0 | ecc_free(¶m->key); |
679 | 0 | m_free(param); |
680 | |
|
681 | 0 | } |
682 | | void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them, |
683 | 0 | sign_key *hostkey) { |
684 | 0 | const struct dropbear_kex *algo_kex = ses.newkeys->algo_kex; |
685 | | /* public keys from client and server */ |
686 | 0 | ecc_key *Q_C, *Q_S, *Q_them; |
687 | |
|
688 | 0 | Q_them = buf_get_ecc_raw_pubkey(pub_them, algo_kex->ecc_curve); |
689 | 0 | if (Q_them == NULL) { |
690 | 0 | dropbear_exit("ECC error"); |
691 | 0 | } |
692 | | |
693 | 0 | ses.dh_K = dropbear_ecc_shared_secret(Q_them, ¶m->key); |
694 | | |
695 | | /* Create the remainder of the hash buffer, to generate the exchange hash |
696 | | See RFC5656 section 4 page 7 */ |
697 | 0 | if (IS_DROPBEAR_CLIENT) { |
698 | 0 | Q_C = ¶m->key; |
699 | 0 | Q_S = Q_them; |
700 | 0 | } else { |
701 | 0 | Q_C = Q_them; |
702 | 0 | Q_S = ¶m->key; |
703 | 0 | } |
704 | | |
705 | | /* K_S, the host key */ |
706 | 0 | buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey); |
707 | | /* Q_C, client's ephemeral public key octet string */ |
708 | 0 | buf_put_ecc_raw_pubkey_string(ses.kexhashbuf, Q_C); |
709 | | /* Q_S, server's ephemeral public key octet string */ |
710 | 0 | buf_put_ecc_raw_pubkey_string(ses.kexhashbuf, Q_S); |
711 | | /* K, the shared secret */ |
712 | 0 | buf_putmpint(ses.kexhashbuf, ses.dh_K); |
713 | |
|
714 | 0 | ecc_free(Q_them); |
715 | 0 | m_free(Q_them); |
716 | | |
717 | | /* calculate the hash H to sign */ |
718 | 0 | finish_kexhashbuf(); |
719 | 0 | } |
720 | | #endif /* DROPBEAR_ECDH */ |
721 | | |
722 | | #if DROPBEAR_CURVE25519 |
723 | 0 | struct kex_curve25519_param *gen_kexcurve25519_param() { |
724 | | /* Per http://cr.yp.to/ecdh.html */ |
725 | 0 | struct kex_curve25519_param *param = m_malloc(sizeof(*param)); |
726 | 0 | const unsigned char basepoint[32] = {9}; |
727 | |
|
728 | 0 | genrandom(param->priv, CURVE25519_LEN); |
729 | 0 | dropbear_curve25519_scalarmult(param->pub, param->priv, basepoint); |
730 | |
|
731 | 0 | return param; |
732 | 0 | } |
733 | | |
734 | 0 | void free_kexcurve25519_param(struct kex_curve25519_param *param) { |
735 | 0 | m_burn(param->priv, CURVE25519_LEN); |
736 | 0 | m_free(param); |
737 | 0 | } |
738 | | |
739 | | void kexcurve25519_comb_key(const struct kex_curve25519_param *param, const buffer *buf_pub_them, |
740 | 0 | sign_key *hostkey) { |
741 | 0 | unsigned char out[CURVE25519_LEN]; |
742 | 0 | const unsigned char* Q_C = NULL; |
743 | 0 | const unsigned char* Q_S = NULL; |
744 | 0 | char zeroes[CURVE25519_LEN] = {0}; |
745 | |
|
746 | 0 | if (buf_pub_them->len != CURVE25519_LEN) |
747 | 0 | { |
748 | 0 | dropbear_exit("Bad curve25519"); |
749 | 0 | } |
750 | | |
751 | 0 | dropbear_curve25519_scalarmult(out, param->priv, buf_pub_them->data); |
752 | |
|
753 | 0 | if (constant_time_memcmp(zeroes, out, CURVE25519_LEN) == 0) { |
754 | 0 | dropbear_exit("Bad curve25519"); |
755 | 0 | } |
756 | | |
757 | 0 | m_mp_alloc_init_multi(&ses.dh_K, NULL); |
758 | 0 | bytes_to_mp(ses.dh_K, out, CURVE25519_LEN); |
759 | 0 | m_burn(out, sizeof(out)); |
760 | | |
761 | | /* Create the remainder of the hash buffer, to generate the exchange hash. |
762 | | See RFC5656 section 4 page 7 */ |
763 | 0 | if (IS_DROPBEAR_CLIENT) { |
764 | 0 | Q_C = param->pub; |
765 | 0 | Q_S = buf_pub_them->data; |
766 | 0 | } else { |
767 | 0 | Q_S = param->pub; |
768 | 0 | Q_C = buf_pub_them->data; |
769 | 0 | } |
770 | | |
771 | | /* K_S, the host key */ |
772 | 0 | buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey); |
773 | | /* Q_C, client's ephemeral public key octet string */ |
774 | 0 | buf_putstring(ses.kexhashbuf, (const char*)Q_C, CURVE25519_LEN); |
775 | | /* Q_S, server's ephemeral public key octet string */ |
776 | 0 | buf_putstring(ses.kexhashbuf, (const char*)Q_S, CURVE25519_LEN); |
777 | | /* K, the shared secret */ |
778 | 0 | buf_putmpint(ses.kexhashbuf, ses.dh_K); |
779 | | |
780 | | /* calculate the hash H to sign */ |
781 | 0 | finish_kexhashbuf(); |
782 | 0 | } |
783 | | #endif /* DROPBEAR_CURVE25519 */ |
784 | | |
785 | | |
786 | 0 | void finish_kexhashbuf(void) { |
787 | 0 | hash_state hs; |
788 | 0 | const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc; |
789 | |
|
790 | 0 | hash_desc->init(&hs); |
791 | 0 | buf_setpos(ses.kexhashbuf, 0); |
792 | 0 | hash_desc->process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len), |
793 | 0 | ses.kexhashbuf->len); |
794 | 0 | ses.hash = buf_new(hash_desc->hashsize); |
795 | 0 | hash_desc->done(&hs, buf_getwriteptr(ses.hash, hash_desc->hashsize)); |
796 | 0 | buf_setlen(ses.hash, hash_desc->hashsize); |
797 | |
|
798 | | #if defined(DEBUG_KEXHASH) && DEBUG_TRACE |
799 | | if (!debug_trace) { |
800 | | printhex("kexhashbuf", ses.kexhashbuf->data, ses.kexhashbuf->len); |
801 | | printhex("kexhash", ses.hash->data, ses.hash->len); |
802 | | } |
803 | | #endif |
804 | |
|
805 | 0 | buf_burn_free(ses.kexhashbuf); |
806 | 0 | m_burn(&hs, sizeof(hash_state)); |
807 | 0 | ses.kexhashbuf = NULL; |
808 | | |
809 | | /* first time around, we set the session_id to H */ |
810 | 0 | if (ses.session_id == NULL) { |
811 | | /* create the session_id, this never needs freeing */ |
812 | 0 | ses.session_id = buf_newcopy(ses.hash); |
813 | 0 | } |
814 | 0 | } |
815 | | |
816 | | /* read the other side's algo list. buf_match_algo is a callback to match |
817 | | * algos for the client or server. */ |
818 | 330 | static void read_kex_algos() { |
819 | | |
820 | | /* for asymmetry */ |
821 | 330 | algo_type * c2s_hash_algo = NULL; |
822 | 330 | algo_type * s2c_hash_algo = NULL; |
823 | 330 | algo_type * c2s_cipher_algo = NULL; |
824 | 330 | algo_type * s2c_cipher_algo = NULL; |
825 | 330 | algo_type * c2s_comp_algo = NULL; |
826 | 330 | algo_type * s2c_comp_algo = NULL; |
827 | | /* the generic one */ |
828 | 330 | algo_type * algo = NULL; |
829 | | |
830 | | /* which algo couldn't match */ |
831 | 330 | char * erralgo = NULL; |
832 | | |
833 | 330 | int goodguess = 0; |
834 | 330 | int allgood = 1; /* we AND this with each goodguess and see if its still |
835 | | true after */ |
836 | 330 | int kexguess2 = 0; |
837 | | |
838 | 330 | buf_incrpos(ses.payload, 16); /* start after the cookie */ |
839 | | |
840 | 330 | memset(ses.newkeys, 0x0, sizeof(*ses.newkeys)); |
841 | | |
842 | | /* kex_algorithms */ |
843 | 330 | #if DROPBEAR_KEXGUESS2 |
844 | 330 | if (buf_has_algo(ses.payload, KEXGUESS2_ALGO_NAME) == DROPBEAR_SUCCESS) { |
845 | 12 | kexguess2 = 1; |
846 | 12 | } |
847 | 330 | #endif |
848 | | |
849 | 330 | #if DROPBEAR_EXT_INFO |
850 | | /* Determine if SSH_MSG_EXT_INFO messages should be sent. |
851 | | Should be done for the first key exchange. Only required on server side |
852 | | for server-sig-algs */ |
853 | 330 | if (IS_DROPBEAR_SERVER) { |
854 | 277 | if (!ses.kexstate.donefirstkex) { |
855 | 277 | if (buf_has_algo(ses.payload, SSH_EXT_INFO_C) == DROPBEAR_SUCCESS) { |
856 | 14 | ses.allow_ext_info = 1; |
857 | 14 | } |
858 | 277 | } |
859 | 277 | } |
860 | 330 | #endif |
861 | | |
862 | 330 | algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess); |
863 | 330 | allgood &= goodguess; |
864 | 330 | if (algo == NULL || algo->data == NULL) { |
865 | | /* kexguess2, ext-info-c, ext-info-s should not match negotiation */ |
866 | 234 | erralgo = "kex"; |
867 | 234 | goto error; |
868 | 234 | } |
869 | 96 | TRACE(("kexguess2 %d", kexguess2)) |
870 | 96 | DEBUG3(("kex algo %s", algo->name)) |
871 | 96 | ses.newkeys->algo_kex = algo->data; |
872 | | |
873 | | /* server_host_key_algorithms */ |
874 | 96 | algo = buf_match_algo(ses.payload, sigalgs, kexguess2, &goodguess); |
875 | 96 | allgood &= goodguess; |
876 | 96 | if (algo == NULL) { |
877 | 16 | erralgo = "hostkey"; |
878 | 16 | goto error; |
879 | 16 | } |
880 | 80 | DEBUG2(("hostkey algo %s", algo->name)) |
881 | 80 | ses.newkeys->algo_signature = algo->val; |
882 | 80 | ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature); |
883 | | |
884 | | /* encryption_algorithms_client_to_server */ |
885 | 80 | c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL); |
886 | 80 | if (c2s_cipher_algo == NULL) { |
887 | 0 | erralgo = "enc c->s"; |
888 | 0 | goto error; |
889 | 0 | } |
890 | 80 | DEBUG2(("enc c2s is %s", c2s_cipher_algo->name)) |
891 | | |
892 | | /* encryption_algorithms_server_to_client */ |
893 | 80 | s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL); |
894 | 80 | if (s2c_cipher_algo == NULL) { |
895 | 0 | erralgo = "enc s->c"; |
896 | 0 | goto error; |
897 | 0 | } |
898 | 80 | DEBUG2(("enc s2c is %s", s2c_cipher_algo->name)) |
899 | | |
900 | | /* mac_algorithms_client_to_server */ |
901 | 80 | c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL); |
902 | 80 | #if DROPBEAR_AEAD_MODE |
903 | 80 | if (((struct dropbear_cipher_mode*)c2s_cipher_algo->mode)->aead_crypt != NULL) { |
904 | 0 | c2s_hash_algo = NULL; |
905 | 0 | } else |
906 | 80 | #endif |
907 | 80 | if (c2s_hash_algo == NULL) { |
908 | 0 | erralgo = "mac c->s"; |
909 | 0 | goto error; |
910 | 0 | } |
911 | 80 | DEBUG2(("hmac c2s is %s", c2s_hash_algo ? c2s_hash_algo->name : "<implicit>")) |
912 | | |
913 | | /* mac_algorithms_server_to_client */ |
914 | 80 | s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL); |
915 | 80 | #if DROPBEAR_AEAD_MODE |
916 | 80 | if (((struct dropbear_cipher_mode*)s2c_cipher_algo->mode)->aead_crypt != NULL) { |
917 | 0 | s2c_hash_algo = NULL; |
918 | 0 | } else |
919 | 80 | #endif |
920 | 80 | if (s2c_hash_algo == NULL) { |
921 | 0 | erralgo = "mac s->c"; |
922 | 0 | goto error; |
923 | 0 | } |
924 | 80 | DEBUG2(("hmac s2c is %s", s2c_hash_algo ? s2c_hash_algo->name : "<implicit>")) |
925 | | |
926 | | /* compression_algorithms_client_to_server */ |
927 | 80 | c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL); |
928 | 80 | if (c2s_comp_algo == NULL) { |
929 | 0 | erralgo = "comp c->s"; |
930 | 0 | goto error; |
931 | 0 | } |
932 | 80 | DEBUG2(("comp c2s is %s", c2s_comp_algo->name)) |
933 | | |
934 | | /* compression_algorithms_server_to_client */ |
935 | 80 | s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL); |
936 | 80 | if (s2c_comp_algo == NULL) { |
937 | 0 | erralgo = "comp s->c"; |
938 | 0 | goto error; |
939 | 0 | } |
940 | 80 | DEBUG2(("comp s2c is %s", s2c_comp_algo->name)) |
941 | | |
942 | | /* languages_client_to_server */ |
943 | 80 | buf_eatstring(ses.payload); |
944 | | |
945 | | /* languages_server_to_client */ |
946 | 80 | buf_eatstring(ses.payload); |
947 | | |
948 | | /* their first_kex_packet_follows */ |
949 | 80 | if (buf_getbool(ses.payload)) { |
950 | 0 | TRACE(("them kex firstfollows. allgood %d", allgood)) |
951 | 0 | ses.kexstate.them_firstfollows = 1; |
952 | | /* if the guess wasn't good, we ignore the packet sent */ |
953 | 0 | if (!allgood) { |
954 | 0 | ses.ignorenext = 1; |
955 | 0 | } |
956 | 0 | } |
957 | | |
958 | | /* Handle the asymmetry */ |
959 | 80 | if (IS_DROPBEAR_CLIENT) { |
960 | 0 | ses.newkeys->recv.algo_crypt = |
961 | 0 | (struct dropbear_cipher*)s2c_cipher_algo->data; |
962 | 0 | ses.newkeys->trans.algo_crypt = |
963 | 0 | (struct dropbear_cipher*)c2s_cipher_algo->data; |
964 | 0 | ses.newkeys->recv.crypt_mode = |
965 | 0 | (struct dropbear_cipher_mode*)s2c_cipher_algo->mode; |
966 | 0 | ses.newkeys->trans.crypt_mode = |
967 | 0 | (struct dropbear_cipher_mode*)c2s_cipher_algo->mode; |
968 | 0 | ses.newkeys->recv.algo_mac = |
969 | 0 | #if DROPBEAR_AEAD_MODE |
970 | 0 | s2c_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac : |
971 | 0 | #endif |
972 | 0 | (struct dropbear_hash*)s2c_hash_algo->data; |
973 | 0 | ses.newkeys->trans.algo_mac = |
974 | 0 | #if DROPBEAR_AEAD_MODE |
975 | 0 | c2s_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac : |
976 | 0 | #endif |
977 | 0 | (struct dropbear_hash*)c2s_hash_algo->data; |
978 | 0 | ses.newkeys->recv.algo_comp = s2c_comp_algo->val; |
979 | 0 | ses.newkeys->trans.algo_comp = c2s_comp_algo->val; |
980 | 80 | } else { |
981 | | /* SERVER */ |
982 | 80 | ses.newkeys->recv.algo_crypt = |
983 | 80 | (struct dropbear_cipher*)c2s_cipher_algo->data; |
984 | 80 | ses.newkeys->trans.algo_crypt = |
985 | 80 | (struct dropbear_cipher*)s2c_cipher_algo->data; |
986 | 80 | ses.newkeys->recv.crypt_mode = |
987 | 80 | (struct dropbear_cipher_mode*)c2s_cipher_algo->mode; |
988 | 80 | ses.newkeys->trans.crypt_mode = |
989 | 80 | (struct dropbear_cipher_mode*)s2c_cipher_algo->mode; |
990 | 80 | ses.newkeys->recv.algo_mac = |
991 | 80 | #if DROPBEAR_AEAD_MODE |
992 | 80 | c2s_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac : |
993 | 80 | #endif |
994 | 80 | (struct dropbear_hash*)c2s_hash_algo->data; |
995 | 80 | ses.newkeys->trans.algo_mac = |
996 | 80 | #if DROPBEAR_AEAD_MODE |
997 | 80 | s2c_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac : |
998 | 80 | #endif |
999 | 80 | (struct dropbear_hash*)s2c_hash_algo->data; |
1000 | 80 | ses.newkeys->recv.algo_comp = c2s_comp_algo->val; |
1001 | 80 | ses.newkeys->trans.algo_comp = s2c_comp_algo->val; |
1002 | 80 | } |
1003 | | |
1004 | 80 | #if DROPBEAR_FUZZ |
1005 | 80 | if (fuzz.fuzzing) { |
1006 | 0 | fuzz_kex_fakealgos(); |
1007 | 0 | } |
1008 | 80 | #endif |
1009 | | |
1010 | | /* reserved for future extensions */ |
1011 | 80 | buf_getint(ses.payload); |
1012 | | |
1013 | 80 | if (ses.send_kex_first_guess && allgood) { |
1014 | 0 | TRACE(("our_first_follows_matches 1")) |
1015 | 0 | ses.kexstate.our_first_follows_matches = 1; |
1016 | 0 | } |
1017 | 80 | return; |
1018 | | |
1019 | 250 | error: |
1020 | 250 | dropbear_exit("No matching algo %s", erralgo); |
1021 | 80 | } |