xref: /freebsd/crypto/openssh/kex.c (revision b601c69bdbe8755d26570261d7fd4c02ee4eff74)
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"
31 RCSID("$Id: kex.c,v 1.7 2000/05/25 20:45:20 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 "packet.h"
39 #include "cipher.h"
40 #include "compat.h"
41 
42 #include <openssl/bn.h>
43 #include <openssl/dh.h>
44 
45 #include <openssl/crypto.h>
46 #include <openssl/bio.h>
47 #include <openssl/bn.h>
48 #include <openssl/dh.h>
49 #include <openssl/pem.h>
50 
51 #include "kex.h"
52 
53 #define KEX_COOKIE_LEN	16
54 
55 Buffer *
56 kex_init(char *myproposal[PROPOSAL_MAX])
57 {
58 	int first_kex_packet_follows = 0;
59 	unsigned char cookie[KEX_COOKIE_LEN];
60 	u_int32_t rand = 0;
61 	int i;
62 	Buffer *ki = xmalloc(sizeof(*ki));
63 	for (i = 0; i < KEX_COOKIE_LEN; i++) {
64 		if (i % 4 == 0)
65 			rand = arc4random();
66 		cookie[i] = rand & 0xff;
67 		rand >>= 8;
68 	}
69 	buffer_init(ki);
70 	buffer_append(ki, (char *)cookie, sizeof cookie);
71 	for (i = 0; i < PROPOSAL_MAX; i++)
72 		buffer_put_cstring(ki, myproposal[i]);
73 	buffer_put_char(ki, first_kex_packet_follows);
74 	buffer_put_int(ki, 0);				/* uint32 reserved */
75 	return ki;
76 }
77 
78 /* send kexinit, parse and save reply */
79 void
80 kex_exchange_kexinit(
81     Buffer *my_kexinit, Buffer *peer_kexint,
82     char *peer_proposal[PROPOSAL_MAX])
83 {
84 	int i;
85 	char *ptr;
86 	int plen;
87 
88 	debug("send KEXINIT");
89 	packet_start(SSH2_MSG_KEXINIT);
90 	packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));
91 	packet_send();
92 	packet_write_wait();
93 	debug("done");
94 
95 	/*
96 	 * read and save raw KEXINIT payload in buffer. this is used during
97 	 * computation of the session_id and the session keys.
98 	 */
99 	debug("wait KEXINIT");
100 	packet_read_expect(&plen, SSH2_MSG_KEXINIT);
101 	ptr = packet_get_raw(&plen);
102 	buffer_append(peer_kexint, ptr, plen);
103 
104 	/* parse packet and save algorithm proposal */
105 	/* skip cookie */
106 	for (i = 0; i < KEX_COOKIE_LEN; i++)
107 		packet_get_char();
108 	/* extract kex init proposal strings */
109 	for (i = 0; i < PROPOSAL_MAX; i++) {
110 		peer_proposal[i] = packet_get_string(NULL);
111 		debug("got kexinit: %s", peer_proposal[i]);
112 	}
113 	/* first kex follow / reserved */
114 	i = packet_get_char();
115 	debug("first kex follow: %d ", i);
116 	i = packet_get_int();
117 	debug("reserved: %d ", i);
118 	packet_done();
119 	debug("done");
120 }
121 
122 /* diffie-hellman-group1-sha1 */
123 
124 int
125 dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
126 {
127 	int i;
128 	int n = BN_num_bits(dh_pub);
129 	int bits_set = 0;
130 
131 	/* we only accept g==2 */
132 	if (!BN_is_word(dh->g, 2)) {
133 		log("invalid DH base != 2");
134 		return 0;
135 	}
136 	if (dh_pub->neg) {
137 		log("invalid public DH value: negativ");
138 		return 0;
139 	}
140 	for (i = 0; i <= n; i++)
141 		if (BN_is_bit_set(dh_pub, i))
142 			bits_set++;
143 	debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
144 
145 	/* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
146 	if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
147 		return 1;
148 	log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
149 	return 0;
150 }
151 
152 DH *
153 dh_new_group1()
154 {
155 	static char *group1 =
156 	    "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
157 	    "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
158 	    "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
159 	    "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
160 	    "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
161 	    "FFFFFFFF" "FFFFFFFF";
162 	DH *dh;
163 	int ret, tries = 0;
164 	dh = DH_new();
165 	if(dh == NULL)
166 		fatal("DH_new");
167 	ret = BN_hex2bn(&dh->p, group1);
168 	if(ret<0)
169 		fatal("BN_hex2bn");
170 	dh->g = BN_new();
171 	if(dh->g == NULL)
172 		fatal("DH_new g");
173 	BN_set_word(dh->g, 2);
174 	do {
175 		if (DH_generate_key(dh) == 0)
176 			fatal("DH_generate_key");
177 		if (tries++ > 10)
178 			fatal("dh_new_group1: too many bad keys: giving up");
179 	} while (!dh_pub_is_valid(dh, dh->pub_key));
180 	return dh;
181 }
182 
183 void
184 dump_digest(unsigned char *digest, int len)
185 {
186 	int i;
187 	for (i = 0; i< len; i++){
188 		fprintf(stderr, "%02x", digest[i]);
189 		if(i%2!=0)
190 			fprintf(stderr, " ");
191 	}
192 	fprintf(stderr, "\n");
193 }
194 
195 unsigned char *
196 kex_hash(
197     char *client_version_string,
198     char *server_version_string,
199     char *ckexinit, int ckexinitlen,
200     char *skexinit, int skexinitlen,
201     char *serverhostkeyblob, int sbloblen,
202     BIGNUM *client_dh_pub,
203     BIGNUM *server_dh_pub,
204     BIGNUM *shared_secret)
205 {
206 	Buffer b;
207 	static unsigned char digest[EVP_MAX_MD_SIZE];
208 	EVP_MD *evp_md = EVP_sha1();
209 	EVP_MD_CTX md;
210 
211 	buffer_init(&b);
212 	buffer_put_string(&b, client_version_string, strlen(client_version_string));
213 	buffer_put_string(&b, server_version_string, strlen(server_version_string));
214 
215 	/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
216 	buffer_put_int(&b, ckexinitlen+1);
217 	buffer_put_char(&b, SSH2_MSG_KEXINIT);
218 	buffer_append(&b, ckexinit, ckexinitlen);
219 	buffer_put_int(&b, skexinitlen+1);
220 	buffer_put_char(&b, SSH2_MSG_KEXINIT);
221 	buffer_append(&b, skexinit, skexinitlen);
222 
223 	buffer_put_string(&b, serverhostkeyblob, sbloblen);
224 	buffer_put_bignum2(&b, client_dh_pub);
225 	buffer_put_bignum2(&b, server_dh_pub);
226 	buffer_put_bignum2(&b, shared_secret);
227 
228 #ifdef DEBUG_KEX
229 	buffer_dump(&b);
230 #endif
231 
232 	EVP_DigestInit(&md, evp_md);
233 	EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
234 	EVP_DigestFinal(&md, digest, NULL);
235 
236 	buffer_free(&b);
237 
238 #ifdef DEBUG_KEX
239 	dump_digest(digest, evp_md->md_size);
240 #endif
241 	return digest;
242 }
243 
244 unsigned char *
245 derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
246 {
247 	Buffer b;
248 	EVP_MD *evp_md = EVP_sha1();
249 	EVP_MD_CTX md;
250 	char c = id;
251 	int have;
252 	int mdsz = evp_md->md_size;
253 	unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
254 
255 	buffer_init(&b);
256 	buffer_put_bignum2(&b, shared_secret);
257 
258 	EVP_DigestInit(&md, evp_md);
259 	EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));	/* shared_secret K */
260 	EVP_DigestUpdate(&md, hash, mdsz);		/* transport-06 */
261 	EVP_DigestUpdate(&md, &c, 1);			/* key id */
262 	EVP_DigestUpdate(&md, hash, mdsz);		/* session id */
263 	EVP_DigestFinal(&md, digest, NULL);
264 
265 	/* expand */
266 	for (have = mdsz; need > have; have += mdsz) {
267 		EVP_DigestInit(&md, evp_md);
268 		EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
269 		EVP_DigestUpdate(&md, hash, mdsz);
270 		EVP_DigestUpdate(&md, digest, have);
271 		EVP_DigestFinal(&md, digest + have, NULL);
272 	}
273 	buffer_free(&b);
274 #ifdef DEBUG_KEX
275 	fprintf(stderr, "Digest '%c'== ", c);
276 	dump_digest(digest, need);
277 #endif
278 	return digest;
279 }
280 
281 #define NKEYS	6
282 
283 #define	MAX_PROP	20
284 #define	SEP	","
285 
286 char *
287 get_match(char *client, char *server)
288 {
289 	char *sproposals[MAX_PROP];
290 	char *c, *s, *p, *ret;
291 	int i, j, nproposals;
292 
293 	c = xstrdup(client);
294 	s = xstrdup(server);
295 
296 	for ((p = strtok(s, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
297 		if (i < MAX_PROP)
298 			sproposals[i] = p;
299 		else
300 			break;
301 	}
302 	nproposals = i;
303 
304 	for ((p = strtok(c, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
305 		for (j = 0; j < nproposals; j++) {
306 			if (strcmp(p, sproposals[j]) == 0) {
307 				ret = xstrdup(p);
308 				xfree(c);
309 				xfree(s);
310 				return ret;
311 			}
312 		}
313 	}
314 	xfree(c);
315 	xfree(s);
316 	return NULL;
317 }
318 void
319 choose_enc(Enc *enc, char *client, char *server)
320 {
321 	char *name = get_match(client, server);
322 	if (name == NULL)
323 		fatal("no matching cipher found: client %s server %s", client, server);
324 	enc->type = cipher_number(name);
325 
326 	switch (enc->type) {
327 	case SSH_CIPHER_3DES_CBC:
328 		enc->key_len = 24;
329 		enc->iv_len = 8;
330 		enc->block_size = 8;
331 		break;
332 	case SSH_CIPHER_BLOWFISH_CBC:
333 	case SSH_CIPHER_CAST128_CBC:
334 		enc->key_len = 16;
335 		enc->iv_len = 8;
336 		enc->block_size = 8;
337 		break;
338 	case SSH_CIPHER_ARCFOUR:
339 		enc->key_len = 16;
340 		enc->iv_len = 0;
341 		enc->block_size = 8;
342 		break;
343 	default:
344 		fatal("unsupported cipher %s", name);
345 	}
346 	enc->name = name;
347 	enc->enabled = 0;
348 	enc->iv = NULL;
349 	enc->key = NULL;
350 }
351 void
352 choose_mac(Mac *mac, char *client, char *server)
353 {
354 	char *name = get_match(client, server);
355 	if (name == NULL)
356 		fatal("no matching mac found: client %s server %s", client, server);
357 	if (strcmp(name, "hmac-md5") == 0) {
358 		mac->md = EVP_md5();
359 	} else if (strcmp(name, "hmac-sha1") == 0) {
360 		mac->md = EVP_sha1();
361 	} else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
362 		mac->md = EVP_ripemd160();
363 	} else {
364 		fatal("unsupported mac %s", name);
365 	}
366 	mac->name = name;
367 	mac->mac_len = mac->md->md_size;
368 	mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
369 	mac->key = NULL;
370 	mac->enabled = 0;
371 }
372 void
373 choose_comp(Comp *comp, char *client, char *server)
374 {
375 	char *name = get_match(client, server);
376 	if (name == NULL)
377 		fatal("no matching comp found: client %s server %s", client, server);
378 	if (strcmp(name, "zlib") == 0) {
379 		comp->type = 1;
380 	} else if (strcmp(name, "none") == 0) {
381 		comp->type = 0;
382 	} else {
383 		fatal("unsupported comp %s", name);
384 	}
385 	comp->name = name;
386 }
387 void
388 choose_kex(Kex *k, char *client, char *server)
389 {
390 	k->name = get_match(client, server);
391 	if (k->name == NULL)
392 		fatal("no kex alg");
393 	if (strcmp(k->name, KEX_DH1) != 0)
394 		fatal("bad kex alg %s", k->name);
395 }
396 void
397 choose_hostkeyalg(Kex *k, char *client, char *server)
398 {
399 	k->hostkeyalg = get_match(client, server);
400 	if (k->hostkeyalg == NULL)
401 		fatal("no hostkey alg");
402 	if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
403 		fatal("bad hostkey alg %s", k->hostkeyalg);
404 }
405 
406 Kex *
407 kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
408 {
409 	int mode;
410 	int ctos;				/* direction: if true client-to-server */
411 	int need;
412 	Kex *k;
413 
414 	k = xmalloc(sizeof(*k));
415 	memset(k, 0, sizeof(*k));
416 	k->server = server;
417 
418 	for (mode = 0; mode < MODE_MAX; mode++) {
419 		int nenc, nmac, ncomp;
420 		ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
421 		nenc  = ctos ? PROPOSAL_ENC_ALGS_CTOS  : PROPOSAL_ENC_ALGS_STOC;
422 		nmac  = ctos ? PROPOSAL_MAC_ALGS_CTOS  : PROPOSAL_MAC_ALGS_STOC;
423 		ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
424 		choose_enc (&k->enc [mode], cprop[nenc],  sprop[nenc]);
425 		choose_mac (&k->mac [mode], cprop[nmac],  sprop[nmac]);
426 		choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
427 		debug("kex: %s %s %s %s",
428 		    ctos ? "client->server" : "server->client",
429 		    k->enc[mode].name,
430 		    k->mac[mode].name,
431 		    k->comp[mode].name);
432 	}
433 	choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
434 	choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
435 	    sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
436 	need = 0;
437 	for (mode = 0; mode < MODE_MAX; mode++) {
438 	    if (need < k->enc[mode].key_len)
439 		    need = k->enc[mode].key_len;
440 	    if (need < k->enc[mode].iv_len)
441 		    need = k->enc[mode].iv_len;
442 	    if (need < k->mac[mode].key_len)
443 		    need = k->mac[mode].key_len;
444 	}
445 	/* XXX need runden? */
446 	k->we_need = need;
447 	return k;
448 }
449 
450 int
451 kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
452 {
453 	int i;
454 	int mode;
455 	int ctos;
456 	unsigned char *keys[NKEYS];
457 
458 	for (i = 0; i < NKEYS; i++)
459 		keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
460 
461 	for (mode = 0; mode < MODE_MAX; mode++) {
462 		ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
463 		k->enc[mode].iv  = keys[ctos ? 0 : 1];
464 		k->enc[mode].key = keys[ctos ? 2 : 3];
465 		k->mac[mode].key = keys[ctos ? 4 : 5];
466 	}
467 	return 0;
468 }
469