kex.c revision 60573
1/*
2 * Copyright (c) 2000 Markus Friedl.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 * 3. All advertising materials mentioning features or use of this software
13 *    must display the following acknowledgement:
14 *      This product includes software developed by Markus Friedl.
15 * 4. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "includes.h"
31RCSID("$Id: kex.c,v 1.6 2000/05/08 17:42:25 markus Exp $");
32
33#include "ssh.h"
34#include "ssh2.h"
35#include "xmalloc.h"
36#include "buffer.h"
37#include "bufaux.h"
38#include "cipher.h"
39#include "compat.h"
40
41#include <openssl/bn.h>
42#include <openssl/dh.h>
43
44#include <openssl/crypto.h>
45#include <openssl/bio.h>
46#include <openssl/bn.h>
47#include <openssl/dh.h>
48#include <openssl/pem.h>
49
50#include "kex.h"
51
52Buffer *
53kex_init(char *myproposal[PROPOSAL_MAX])
54{
55	char c = 0;
56	unsigned char cookie[16];
57	u_int32_t rand = 0;
58	int i;
59	Buffer *ki = xmalloc(sizeof(*ki));
60	for (i = 0; i < 16; i++) {
61		if (i % 4 == 0)
62			rand = arc4random();
63		cookie[i] = rand & 0xff;
64		rand >>= 8;
65	}
66	buffer_init(ki);
67	buffer_append(ki, (char *)cookie, sizeof cookie);
68	for (i = 0; i < PROPOSAL_MAX; i++)
69		buffer_put_cstring(ki, myproposal[i]);
70	buffer_append(ki, &c, 1); /* boolean   first_kex_packet_follows */
71	buffer_put_int(ki, 0);    /* uint32    0 (reserved for future extension) */
72	return ki;
73}
74
75/* diffie-hellman-group1-sha1 */
76
77int
78dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
79{
80	int i;
81	int n = BN_num_bits(dh_pub);
82	int bits_set = 0;
83
84	/* we only accept g==2 */
85	if (!BN_is_word(dh->g, 2)) {
86		log("invalid DH base != 2");
87		return 0;
88	}
89	if (dh_pub->neg) {
90		log("invalid public DH value: negativ");
91		return 0;
92	}
93	for (i = 0; i <= n; i++)
94		if (BN_is_bit_set(dh_pub, i))
95			bits_set++;
96	debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
97
98	/* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
99	if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
100		return 1;
101	log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
102	return 0;
103}
104
105DH *
106dh_new_group1()
107{
108	static char *group1 =
109	    "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
110	    "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
111	    "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
112	    "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
113	    "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
114	    "FFFFFFFF" "FFFFFFFF";
115	DH *dh;
116	int ret, tries = 0;
117	dh = DH_new();
118	if(dh == NULL)
119		fatal("DH_new");
120	ret = BN_hex2bn(&dh->p, group1);
121	if(ret<0)
122		fatal("BN_hex2bn");
123	dh->g = BN_new();
124	if(dh->g == NULL)
125		fatal("DH_new g");
126	BN_set_word(dh->g, 2);
127	do {
128		if (DH_generate_key(dh) == 0)
129			fatal("DH_generate_key");
130		if (tries++ > 10)
131			fatal("dh_new_group1: too many bad keys: giving up");
132	} while (!dh_pub_is_valid(dh, dh->pub_key));
133	return dh;
134}
135
136void
137bignum_print(BIGNUM *b)
138{
139	BN_print_fp(stderr,b);
140}
141
142void
143dump_digest(unsigned char *digest, int len)
144{
145	int i;
146	for (i = 0; i< len; i++){
147		fprintf(stderr, "%02x", digest[i]);
148		if(i%2!=0)
149			fprintf(stderr, " ");
150	}
151	fprintf(stderr, "\n");
152}
153
154unsigned char *
155kex_hash(
156    char *client_version_string,
157    char *server_version_string,
158    char *ckexinit, int ckexinitlen,
159    char *skexinit, int skexinitlen,
160    char *serverhostkeyblob, int sbloblen,
161    BIGNUM *client_dh_pub,
162    BIGNUM *server_dh_pub,
163    BIGNUM *shared_secret)
164{
165	Buffer b;
166	static unsigned char digest[EVP_MAX_MD_SIZE];
167	EVP_MD *evp_md = EVP_sha1();
168	EVP_MD_CTX md;
169
170	buffer_init(&b);
171	buffer_put_string(&b, client_version_string, strlen(client_version_string));
172	buffer_put_string(&b, server_version_string, strlen(server_version_string));
173
174	/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
175	buffer_put_int(&b, ckexinitlen+1);
176	buffer_put_char(&b, SSH2_MSG_KEXINIT);
177	buffer_append(&b, ckexinit, ckexinitlen);
178	buffer_put_int(&b, skexinitlen+1);
179	buffer_put_char(&b, SSH2_MSG_KEXINIT);
180	buffer_append(&b, skexinit, skexinitlen);
181
182	buffer_put_string(&b, serverhostkeyblob, sbloblen);
183	buffer_put_bignum2(&b, client_dh_pub);
184	buffer_put_bignum2(&b, server_dh_pub);
185	buffer_put_bignum2(&b, shared_secret);
186
187#ifdef DEBUG_KEX
188	buffer_dump(&b);
189#endif
190
191	EVP_DigestInit(&md, evp_md);
192	EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
193	EVP_DigestFinal(&md, digest, NULL);
194
195	buffer_free(&b);
196
197#ifdef DEBUG_KEX
198	dump_digest(digest, evp_md->md_size);
199#endif
200	return digest;
201}
202
203unsigned char *
204derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
205{
206	Buffer b;
207	EVP_MD *evp_md = EVP_sha1();
208	EVP_MD_CTX md;
209	char c = id;
210	int have;
211	int mdsz = evp_md->md_size;
212	unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
213
214	buffer_init(&b);
215	buffer_put_bignum2(&b, shared_secret);
216
217	EVP_DigestInit(&md, evp_md);
218	EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));	/* shared_secret K */
219	EVP_DigestUpdate(&md, hash, mdsz);		/* transport-06 */
220	EVP_DigestUpdate(&md, &c, 1);			/* key id */
221	EVP_DigestUpdate(&md, hash, mdsz);		/* session id */
222	EVP_DigestFinal(&md, digest, NULL);
223
224	/* expand */
225	for (have = mdsz; need > have; have += mdsz) {
226		EVP_DigestInit(&md, evp_md);
227		EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
228		EVP_DigestUpdate(&md, hash, mdsz);
229		EVP_DigestUpdate(&md, digest, have);
230		EVP_DigestFinal(&md, digest + have, NULL);
231	}
232	buffer_free(&b);
233#ifdef DEBUG_KEX
234	fprintf(stderr, "Digest '%c'== ", c);
235	dump_digest(digest, need);
236#endif
237	return digest;
238}
239
240#define NKEYS	6
241
242#define	MAX_PROP	20
243#define	SEP	","
244
245char *
246get_match(char *client, char *server)
247{
248	char *sproposals[MAX_PROP];
249	char *p;
250	int i, j, nproposals;
251
252	for ((p = strtok(server, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
253		if (i < MAX_PROP)
254			sproposals[i] = p;
255		else
256			break;
257	}
258	nproposals = i;
259
260	for ((p = strtok(client, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
261		for (j = 0; j < nproposals; j++)
262			if (strcmp(p, sproposals[j]) == 0)
263				return xstrdup(p);
264	}
265	return NULL;
266}
267void
268choose_enc(Enc *enc, char *client, char *server)
269{
270	char *name = get_match(client, server);
271	if (name == NULL)
272		fatal("no matching cipher found: client %s server %s", client, server);
273	enc->type = cipher_number(name);
274
275	switch (enc->type) {
276	case SSH_CIPHER_3DES_CBC:
277		enc->key_len = 24;
278		enc->iv_len = 8;
279		enc->block_size = 8;
280		break;
281	case SSH_CIPHER_BLOWFISH_CBC:
282	case SSH_CIPHER_CAST128_CBC:
283		enc->key_len = 16;
284		enc->iv_len = 8;
285		enc->block_size = 8;
286		break;
287	case SSH_CIPHER_ARCFOUR:
288		enc->key_len = 16;
289		enc->iv_len = 0;
290		enc->block_size = 8;
291		break;
292	default:
293		fatal("unsupported cipher %s", name);
294	}
295	enc->name = name;
296	enc->enabled = 0;
297	enc->iv = NULL;
298	enc->key = NULL;
299}
300void
301choose_mac(Mac *mac, char *client, char *server)
302{
303	char *name = get_match(client, server);
304	if (name == NULL)
305		fatal("no matching mac found: client %s server %s", client, server);
306	if (strcmp(name, "hmac-md5") == 0) {
307		mac->md = EVP_md5();
308	} else if (strcmp(name, "hmac-sha1") == 0) {
309		mac->md = EVP_sha1();
310	} else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
311		mac->md = EVP_ripemd160();
312	} else {
313		fatal("unsupported mac %s", name);
314	}
315	mac->name = name;
316	mac->mac_len = mac->md->md_size;
317	mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
318	mac->key = NULL;
319	mac->enabled = 0;
320}
321void
322choose_comp(Comp *comp, char *client, char *server)
323{
324	char *name = get_match(client, server);
325	if (name == NULL)
326		fatal("no matching comp found: client %s server %s", client, server);
327	if (strcmp(name, "zlib") == 0) {
328		comp->type = 1;
329	} else if (strcmp(name, "none") == 0) {
330		comp->type = 0;
331	} else {
332		fatal("unsupported comp %s", name);
333	}
334	comp->name = name;
335}
336void
337choose_kex(Kex *k, char *client, char *server)
338{
339	k->name = get_match(client, server);
340	if (k->name == NULL)
341		fatal("no kex alg");
342	if (strcmp(k->name, KEX_DH1) != 0)
343		fatal("bad kex alg %s", k->name);
344}
345void
346choose_hostkeyalg(Kex *k, char *client, char *server)
347{
348	k->hostkeyalg = get_match(client, server);
349	if (k->hostkeyalg == NULL)
350		fatal("no hostkey alg");
351	if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
352		fatal("bad hostkey alg %s", k->hostkeyalg);
353}
354
355Kex *
356kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
357{
358	int i;
359	int mode;
360	int ctos;				/* direction: if true client-to-server */
361	int need;
362	Kex *k;
363
364	k = xmalloc(sizeof(*k));
365	memset(k, 0, sizeof(*k));
366	k->server = server;
367
368	for (mode = 0; mode < MODE_MAX; mode++) {
369		int nenc, nmac, ncomp;
370		ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
371		nenc  = ctos ? PROPOSAL_ENC_ALGS_CTOS  : PROPOSAL_ENC_ALGS_STOC;
372		nmac  = ctos ? PROPOSAL_MAC_ALGS_CTOS  : PROPOSAL_MAC_ALGS_STOC;
373		ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
374		choose_enc (&k->enc [mode], cprop[nenc],  sprop[nenc]);
375		choose_mac (&k->mac [mode], cprop[nmac],  sprop[nmac]);
376		choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
377		debug("kex: %s %s %s %s",
378		    ctos ? "client->server" : "server->client",
379		    k->enc[mode].name,
380		    k->mac[mode].name,
381		    k->comp[mode].name);
382	}
383	choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
384	choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
385	    sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
386	for (i = 0; i < PROPOSAL_MAX; i++) {
387		xfree(cprop[i]);
388		xfree(sprop[i]);
389	}
390	need = 0;
391	for (mode = 0; mode < MODE_MAX; mode++) {
392	    if (need < k->enc[mode].key_len)
393		    need = k->enc[mode].key_len;
394	    if (need < k->enc[mode].iv_len)
395		    need = k->enc[mode].iv_len;
396	    if (need < k->mac[mode].key_len)
397		    need = k->mac[mode].key_len;
398	}
399	/* need runden? */
400#define WE_NEED 32
401	k->we_need = WE_NEED;
402	k->we_need = need;
403	return k;
404}
405
406int
407kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
408{
409	int i;
410	int mode;
411	int ctos;
412	unsigned char *keys[NKEYS];
413
414	for (i = 0; i < NKEYS; i++)
415		keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
416
417	for (mode = 0; mode < MODE_MAX; mode++) {
418		ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
419		k->enc[mode].iv  = keys[ctos ? 0 : 1];
420		k->enc[mode].key = keys[ctos ? 2 : 3];
421		k->mac[mode].key = keys[ctos ? 4 : 5];
422	}
423	return 0;
424}
425