common-kex.c 25 KB
Newer Older
1
/*
2
 * Dropbear SSH
3
 * 
Matt Johnston's avatar
Matt Johnston committed
4
 * Copyright (c) 2002-2004 Matt Johnston
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 * Portions Copyright (c) 2004 by Mihnea Stoenescu
 * All rights reserved.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. */

#include "includes.h"
#include "dbutil.h"
#include "algo.h"
#include "buffer.h"
#include "session.h"
#include "kex.h"
#include "ssh.h"
#include "packet.h"
#include "bignum.h"
#include "random.h"
36
#include "runopts.h"
37
38

/* diffie-hellman-group1-sha1 value for p */
39
40
#define DH_P_1_LEN 128
static const unsigned char dh_p_1[DH_P_1_LEN] = {
41
42
43
44
45
46
47
48
49
50
51
52
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
    0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
	0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
	0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
	0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
	0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/* diffie-hellman-group14-sha1 value for p */
#define DH_P_14_LEN 256
static const unsigned char dh_p_14[DH_P_14_LEN] = {
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 
    0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 
	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
	0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
	0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
	0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
	0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
	0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
	0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
	0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
	0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2,
	0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
	0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C,
	0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
	0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF};

/* Same for group1 and group14 */
Matt Johnston's avatar
Matt Johnston committed
80
static const int DH_G_VAL = 2;
81

Matt Johnston's avatar
Matt Johnston committed
82
static void kexinitialise();
Matt Johnston's avatar
Matt Johnston committed
83
void gen_new_keys();
84
85
86
#ifndef DISABLE_ZLIB
static void gen_new_zstreams();
#endif
Matt Johnston's avatar
Matt Johnston committed
87
static void read_kex_algos();
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/* helper function for gen_new_keys */
static void hashkeys(unsigned char *out, int outlen, 
		const hash_state * hs, unsigned const char X);


/* Send our list of algorithms we can use */
void send_msg_kexinit() {

	CHECKCLEARTOWRITE();
	buf_putbyte(ses.writepayload, SSH_MSG_KEXINIT);

	/* cookie */
	genrandom(buf_getwriteptr(ses.writepayload, 16), 16);
	buf_incrwritepos(ses.writepayload, 16);

	/* kex algos */
	buf_put_algolist(ses.writepayload, sshkex);

	/* server_host_key_algorithms */
	buf_put_algolist(ses.writepayload, sshhostkey);

	/* encryption_algorithms_client_to_server */
	buf_put_algolist(ses.writepayload, sshciphers);

	/* encryption_algorithms_server_to_client */
	buf_put_algolist(ses.writepayload, sshciphers);

	/* mac_algorithms_client_to_server */
	buf_put_algolist(ses.writepayload, sshhashes);

	/* mac_algorithms_server_to_client */
	buf_put_algolist(ses.writepayload, sshhashes);


	/* compression_algorithms_client_to_server */
123
	buf_put_algolist(ses.writepayload, ses.compress_algos);
124
125

	/* compression_algorithms_server_to_client */
126
	buf_put_algolist(ses.writepayload, ses.compress_algos);
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146

	/* languages_client_to_server */
	buf_putstring(ses.writepayload, "", 0);

	/* languages_server_to_client */
	buf_putstring(ses.writepayload, "", 0);

	/* first_kex_packet_follows - unimplemented for now */
	buf_putbyte(ses.writepayload, 0x00);

	/* reserved unit32 */
	buf_putint(ses.writepayload, 0);

	/* set up transmitted kex packet buffer for hashing. 
	 * This is freed after the end of the kex */
	ses.transkexinit = buf_newcopy(ses.writepayload);

	encrypt_packet();
	ses.dataallowed = 0; /* don't send other packets during kex */

147
148
	TRACE(("DATAALLOWED=0"))
	TRACE(("-> KEXINIT"))
149
150
151
152
153
154
155
156
157
158
159
160
	ses.kexstate.sentkexinit = 1;
}

/* *** NOTE regarding (send|recv)_msg_newkeys *** 
 * Changed by mihnea from the original kex.c to set dataallowed after a 
 * completed key exchange, no matter the order in which it was performed.
 * This enables client mode without affecting server functionality.
 */

/* Bring new keys into use after a key exchange, and let the client know*/
void send_msg_newkeys() {

161
	TRACE(("enter send_msg_newkeys"))
162
163
164
165
166
167
168
169
170

	/* generate the kexinit request */
	CHECKCLEARTOWRITE();
	buf_putbyte(ses.writepayload, SSH_MSG_NEWKEYS);
	encrypt_packet();
	

	/* set up our state */
	if (ses.kexstate.recvnewkeys) {
171
		TRACE(("while RECVNEWKEYS=1"))
172
173
		gen_new_keys();
		kexinitialise(); /* we've finished with this kex */
174
		TRACE((" -> DATAALLOWED=1"))
175
		ses.dataallowed = 1; /* we can send other packets again now */
Matt Johnston's avatar
Matt Johnston committed
176
		ses.kexstate.donefirstkex = 1;
177
178
	} else {
		ses.kexstate.sentnewkeys = 1;
179
		TRACE(("SENTNEWKEYS=1"))
180
181
	}

182
183
	TRACE(("-> MSG_NEWKEYS"))
	TRACE(("leave send_msg_newkeys"))
184
185
186
187
188
}

/* Bring the new keys into use after a key exchange */
void recv_msg_newkeys() {

189
190
	TRACE(("<- MSG_NEWKEYS"))
	TRACE(("enter recv_msg_newkeys"))
191
192
193
194

	/* simply check if we've sent SSH_MSG_NEWKEYS, and if so,
	 * switch to the new keys */
	if (ses.kexstate.sentnewkeys) {
195
		TRACE(("while SENTNEWKEYS=1"))
196
197
		gen_new_keys();
		kexinitialise(); /* we've finished with this kex */
198
	    TRACE((" -> DATAALLOWED=1"))
199
	    ses.dataallowed = 1; /* we can send other packets again now */
Matt Johnston's avatar
Matt Johnston committed
200
		ses.kexstate.donefirstkex = 1;
201
	} else {
202
		TRACE(("RECVNEWKEYS=1"))
203
204
205
		ses.kexstate.recvnewkeys = 1;
	}
	
206
	TRACE(("leave recv_msg_newkeys"))
207
208
209
}


Matt Johnston's avatar
Matt Johnston committed
210
211
212
/* Set up the kex for the first time */
void kexfirstinitialise() {
	ses.kexstate.donefirstkex = 0;
213
214
215
216
217
218
219
220
221

#ifndef DISABLE_ZLIB
	if (opts.enable_compress) {
		ses.compress_algos = ssh_compress;
	} else
#endif
	{
		ses.compress_algos = ssh_nocompress;
	}
Matt Johnston's avatar
Matt Johnston committed
222
223
224
225
226
	kexinitialise();
}

/* Reset the kex state, ready for a new negotiation */
static void kexinitialise() {
227

228
	TRACE(("kexinitialise()"))
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243

	/* sent/recv'd MSG_KEXINIT */
	ses.kexstate.sentkexinit = 0;
	ses.kexstate.recvkexinit = 0;

	/* sent/recv'd MSG_NEWKEYS */
	ses.kexstate.recvnewkeys = 0;
	ses.kexstate.sentnewkeys = 0;

	/* first_packet_follows */
	ses.kexstate.firstfollows = 0;

	ses.kexstate.datatrans = 0;
	ses.kexstate.datarecv = 0;

244
	ses.kexstate.lastkextime = time(NULL);
245
246
247
248
249
250
251
252

}

/* Helper function for gen_new_keys, creates a hash. It makes a copy of the
 * already initialised hash_state hs, which should already have processed
 * the dh_K and hash, since these are common. X is the letter 'A', 'B' etc.
 * out must have at least min(SHA1_HASH_SIZE, outlen) bytes allocated.
 *
253
 * See Section 7.2 of rfc4253 (ssh transport) for details */
254
255
256
257
static void hashkeys(unsigned char *out, int outlen, 
		const hash_state * hs, const unsigned char X) {

	hash_state hs2;
258
	int offset;
259
260
261
262
263

	memcpy(&hs2, hs, sizeof(hash_state));
	sha1_process(&hs2, &X, 1);
	sha1_process(&hs2, ses.session_id, SHA1_HASH_SIZE);
	sha1_done(&hs2, out);
264
265
266
267
	for (offset = SHA1_HASH_SIZE; 
			offset < outlen; 
			offset += SHA1_HASH_SIZE)
	{
268
		/* need to extend */
269
		unsigned char k2[SHA1_HASH_SIZE];
270
		memcpy(&hs2, hs, sizeof(hash_state));
271
		sha1_process(&hs2, out, offset);
272
		sha1_done(&hs2, k2);
273
		memcpy(&out[offset], k2, MIN(outlen - offset, SHA1_HASH_SIZE));
274
275
276
277
	}
}

/* Generate the actual encryption/integrity keys, using the results of the
278
279
 * key exchange, as specified in section 7.2 of the transport rfc 4253.
 * This occurs after the DH key-exchange.
280
281
282
283
284
 *
 * ses.newkeys is the new set of keys which are generated, these are only
 * taken into use after both sides have sent a newkeys message */

/* Originally from kex.c, generalized for cli/svr mode --mihnea */
Matt Johnston's avatar
Matt Johnston committed
285
void gen_new_keys() {
286
287
288
289
290
291
292
293
294
295
296
297

	unsigned char C2S_IV[MAX_IV_LEN];
	unsigned char C2S_key[MAX_KEY_LEN];
	unsigned char S2C_IV[MAX_IV_LEN];
	unsigned char S2C_key[MAX_KEY_LEN];
	/* unsigned char key[MAX_KEY_LEN]; */
	unsigned char *trans_IV, *trans_key, *recv_IV, *recv_key;

	hash_state hs;
	unsigned int C2S_keysize, S2C_keysize;
	char mactransletter, macrecvletter; /* Client or server specific */

298
	TRACE(("enter gen_new_keys"))
299
300
301
302
303
304
305
306
307
308
309
310
311
312
	/* the dh_K and hash are the start of all hashes, we make use of that */

	sha1_init(&hs);
	sha1_process_mp(&hs, ses.dh_K);
	mp_clear(ses.dh_K);
	m_free(ses.dh_K);
	sha1_process(&hs, ses.hash, SHA1_HASH_SIZE);
	m_burn(ses.hash, SHA1_HASH_SIZE);

	if (IS_DROPBEAR_CLIENT) {
	    trans_IV	= C2S_IV;
	    recv_IV		= S2C_IV;
	    trans_key	= C2S_key;
	    recv_key	= S2C_key;
313
314
	    C2S_keysize = ses.newkeys->trans.algo_crypt->keysize;
	    S2C_keysize = ses.newkeys->recv.algo_crypt->keysize;
315
316
317
318
319
320
321
		mactransletter = 'E';
		macrecvletter = 'F';
	} else {
	    trans_IV	= S2C_IV;
	    recv_IV		= C2S_IV;
	    trans_key	= S2C_key;
	    recv_key	= C2S_key;
322
323
	    C2S_keysize = ses.newkeys->recv.algo_crypt->keysize;
	    S2C_keysize = ses.newkeys->trans.algo_crypt->keysize;
324
325
326
327
		mactransletter = 'F';
		macrecvletter = 'E';
	}

Matt Johnston's avatar
Matt Johnston committed
328
329
	hashkeys(C2S_IV, SHA1_HASH_SIZE, &hs, 'A');
	hashkeys(S2C_IV, SHA1_HASH_SIZE, &hs, 'B');
330
331
332
	hashkeys(C2S_key, C2S_keysize, &hs, 'C');
	hashkeys(S2C_key, S2C_keysize, &hs, 'D');

333
334
	if (ses.newkeys->recv.algo_crypt->cipherdesc != NULL) {
		int recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
335
		if (recv_cipher < 0)
336
337
			dropbear_exit("Crypto error");
		if (ses.newkeys->recv.crypt_mode->start(recv_cipher, 
338
				recv_IV, recv_key, 
339
340
341
				ses.newkeys->recv.algo_crypt->keysize, 0, 
				&ses.newkeys->recv.cipher_state) != CRYPT_OK) {
			dropbear_exit("Crypto error");
342
		}
343
	}
Matt Johnston's avatar
Matt Johnston committed
344

345
346
	if (ses.newkeys->trans.algo_crypt->cipherdesc != NULL) {
		int trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
347
		if (trans_cipher < 0)
348
349
			dropbear_exit("Crypto error");
		if (ses.newkeys->trans.crypt_mode->start(trans_cipher, 
350
				trans_IV, trans_key, 
351
352
353
				ses.newkeys->trans.algo_crypt->keysize, 0, 
				&ses.newkeys->trans.cipher_state) != CRYPT_OK) {
			dropbear_exit("Crypto error");
354
		}
355
	}
356

357
358
359
	if (ses.newkeys->trans.algo_mac->hashdesc != NULL) {
		hashkeys(ses.newkeys->trans.mackey, 
				ses.newkeys->trans.algo_mac->keysize, &hs, mactransletter);
360
		ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hashdesc->name);
361
	}
362

363
364
365
	if (ses.newkeys->recv.algo_mac->hashdesc != NULL) {
		hashkeys(ses.newkeys->recv.mackey, 
				ses.newkeys->recv.algo_mac->keysize, &hs, macrecvletter);
366
		ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hashdesc->name);
367
	}
368
369
370
371
372
373
374
375
376
377
378

#ifndef DISABLE_ZLIB
	gen_new_zstreams();
#endif
	
	/* Switch over to the new keys */
	m_burn(ses.keys, sizeof(struct key_context));
	m_free(ses.keys);
	ses.keys = ses.newkeys;
	ses.newkeys = NULL;

379
380
381
382
383
	m_burn(C2S_IV, sizeof(C2S_IV));
	m_burn(C2S_key, sizeof(C2S_key));
	m_burn(S2C_IV, sizeof(S2C_IV));
	m_burn(S2C_key, sizeof(S2C_key));

384
	TRACE(("leave gen_new_keys"))
385
386
387
}

#ifndef DISABLE_ZLIB
388
389

int is_compress_trans() {
390
	return ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB
391
		|| (ses.authstate.authdone
392
			&& ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
393
394
395
}

int is_compress_recv() {
396
	return ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB
397
		|| (ses.authstate.authdone
398
			&& ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
399
400
}

401
402
403
404
405
/* Set up new zlib compression streams, close the old ones. Only
 * called from gen_new_keys() */
static void gen_new_zstreams() {

	/* create new zstreams */
406
407
408
409
410
	if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB
			|| ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
		ses.newkeys->recv.zstream = (z_streamp)m_malloc(sizeof(z_stream));
		ses.newkeys->recv.zstream->zalloc = Z_NULL;
		ses.newkeys->recv.zstream->zfree = Z_NULL;
411
		
412
		if (inflateInit(ses.newkeys->recv.zstream) != Z_OK) {
413
414
415
			dropbear_exit("zlib error");
		}
	} else {
416
		ses.newkeys->recv.zstream = NULL;
417
418
	}

419
420
421
422
423
	if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB
			|| ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
		ses.newkeys->trans.zstream = (z_streamp)m_malloc(sizeof(z_stream));
		ses.newkeys->trans.zstream->zalloc = Z_NULL;
		ses.newkeys->trans.zstream->zfree = Z_NULL;
424
	
425
426
427
		if (deflateInit2(ses.newkeys->trans.zstream, Z_DEFAULT_COMPRESSION,
					Z_DEFLATED, DROPBEAR_ZLIB_WINDOW_BITS, 
					DROPBEAR_ZLIB_MEM_LEVEL, Z_DEFAULT_STRATEGY)
428
429
430
431
				!= Z_OK) {
			dropbear_exit("zlib error");
		}
	} else {
432
		ses.newkeys->trans.zstream = NULL;
433
	}
434

435
	/* clean up old keys */
436
437
	if (ses.keys->recv.zstream != NULL) {
		if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
438
			/* Z_DATA_ERROR is ok, just means that stream isn't ended */
439
			dropbear_exit("Crypto error");
440
		}
441
		m_free(ses.keys->recv.zstream);
442
	}
443
444
	if (ses.keys->trans.zstream != NULL) {
		if (deflateEnd(ses.keys->trans.zstream) == Z_STREAM_ERROR) {
445
			/* Z_DATA_ERROR is ok, just means that stream isn't ended */
446
			dropbear_exit("Crypto error");
447
		}
448
		m_free(ses.keys->trans.zstream);
449
450
	}
}
451
#endif /* DISABLE_ZLIB */
452
453
454
455
456
457
458
459
460
461
462
463
464


/* Executed upon receiving a kexinit message from the client to initiate
 * key exchange. If we haven't already done so, we send the list of our
 * preferred algorithms. The client's requested algorithms are processed,
 * and we calculate the first portion of the key-exchange-hash for used
 * later in the key exchange. No response is sent, as the client should
 * initiate the diffie-hellman key exchange */

/* Originally from kex.c, generalized for cli/svr mode --mihnea  */
/* Belongs in common_kex.c where it should be moved after review */
void recv_msg_kexinit() {
	
465
466
467
468
	unsigned int kexhashbuf_len = 0;
	unsigned int remote_ident_len = 0;
	unsigned int local_ident_len = 0;

469
470
	TRACE(("<- KEXINIT"))
	TRACE(("enter recv_msg_kexinit"))
471
472
473
474
	
	if (!ses.kexstate.sentkexinit) {
		/* we need to send a kex packet */
		send_msg_kexinit();
475
		TRACE(("continue recv_msg_kexinit: sent kexinit"))
476
477
	}

478
479
480
481
482
483
484
485
486
	/* start the kex hash */
	local_ident_len = strlen(LOCAL_IDENT);
	remote_ident_len = strlen((char*)ses.remoteident);

	kexhashbuf_len = local_ident_len + remote_ident_len
		+ ses.transkexinit->len + ses.payload->len
		+ KEXHASHBUF_MAX_INTS;

	ses.kexhashbuf = buf_new(kexhashbuf_len);
487
488
489

	if (IS_DROPBEAR_CLIENT) {

Matt Johnston's avatar
Matt Johnston committed
490
		/* read the peer's choice of algos */
Matt Johnston's avatar
Matt Johnston committed
491
		read_kex_algos();
492

Matt Johnston's avatar
Matt Johnston committed
493
		/* V_C, the client's version string (CR and NL excluded) */
494
	    buf_putstring(ses.kexhashbuf,
495
			(unsigned char*)LOCAL_IDENT, local_ident_len);
Matt Johnston's avatar
Matt Johnston committed
496
		/* V_S, the server's version string (CR and NL excluded) */
497
	    buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
498

Matt Johnston's avatar
Matt Johnston committed
499
		/* I_C, the payload of the client's SSH_MSG_KEXINIT */
500
	    buf_putstring(ses.kexhashbuf,
501
			ses.transkexinit->data, ses.transkexinit->len);
Matt Johnston's avatar
Matt Johnston committed
502
		/* I_S, the payload of the server's SSH_MSG_KEXINIT */
503
	    buf_setpos(ses.payload, 0);
504
	    buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len);
505
506

	} else {
Matt Johnston's avatar
Matt Johnston committed
507
		/* SERVER */
508

Matt Johnston's avatar
Matt Johnston committed
509
		/* read the peer's choice of algos */
Matt Johnston's avatar
Matt Johnston committed
510
		read_kex_algos();
Matt Johnston's avatar
Matt Johnston committed
511
		/* V_C, the client's version string (CR and NL excluded) */
512
	    buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
Matt Johnston's avatar
Matt Johnston committed
513
		/* V_S, the server's version string (CR and NL excluded) */
514
515
	    buf_putstring(ses.kexhashbuf, 
				(unsigned char*)LOCAL_IDENT, local_ident_len);
516

Matt Johnston's avatar
Matt Johnston committed
517
		/* I_C, the payload of the client's SSH_MSG_KEXINIT */
518
	    buf_setpos(ses.payload, 0);
519
520
	    buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len);

Matt Johnston's avatar
Matt Johnston committed
521
		/* I_S, the payload of the server's SSH_MSG_KEXINIT */
522
	    buf_putstring(ses.kexhashbuf,
523
524
			ses.transkexinit->data, ses.transkexinit->len);

Matt Johnston's avatar
Matt Johnston committed
525
		ses.requirenext = SSH_MSG_KEXDH_INIT;
526
527
528
529
530
531
532
533
	}

	buf_free(ses.transkexinit);
	ses.transkexinit = NULL;
	/* the rest of ses.kexhashbuf will be done after DH exchange */

	ses.kexstate.recvkexinit = 1;

534
	TRACE(("leave recv_msg_kexinit"))
535
536
}

537
538
539
540
541
542
543
544
545
546
547
548
static void load_dh_p(mp_int * dh_p)
{
	switch (ses.newkeys->algo_kex) {
		case DROPBEAR_KEX_DH_GROUP1:
			bytes_to_mp(dh_p, dh_p_1, DH_P_1_LEN);
			break;
		case DROPBEAR_KEX_DH_GROUP14:
			bytes_to_mp(dh_p, dh_p_14, DH_P_14_LEN);
			break;
	}
}

Matt Johnston's avatar
Matt Johnston committed
549
/* Initialises and generate one side of the diffie-hellman key exchange values.
550
 * See the transport rfc 4253 section 8 for details */
551
/* dh_pub and dh_priv MUST be already initialised */
Matt Johnston's avatar
Matt Johnston committed
552
553
void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {

554
555
556
	DEF_MP_INT(dh_p);
	DEF_MP_INT(dh_q);
	DEF_MP_INT(dh_g);
Matt Johnston's avatar
Matt Johnston committed
557

558
	TRACE(("enter send_msg_kexdh_reply"))
Matt Johnston's avatar
Matt Johnston committed
559
	
560
	m_mp_init_multi(&dh_g, &dh_p, &dh_q, NULL);
Matt Johnston's avatar
Matt Johnston committed
561
562

	/* read the prime and generator*/
563
	load_dh_p(&dh_p);
Matt Johnston's avatar
Matt Johnston committed
564
565
566
567
568
569
570
571
572
573
574
575
576
577
	
	if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) {
		dropbear_exit("Diffie-Hellman error");
	}

	/* calculate q = (p-1)/2 */
	/* dh_priv is just a temp var here */
	if (mp_sub_d(&dh_p, 1, dh_priv) != MP_OKAY) { 
		dropbear_exit("Diffie-Hellman error");
	}
	if (mp_div_2(dh_priv, &dh_q) != MP_OKAY) {
		dropbear_exit("Diffie-Hellman error");
	}

578
579
	/* Generate a private portion 0 < dh_priv < dh_q */
	gen_random_mpint(&dh_q, dh_priv);
Matt Johnston's avatar
Matt Johnston committed
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599

	/* f = g^y mod p */
	if (mp_exptmod(&dh_g, dh_priv, &dh_p, dh_pub) != MP_OKAY) {
		dropbear_exit("Diffie-Hellman error");
	}
	mp_clear_multi(&dh_g, &dh_p, &dh_q, NULL);
}

/* This function is fairly common between client/server, with some substitution
 * of dh_e/dh_f etc. Hence these arguments:
 * dh_pub_us is 'e' for the client, 'f' for the server. dh_pub_them is 
 * vice-versa. dh_priv is the x/y value corresponding to dh_pub_us */
void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
		sign_key *hostkey) {

	mp_int dh_p;
	mp_int *dh_e = NULL, *dh_f = NULL;
	hash_state hs;

	/* read the prime and generator*/
Matt Johnston's avatar
Matt Johnston committed
600
	m_mp_init(&dh_p);
601
	load_dh_p(&dh_p);
Matt Johnston's avatar
Matt Johnston committed
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644

	/* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */
	if (mp_cmp(dh_pub_them, &dh_p) != MP_LT 
			|| mp_cmp_d(dh_pub_them, 0) != MP_GT) {
		dropbear_exit("Diffie-Hellman error");
	}
	
	/* K = e^y mod p = f^x mod p */
	ses.dh_K = (mp_int*)m_malloc(sizeof(mp_int));
	m_mp_init(ses.dh_K);
	if (mp_exptmod(dh_pub_them, dh_priv, &dh_p, ses.dh_K) != MP_OKAY) {
		dropbear_exit("Diffie-Hellman error");
	}

	/* clear no longer needed vars */
	mp_clear_multi(&dh_p, NULL);

	/* From here on, the code needs to work with the _same_ vars on each side,
	 * not vice-versaing for client/server */
	if (IS_DROPBEAR_CLIENT) {
		dh_e = dh_pub_us;
		dh_f = dh_pub_them;
	} else {
		dh_e = dh_pub_them;
		dh_f = dh_pub_us;
	} 

	/* Create the remainder of the hash buffer, to generate the exchange hash */
	/* K_S, the host key */
	buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
	/* e, exchange value sent by the client */
	buf_putmpint(ses.kexhashbuf, dh_e);
	/* f, exchange value sent by the server */
	buf_putmpint(ses.kexhashbuf, dh_f);
	/* K, the shared secret */
	buf_putmpint(ses.kexhashbuf, ses.dh_K);

	/* calculate the hash H to sign */
	sha1_init(&hs);
	buf_setpos(ses.kexhashbuf, 0);
	sha1_process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len),
			ses.kexhashbuf->len);
	sha1_done(&hs, ses.hash);
Matt Johnston's avatar
Matt Johnston committed
645
646

	buf_burn(ses.kexhashbuf);
Matt Johnston's avatar
Matt Johnston committed
647
648
649
650
651
652
653
654
655
656
657
658
659
	buf_free(ses.kexhashbuf);
	ses.kexhashbuf = NULL;
	
	/* first time around, we set the session_id to H */
	if (ses.session_id == NULL) {
		/* create the session_id, this never needs freeing */
		ses.session_id = (unsigned char*)m_malloc(SHA1_HASH_SIZE);
		memcpy(ses.session_id, ses.hash, SHA1_HASH_SIZE);
	}
}

/* read the other side's algo list. buf_match_algo is a callback to match
 * algos for the client or server. */
Matt Johnston's avatar
Matt Johnston committed
660
static void read_kex_algos() {
Matt Johnston's avatar
Matt Johnston committed
661

662
663
664
665
666
667
668
669
670
671
672
	/* for asymmetry */
	algo_type * c2s_hash_algo = NULL;
	algo_type * s2c_hash_algo = NULL;
	algo_type * c2s_cipher_algo = NULL;
	algo_type * s2c_cipher_algo = NULL;
	algo_type * c2s_comp_algo = NULL;
	algo_type * s2c_comp_algo = NULL;
	/* the generic one */
	algo_type * algo = NULL;

	/* which algo couldn't match */
Matt Johnston's avatar
Matt Johnston committed
673
674
675
676
677
678
679
680
681
682
683
	char * erralgo = NULL;

	int goodguess = 0;
	int allgood = 1; /* we AND this with each goodguess and see if its still
						true after */

	buf_incrpos(ses.payload, 16); /* start after the cookie */

	ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));

	/* kex_algorithms */
Matt Johnston's avatar
Matt Johnston committed
684
	algo = ses.buf_match_algo(ses.payload, sshkex, &goodguess);
Matt Johnston's avatar
Matt Johnston committed
685
686
687
688
689
	allgood &= goodguess;
	if (algo == NULL) {
		erralgo = "kex";
		goto error;
	}
690
	TRACE(("kex algo %s", algo->name))
Matt Johnston's avatar
Matt Johnston committed
691
692
693
	ses.newkeys->algo_kex = algo->val;

	/* server_host_key_algorithms */
Matt Johnston's avatar
Matt Johnston committed
694
	algo = ses.buf_match_algo(ses.payload, sshhostkey, &goodguess);
Matt Johnston's avatar
Matt Johnston committed
695
696
697
698
699
	allgood &= goodguess;
	if (algo == NULL) {
		erralgo = "hostkey";
		goto error;
	}
700
	TRACE(("hostkey algo %s", algo->name))
Matt Johnston's avatar
Matt Johnston committed
701
702
703
	ses.newkeys->algo_hostkey = algo->val;

	/* encryption_algorithms_client_to_server */
704
	c2s_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
705
	if (c2s_cipher_algo == NULL) {
Matt Johnston's avatar
Matt Johnston committed
706
707
708
		erralgo = "enc c->s";
		goto error;
	}
709
	TRACE(("enc c2s is  %s", c2s_cipher_algo->name))
Matt Johnston's avatar
Matt Johnston committed
710
711

	/* encryption_algorithms_server_to_client */
712
	s2c_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
713
	if (s2c_cipher_algo == NULL) {
Matt Johnston's avatar
Matt Johnston committed
714
715
716
		erralgo = "enc s->c";
		goto error;
	}
717
	TRACE(("enc s2c is  %s", s2c_cipher_algo->name))
Matt Johnston's avatar
Matt Johnston committed
718
719

	/* mac_algorithms_client_to_server */
720
	c2s_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
721
	if (c2s_hash_algo == NULL) {
Matt Johnston's avatar
Matt Johnston committed
722
723
724
		erralgo = "mac c->s";
		goto error;
	}
725
	TRACE(("hash c2s is  %s", c2s_hash_algo->name))
Matt Johnston's avatar
Matt Johnston committed
726
727

	/* mac_algorithms_server_to_client */
728
	s2c_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
729
	if (s2c_hash_algo == NULL) {
Matt Johnston's avatar
Matt Johnston committed
730
731
732
		erralgo = "mac s->c";
		goto error;
	}
733
	TRACE(("hash s2c is  %s", s2c_hash_algo->name))
Matt Johnston's avatar
Matt Johnston committed
734
735

	/* compression_algorithms_client_to_server */
736
	c2s_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, &goodguess);
737
	if (c2s_comp_algo == NULL) {
Matt Johnston's avatar
Matt Johnston committed
738
739
740
		erralgo = "comp c->s";
		goto error;
	}
741
	TRACE(("hash c2s is  %s", c2s_comp_algo->name))
Matt Johnston's avatar
Matt Johnston committed
742
743

	/* compression_algorithms_server_to_client */
744
	s2c_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, &goodguess);
745
	if (s2c_comp_algo == NULL) {
Matt Johnston's avatar
Matt Johnston committed
746
747
748
		erralgo = "comp s->c";
		goto error;
	}
749
	TRACE(("hash s2c is  %s", s2c_comp_algo->name))
Matt Johnston's avatar
Matt Johnston committed
750
751
752
753
754
755
756
757

	/* languages_client_to_server */
	buf_eatstring(ses.payload);

	/* languages_server_to_client */
	buf_eatstring(ses.payload);

	/* first_kex_packet_follows */
758
	if (buf_getbool(ses.payload)) {
Matt Johnston's avatar
Matt Johnston committed
759
760
761
762
763
764
765
		ses.kexstate.firstfollows = 1;
		/* if the guess wasn't good, we ignore the packet sent */
		if (!allgood) {
			ses.ignorenext = 1;
		}
	}

766
767
	/* Handle the asymmetry */
	if (IS_DROPBEAR_CLIENT) {
768
		ses.newkeys->recv.algo_crypt = 
769
			(struct dropbear_cipher*)s2c_cipher_algo->data;
770
		ses.newkeys->trans.algo_crypt = 
771
			(struct dropbear_cipher*)c2s_cipher_algo->data;
772
		ses.newkeys->recv.crypt_mode = 
Matt Johnston's avatar
Matt Johnston committed
773
			(struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
774
		ses.newkeys->trans.crypt_mode =
Matt Johnston's avatar
Matt Johnston committed
775
			(struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
776
		ses.newkeys->recv.algo_mac = 
777
			(struct dropbear_hash*)s2c_hash_algo->data;
778
		ses.newkeys->trans.algo_mac = 
779
			(struct dropbear_hash*)c2s_hash_algo->data;
780
781
		ses.newkeys->recv.algo_comp = s2c_comp_algo->val;
		ses.newkeys->trans.algo_comp = c2s_comp_algo->val;
782
783
	} else {
		/* SERVER */
784
		ses.newkeys->recv.algo_crypt = 
785
			(struct dropbear_cipher*)c2s_cipher_algo->data;
786
		ses.newkeys->trans.algo_crypt = 
787
			(struct dropbear_cipher*)s2c_cipher_algo->data;
788
		ses.newkeys->recv.crypt_mode =
Matt Johnston's avatar
Matt Johnston committed
789
			(struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
790
		ses.newkeys->trans.crypt_mode =
Matt Johnston's avatar
Matt Johnston committed
791
			(struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
792
		ses.newkeys->recv.algo_mac = 
793
			(struct dropbear_hash*)c2s_hash_algo->data;
794
		ses.newkeys->trans.algo_mac = 
795
			(struct dropbear_hash*)s2c_hash_algo->data;
796
797
		ses.newkeys->recv.algo_comp = c2s_comp_algo->val;
		ses.newkeys->trans.algo_comp = s2c_comp_algo->val;
798
799
	}

Matt Johnston's avatar
Matt Johnston committed
800
801
802
803
804
	/* reserved for future extensions */
	buf_getint(ses.payload);
	return;

error:
805
	dropbear_exit("No matching algo %s", erralgo);
Matt Johnston's avatar
Matt Johnston committed
806
}