xref: /freebsd/crypto/openssh/kex.c (revision 1d66272a85cde1c8a69c58f4b5dd649babd6eca6)
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  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24 
25 #include "includes.h"
26 RCSID("$OpenBSD: kex.c,v 1.12 2000/10/11 20:27:23 markus Exp $");
27 
28 #include "ssh.h"
29 #include "ssh2.h"
30 #include "xmalloc.h"
31 #include "buffer.h"
32 #include "bufaux.h"
33 #include "packet.h"
34 #include "compat.h"
35 
36 #include <openssl/bn.h>
37 #include <openssl/dh.h>
38 
39 #include <openssl/crypto.h>
40 #include <openssl/bio.h>
41 #include <openssl/bn.h>
42 #include <openssl/dh.h>
43 #include <openssl/pem.h>
44 
45 #include "kex.h"
46 
47 #define KEX_COOKIE_LEN	16
48 
49 Buffer *
50 kex_init(char *myproposal[PROPOSAL_MAX])
51 {
52 	int first_kex_packet_follows = 0;
53 	unsigned char cookie[KEX_COOKIE_LEN];
54 	u_int32_t rand = 0;
55 	int i;
56 	Buffer *ki = xmalloc(sizeof(*ki));
57 	for (i = 0; i < KEX_COOKIE_LEN; i++) {
58 		if (i % 4 == 0)
59 			rand = arc4random();
60 		cookie[i] = rand & 0xff;
61 		rand >>= 8;
62 	}
63 	buffer_init(ki);
64 	buffer_append(ki, (char *)cookie, sizeof cookie);
65 	for (i = 0; i < PROPOSAL_MAX; i++)
66 		buffer_put_cstring(ki, myproposal[i]);
67 	buffer_put_char(ki, first_kex_packet_follows);
68 	buffer_put_int(ki, 0);				/* uint32 reserved */
69 	return ki;
70 }
71 
72 /* send kexinit, parse and save reply */
73 void
74 kex_exchange_kexinit(
75     Buffer *my_kexinit, Buffer *peer_kexint,
76     char *peer_proposal[PROPOSAL_MAX])
77 {
78 	int i;
79 	char *ptr;
80 	int plen;
81 
82 	debug("send KEXINIT");
83 	packet_start(SSH2_MSG_KEXINIT);
84 	packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));
85 	packet_send();
86 	packet_write_wait();
87 	debug("done");
88 
89 	/*
90 	 * read and save raw KEXINIT payload in buffer. this is used during
91 	 * computation of the session_id and the session keys.
92 	 */
93 	debug("wait KEXINIT");
94 	packet_read_expect(&plen, SSH2_MSG_KEXINIT);
95 	ptr = packet_get_raw(&plen);
96 	buffer_append(peer_kexint, ptr, plen);
97 
98 	/* parse packet and save algorithm proposal */
99 	/* skip cookie */
100 	for (i = 0; i < KEX_COOKIE_LEN; i++)
101 		packet_get_char();
102 	/* extract kex init proposal strings */
103 	for (i = 0; i < PROPOSAL_MAX; i++) {
104 		peer_proposal[i] = packet_get_string(NULL);
105 		debug("got kexinit: %s", peer_proposal[i]);
106 	}
107 	/* first kex follow / reserved */
108 	i = packet_get_char();
109 	debug("first kex follow: %d ", i);
110 	i = packet_get_int();
111 	debug("reserved: %d ", i);
112 	packet_done();
113 	debug("done");
114 }
115 
116 /* diffie-hellman-group1-sha1 */
117 
118 int
119 dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
120 {
121 	int i;
122 	int n = BN_num_bits(dh_pub);
123 	int bits_set = 0;
124 
125 	if (dh_pub->neg) {
126 		log("invalid public DH value: negativ");
127 		return 0;
128 	}
129 	for (i = 0; i <= n; i++)
130 		if (BN_is_bit_set(dh_pub, i))
131 			bits_set++;
132 	debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
133 
134 	/* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
135 	if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
136 		return 1;
137 	log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
138 	return 0;
139 }
140 
141 DH *
142 dh_gen_key(DH *dh)
143 {
144 	int tries = 0;
145 
146 	do {
147 		if (DH_generate_key(dh) == 0)
148 			fatal("DH_generate_key");
149 		if (tries++ > 10)
150 			fatal("dh_new_group1: too many bad keys: giving up");
151 	} while (!dh_pub_is_valid(dh, dh->pub_key));
152 	return dh;
153 }
154 
155 DH *
156 dh_new_group_asc(const char *gen, const char *modulus)
157 {
158 	DH *dh;
159 	int ret;
160 
161 	dh = DH_new();
162 	if (dh == NULL)
163 		fatal("DH_new");
164 
165 	if ((ret = BN_hex2bn(&dh->p, modulus)) < 0)
166 		fatal("BN_hex2bn p");
167 	if ((ret = BN_hex2bn(&dh->g, gen)) < 0)
168 		fatal("BN_hex2bn g");
169 
170 	return (dh_gen_key(dh));
171 }
172 
173 DH *
174 dh_new_group(BIGNUM *gen, BIGNUM *modulus)
175 {
176 	DH *dh;
177 
178 	dh = DH_new();
179 	if (dh == NULL)
180 		fatal("DH_new");
181 	dh->p = modulus;
182 	dh->g = gen;
183 
184 	return (dh_gen_key(dh));
185 }
186 
187 DH *
188 dh_new_group1()
189 {
190 	static char *gen = "2", *group1 =
191 	    "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
192 	    "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
193 	    "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
194 	    "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
195 	    "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
196 	    "FFFFFFFF" "FFFFFFFF";
197 
198 	return (dh_new_group_asc(gen, group1));
199 }
200 
201 void
202 dump_digest(unsigned char *digest, int len)
203 {
204 	int i;
205 	for (i = 0; i< len; i++){
206 		fprintf(stderr, "%02x", digest[i]);
207 		if(i%2!=0)
208 			fprintf(stderr, " ");
209 	}
210 	fprintf(stderr, "\n");
211 }
212 
213 unsigned char *
214 kex_hash(
215     char *client_version_string,
216     char *server_version_string,
217     char *ckexinit, int ckexinitlen,
218     char *skexinit, int skexinitlen,
219     char *serverhostkeyblob, int sbloblen,
220     BIGNUM *client_dh_pub,
221     BIGNUM *server_dh_pub,
222     BIGNUM *shared_secret)
223 {
224 	Buffer b;
225 	static unsigned char digest[EVP_MAX_MD_SIZE];
226 	EVP_MD *evp_md = EVP_sha1();
227 	EVP_MD_CTX md;
228 
229 	buffer_init(&b);
230 	buffer_put_string(&b, client_version_string, strlen(client_version_string));
231 	buffer_put_string(&b, server_version_string, strlen(server_version_string));
232 
233 	/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
234 	buffer_put_int(&b, ckexinitlen+1);
235 	buffer_put_char(&b, SSH2_MSG_KEXINIT);
236 	buffer_append(&b, ckexinit, ckexinitlen);
237 	buffer_put_int(&b, skexinitlen+1);
238 	buffer_put_char(&b, SSH2_MSG_KEXINIT);
239 	buffer_append(&b, skexinit, skexinitlen);
240 
241 	buffer_put_string(&b, serverhostkeyblob, sbloblen);
242 	buffer_put_bignum2(&b, client_dh_pub);
243 	buffer_put_bignum2(&b, server_dh_pub);
244 	buffer_put_bignum2(&b, shared_secret);
245 
246 #ifdef DEBUG_KEX
247 	buffer_dump(&b);
248 #endif
249 
250 	EVP_DigestInit(&md, evp_md);
251 	EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
252 	EVP_DigestFinal(&md, digest, NULL);
253 
254 	buffer_free(&b);
255 
256 #ifdef DEBUG_KEX
257 	dump_digest(digest, evp_md->md_size);
258 #endif
259 	return digest;
260 }
261 
262 unsigned char *
263 kex_hash_gex(
264     char *client_version_string,
265     char *server_version_string,
266     char *ckexinit, int ckexinitlen,
267     char *skexinit, int skexinitlen,
268     char *serverhostkeyblob, int sbloblen,
269     int minbits, BIGNUM *prime, BIGNUM *gen,
270     BIGNUM *client_dh_pub,
271     BIGNUM *server_dh_pub,
272     BIGNUM *shared_secret)
273 {
274 	Buffer b;
275 	static unsigned char digest[EVP_MAX_MD_SIZE];
276 	EVP_MD *evp_md = EVP_sha1();
277 	EVP_MD_CTX md;
278 
279 	buffer_init(&b);
280 	buffer_put_string(&b, client_version_string, strlen(client_version_string));
281 	buffer_put_string(&b, server_version_string, strlen(server_version_string));
282 
283 	/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
284 	buffer_put_int(&b, ckexinitlen+1);
285 	buffer_put_char(&b, SSH2_MSG_KEXINIT);
286 	buffer_append(&b, ckexinit, ckexinitlen);
287 	buffer_put_int(&b, skexinitlen+1);
288 	buffer_put_char(&b, SSH2_MSG_KEXINIT);
289 	buffer_append(&b, skexinit, skexinitlen);
290 
291 	buffer_put_string(&b, serverhostkeyblob, sbloblen);
292 	buffer_put_int(&b, minbits);
293 	buffer_put_bignum2(&b, prime);
294 	buffer_put_bignum2(&b, gen);
295 	buffer_put_bignum2(&b, client_dh_pub);
296 	buffer_put_bignum2(&b, server_dh_pub);
297 	buffer_put_bignum2(&b, shared_secret);
298 
299 #ifdef DEBUG_KEX
300 	buffer_dump(&b);
301 #endif
302 
303 	EVP_DigestInit(&md, evp_md);
304 	EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
305 	EVP_DigestFinal(&md, digest, NULL);
306 
307 	buffer_free(&b);
308 
309 #ifdef DEBUG_KEX
310 	dump_digest(digest, evp_md->md_size);
311 #endif
312 	return digest;
313 }
314 
315 unsigned char *
316 derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
317 {
318 	Buffer b;
319 	EVP_MD *evp_md = EVP_sha1();
320 	EVP_MD_CTX md;
321 	char c = id;
322 	int have;
323 	int mdsz = evp_md->md_size;
324 	unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
325 
326 	buffer_init(&b);
327 	buffer_put_bignum2(&b, shared_secret);
328 
329 	EVP_DigestInit(&md, evp_md);
330 	EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));	/* shared_secret K */
331 	EVP_DigestUpdate(&md, hash, mdsz);		/* transport-06 */
332 	EVP_DigestUpdate(&md, &c, 1);			/* key id */
333 	EVP_DigestUpdate(&md, hash, mdsz);		/* session id */
334 	EVP_DigestFinal(&md, digest, NULL);
335 
336 	/* expand */
337 	for (have = mdsz; need > have; have += mdsz) {
338 		EVP_DigestInit(&md, evp_md);
339 		EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
340 		EVP_DigestUpdate(&md, hash, mdsz);
341 		EVP_DigestUpdate(&md, digest, have);
342 		EVP_DigestFinal(&md, digest + have, NULL);
343 	}
344 	buffer_free(&b);
345 #ifdef DEBUG_KEX
346 	fprintf(stderr, "Digest '%c'== ", c);
347 	dump_digest(digest, need);
348 #endif
349 	return digest;
350 }
351 
352 #define NKEYS	6
353 
354 #define	MAX_PROP	20
355 #define	SEP	","
356 
357 char *
358 get_match(char *client, char *server)
359 {
360 	char *sproposals[MAX_PROP];
361 	char *c, *s, *p, *ret, *cp, *sp;
362 	int i, j, nproposals;
363 
364 	c = cp = xstrdup(client);
365 	s = sp = xstrdup(server);
366 
367 	for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
368 	     (p = strsep(&sp, SEP)), i++) {
369 		if (i < MAX_PROP)
370 			sproposals[i] = p;
371 		else
372 			break;
373 	}
374 	nproposals = i;
375 
376 	for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
377 	     (p = strsep(&cp, SEP)), i++) {
378 		for (j = 0; j < nproposals; j++) {
379 			if (strcmp(p, sproposals[j]) == 0) {
380 				ret = xstrdup(p);
381 				xfree(c);
382 				xfree(s);
383 				return ret;
384 			}
385 		}
386 	}
387 	xfree(c);
388 	xfree(s);
389 	return NULL;
390 }
391 void
392 choose_enc(Enc *enc, char *client, char *server)
393 {
394 	char *name = get_match(client, server);
395 	if (name == NULL)
396 		fatal("no matching cipher found: client %s server %s", client, server);
397 	enc->cipher = cipher_by_name(name);
398 	if (enc->cipher == NULL)
399 		fatal("matching cipher is not supported: %s", name);
400 	enc->name = name;
401 	enc->enabled = 0;
402 	enc->iv = NULL;
403 	enc->key = NULL;
404 }
405 void
406 choose_mac(Mac *mac, char *client, char *server)
407 {
408 	char *name = get_match(client, server);
409 	if (name == NULL)
410 		fatal("no matching mac found: client %s server %s", client, server);
411 	if (strcmp(name, "hmac-md5") == 0) {
412 		mac->md = EVP_md5();
413 	} else if (strcmp(name, "hmac-sha1") == 0) {
414 		mac->md = EVP_sha1();
415 	} else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
416 		mac->md = EVP_ripemd160();
417 	} else {
418 		fatal("unsupported mac %s", name);
419 	}
420 	mac->name = name;
421 	mac->mac_len = mac->md->md_size;
422 	mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
423 	mac->key = NULL;
424 	mac->enabled = 0;
425 }
426 void
427 choose_comp(Comp *comp, char *client, char *server)
428 {
429 	char *name = get_match(client, server);
430 	if (name == NULL)
431 		fatal("no matching comp found: client %s server %s", client, server);
432 	if (strcmp(name, "zlib") == 0) {
433 		comp->type = 1;
434 	} else if (strcmp(name, "none") == 0) {
435 		comp->type = 0;
436 	} else {
437 		fatal("unsupported comp %s", name);
438 	}
439 	comp->name = name;
440 }
441 void
442 choose_kex(Kex *k, char *client, char *server)
443 {
444 	k->name = get_match(client, server);
445 	if (k->name == NULL)
446 		fatal("no kex alg");
447 	if (strcmp(k->name, KEX_DH1) == 0) {
448 		k->kex_type = DH_GRP1_SHA1;
449 	} else if (strcmp(k->name, KEX_DHGEX) == 0) {
450 		k->kex_type = DH_GEX_SHA1;
451 	} else
452 		fatal("bad kex alg %s", k->name);
453 }
454 void
455 choose_hostkeyalg(Kex *k, char *client, char *server)
456 {
457 	k->hostkeyalg = get_match(client, server);
458 	if (k->hostkeyalg == NULL)
459 		fatal("no hostkey alg");
460 	if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
461 		fatal("bad hostkey alg %s", k->hostkeyalg);
462 }
463 
464 Kex *
465 kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
466 {
467 	int mode;
468 	int ctos;				/* direction: if true client-to-server */
469 	int need;
470 	Kex *k;
471 
472 	k = xmalloc(sizeof(*k));
473 	memset(k, 0, sizeof(*k));
474 	k->server = server;
475 
476 	for (mode = 0; mode < MODE_MAX; mode++) {
477 		int nenc, nmac, ncomp;
478 		ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
479 		nenc  = ctos ? PROPOSAL_ENC_ALGS_CTOS  : PROPOSAL_ENC_ALGS_STOC;
480 		nmac  = ctos ? PROPOSAL_MAC_ALGS_CTOS  : PROPOSAL_MAC_ALGS_STOC;
481 		ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
482 		choose_enc (&k->enc [mode], cprop[nenc],  sprop[nenc]);
483 		choose_mac (&k->mac [mode], cprop[nmac],  sprop[nmac]);
484 		choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
485 		debug("kex: %s %s %s %s",
486 		    ctos ? "client->server" : "server->client",
487 		    k->enc[mode].name,
488 		    k->mac[mode].name,
489 		    k->comp[mode].name);
490 	}
491 	choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
492 	choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
493 	    sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
494 	need = 0;
495 	for (mode = 0; mode < MODE_MAX; mode++) {
496 	    if (need < k->enc[mode].cipher->key_len)
497 		    need = k->enc[mode].cipher->key_len;
498 	    if (need < k->enc[mode].cipher->block_size)
499 		    need = k->enc[mode].cipher->block_size;
500 	    if (need < k->mac[mode].key_len)
501 		    need = k->mac[mode].key_len;
502 	}
503 	/* XXX need runden? */
504 	k->we_need = need;
505 	return k;
506 }
507 
508 int
509 kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
510 {
511 	int i;
512 	int mode;
513 	int ctos;
514 	unsigned char *keys[NKEYS];
515 
516 	for (i = 0; i < NKEYS; i++)
517 		keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
518 
519 	for (mode = 0; mode < MODE_MAX; mode++) {
520 		ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
521 		k->enc[mode].iv  = keys[ctos ? 0 : 1];
522 		k->enc[mode].key = keys[ctos ? 2 : 3];
523 		k->mac[mode].key = keys[ctos ? 4 : 5];
524 	}
525 	return 0;
526 }
527