xref: /freebsd/crypto/openssh/kex.c (revision 5b9b2fafd4d6d82af10bf630cbfc9393b8ed1d0a)
1a04a10f8SKris Kennaway /*
2a04a10f8SKris Kennaway  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
3a04a10f8SKris Kennaway  *
4a04a10f8SKris Kennaway  * Redistribution and use in source and binary forms, with or without
5a04a10f8SKris Kennaway  * modification, are permitted provided that the following conditions
6a04a10f8SKris Kennaway  * are met:
7a04a10f8SKris Kennaway  * 1. Redistributions of source code must retain the above copyright
8a04a10f8SKris Kennaway  *    notice, this list of conditions and the following disclaimer.
9a04a10f8SKris Kennaway  * 2. Redistributions in binary form must reproduce the above copyright
10a04a10f8SKris Kennaway  *    notice, this list of conditions and the following disclaimer in the
11a04a10f8SKris Kennaway  *    documentation and/or other materials provided with the distribution.
12a04a10f8SKris Kennaway  *
13a04a10f8SKris Kennaway  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14a04a10f8SKris Kennaway  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15a04a10f8SKris Kennaway  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16a04a10f8SKris Kennaway  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17a04a10f8SKris Kennaway  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18a04a10f8SKris Kennaway  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19a04a10f8SKris Kennaway  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20a04a10f8SKris Kennaway  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21a04a10f8SKris Kennaway  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22a04a10f8SKris Kennaway  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23a04a10f8SKris Kennaway  */
24a04a10f8SKris Kennaway 
25a04a10f8SKris Kennaway #include "includes.h"
265b9b2fafSBrian Feldman RCSID("$OpenBSD: kex.c,v 1.12 2000/10/11 20:27:23 markus Exp $");
27a04a10f8SKris Kennaway 
28a04a10f8SKris Kennaway #include "ssh.h"
29a04a10f8SKris Kennaway #include "ssh2.h"
30a04a10f8SKris Kennaway #include "xmalloc.h"
31a04a10f8SKris Kennaway #include "buffer.h"
32a04a10f8SKris Kennaway #include "bufaux.h"
332632b0c8SKris Kennaway #include "packet.h"
34a04a10f8SKris Kennaway #include "compat.h"
35a04a10f8SKris Kennaway 
36a04a10f8SKris Kennaway #include <openssl/bn.h>
37a04a10f8SKris Kennaway #include <openssl/dh.h>
38a04a10f8SKris Kennaway 
39a04a10f8SKris Kennaway #include <openssl/crypto.h>
40a04a10f8SKris Kennaway #include <openssl/bio.h>
41a04a10f8SKris Kennaway #include <openssl/bn.h>
42a04a10f8SKris Kennaway #include <openssl/dh.h>
43a04a10f8SKris Kennaway #include <openssl/pem.h>
44a04a10f8SKris Kennaway 
45a04a10f8SKris Kennaway #include "kex.h"
46a04a10f8SKris Kennaway 
472632b0c8SKris Kennaway #define KEX_COOKIE_LEN	16
482632b0c8SKris Kennaway 
49a04a10f8SKris Kennaway Buffer *
50a04a10f8SKris Kennaway kex_init(char *myproposal[PROPOSAL_MAX])
51a04a10f8SKris Kennaway {
522632b0c8SKris Kennaway 	int first_kex_packet_follows = 0;
532632b0c8SKris Kennaway 	unsigned char cookie[KEX_COOKIE_LEN];
54a04a10f8SKris Kennaway 	u_int32_t rand = 0;
55a04a10f8SKris Kennaway 	int i;
56a04a10f8SKris Kennaway 	Buffer *ki = xmalloc(sizeof(*ki));
572632b0c8SKris Kennaway 	for (i = 0; i < KEX_COOKIE_LEN; i++) {
58a04a10f8SKris Kennaway 		if (i % 4 == 0)
59a04a10f8SKris Kennaway 			rand = arc4random();
60a04a10f8SKris Kennaway 		cookie[i] = rand & 0xff;
61a04a10f8SKris Kennaway 		rand >>= 8;
62a04a10f8SKris Kennaway 	}
63a04a10f8SKris Kennaway 	buffer_init(ki);
64a04a10f8SKris Kennaway 	buffer_append(ki, (char *)cookie, sizeof cookie);
65a04a10f8SKris Kennaway 	for (i = 0; i < PROPOSAL_MAX; i++)
66a04a10f8SKris Kennaway 		buffer_put_cstring(ki, myproposal[i]);
672632b0c8SKris Kennaway 	buffer_put_char(ki, first_kex_packet_follows);
682632b0c8SKris Kennaway 	buffer_put_int(ki, 0);				/* uint32 reserved */
69a04a10f8SKris Kennaway 	return ki;
70a04a10f8SKris Kennaway }
71a04a10f8SKris Kennaway 
722632b0c8SKris Kennaway /* send kexinit, parse and save reply */
732632b0c8SKris Kennaway void
742632b0c8SKris Kennaway kex_exchange_kexinit(
752632b0c8SKris Kennaway     Buffer *my_kexinit, Buffer *peer_kexint,
762632b0c8SKris Kennaway     char *peer_proposal[PROPOSAL_MAX])
772632b0c8SKris Kennaway {
782632b0c8SKris Kennaway 	int i;
792632b0c8SKris Kennaway 	char *ptr;
802632b0c8SKris Kennaway 	int plen;
812632b0c8SKris Kennaway 
822632b0c8SKris Kennaway 	debug("send KEXINIT");
832632b0c8SKris Kennaway 	packet_start(SSH2_MSG_KEXINIT);
842632b0c8SKris Kennaway 	packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));
852632b0c8SKris Kennaway 	packet_send();
862632b0c8SKris Kennaway 	packet_write_wait();
872632b0c8SKris Kennaway 	debug("done");
882632b0c8SKris Kennaway 
892632b0c8SKris Kennaway 	/*
902632b0c8SKris Kennaway 	 * read and save raw KEXINIT payload in buffer. this is used during
912632b0c8SKris Kennaway 	 * computation of the session_id and the session keys.
922632b0c8SKris Kennaway 	 */
932632b0c8SKris Kennaway 	debug("wait KEXINIT");
942632b0c8SKris Kennaway 	packet_read_expect(&plen, SSH2_MSG_KEXINIT);
952632b0c8SKris Kennaway 	ptr = packet_get_raw(&plen);
962632b0c8SKris Kennaway 	buffer_append(peer_kexint, ptr, plen);
972632b0c8SKris Kennaway 
982632b0c8SKris Kennaway 	/* parse packet and save algorithm proposal */
992632b0c8SKris Kennaway 	/* skip cookie */
1002632b0c8SKris Kennaway 	for (i = 0; i < KEX_COOKIE_LEN; i++)
1012632b0c8SKris Kennaway 		packet_get_char();
1022632b0c8SKris Kennaway 	/* extract kex init proposal strings */
1032632b0c8SKris Kennaway 	for (i = 0; i < PROPOSAL_MAX; i++) {
1042632b0c8SKris Kennaway 		peer_proposal[i] = packet_get_string(NULL);
1052632b0c8SKris Kennaway 		debug("got kexinit: %s", peer_proposal[i]);
1062632b0c8SKris Kennaway 	}
1072632b0c8SKris Kennaway 	/* first kex follow / reserved */
1082632b0c8SKris Kennaway 	i = packet_get_char();
1092632b0c8SKris Kennaway 	debug("first kex follow: %d ", i);
1102632b0c8SKris Kennaway 	i = packet_get_int();
1112632b0c8SKris Kennaway 	debug("reserved: %d ", i);
1122632b0c8SKris Kennaway 	packet_done();
1132632b0c8SKris Kennaway 	debug("done");
1142632b0c8SKris Kennaway }
1152632b0c8SKris Kennaway 
116a04a10f8SKris Kennaway /* diffie-hellman-group1-sha1 */
117a04a10f8SKris Kennaway 
118a04a10f8SKris Kennaway int
119a04a10f8SKris Kennaway dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
120a04a10f8SKris Kennaway {
121a04a10f8SKris Kennaway 	int i;
122a04a10f8SKris Kennaway 	int n = BN_num_bits(dh_pub);
123a04a10f8SKris Kennaway 	int bits_set = 0;
124a04a10f8SKris Kennaway 
125a04a10f8SKris Kennaway 	if (dh_pub->neg) {
126a04a10f8SKris Kennaway 		log("invalid public DH value: negativ");
127a04a10f8SKris Kennaway 		return 0;
128a04a10f8SKris Kennaway 	}
129a04a10f8SKris Kennaway 	for (i = 0; i <= n; i++)
130a04a10f8SKris Kennaway 		if (BN_is_bit_set(dh_pub, i))
131a04a10f8SKris Kennaway 			bits_set++;
132a04a10f8SKris Kennaway 	debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
133a04a10f8SKris Kennaway 
134a04a10f8SKris Kennaway 	/* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
135a04a10f8SKris Kennaway 	if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
136a04a10f8SKris Kennaway 		return 1;
137a04a10f8SKris Kennaway 	log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
138a04a10f8SKris Kennaway 	return 0;
139a04a10f8SKris Kennaway }
140a04a10f8SKris Kennaway 
141a04a10f8SKris Kennaway DH *
1425b9b2fafSBrian Feldman dh_gen_key(DH *dh)
143a04a10f8SKris Kennaway {
1445b9b2fafSBrian Feldman 	int tries = 0;
1455b9b2fafSBrian Feldman 
146a04a10f8SKris Kennaway 	do {
147a04a10f8SKris Kennaway 		if (DH_generate_key(dh) == 0)
148a04a10f8SKris Kennaway 			fatal("DH_generate_key");
149a04a10f8SKris Kennaway 		if (tries++ > 10)
150a04a10f8SKris Kennaway 			fatal("dh_new_group1: too many bad keys: giving up");
151a04a10f8SKris Kennaway 	} while (!dh_pub_is_valid(dh, dh->pub_key));
152a04a10f8SKris Kennaway 	return dh;
153a04a10f8SKris Kennaway }
154a04a10f8SKris Kennaway 
1555b9b2fafSBrian Feldman DH *
1565b9b2fafSBrian Feldman dh_new_group_asc(const char *gen, const char *modulus)
1575b9b2fafSBrian Feldman {
1585b9b2fafSBrian Feldman 	DH *dh;
1595b9b2fafSBrian Feldman 	int ret;
1605b9b2fafSBrian Feldman 
1615b9b2fafSBrian Feldman 	dh = DH_new();
1625b9b2fafSBrian Feldman 	if (dh == NULL)
1635b9b2fafSBrian Feldman 		fatal("DH_new");
1645b9b2fafSBrian Feldman 
1655b9b2fafSBrian Feldman 	if ((ret = BN_hex2bn(&dh->p, modulus)) < 0)
1665b9b2fafSBrian Feldman 		fatal("BN_hex2bn p");
1675b9b2fafSBrian Feldman 	if ((ret = BN_hex2bn(&dh->g, gen)) < 0)
1685b9b2fafSBrian Feldman 		fatal("BN_hex2bn g");
1695b9b2fafSBrian Feldman 
1705b9b2fafSBrian Feldman 	return (dh_gen_key(dh));
1715b9b2fafSBrian Feldman }
1725b9b2fafSBrian Feldman 
1735b9b2fafSBrian Feldman DH *
1745b9b2fafSBrian Feldman dh_new_group(BIGNUM *gen, BIGNUM *modulus)
1755b9b2fafSBrian Feldman {
1765b9b2fafSBrian Feldman 	DH *dh;
1775b9b2fafSBrian Feldman 
1785b9b2fafSBrian Feldman 	dh = DH_new();
1795b9b2fafSBrian Feldman 	if (dh == NULL)
1805b9b2fafSBrian Feldman 		fatal("DH_new");
1815b9b2fafSBrian Feldman 	dh->p = modulus;
1825b9b2fafSBrian Feldman 	dh->g = gen;
1835b9b2fafSBrian Feldman 
1845b9b2fafSBrian Feldman 	return (dh_gen_key(dh));
1855b9b2fafSBrian Feldman }
1865b9b2fafSBrian Feldman 
1875b9b2fafSBrian Feldman DH *
1885b9b2fafSBrian Feldman dh_new_group1()
1895b9b2fafSBrian Feldman {
1905b9b2fafSBrian Feldman 	static char *gen = "2", *group1 =
1915b9b2fafSBrian Feldman 	    "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
1925b9b2fafSBrian Feldman 	    "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
1935b9b2fafSBrian Feldman 	    "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
1945b9b2fafSBrian Feldman 	    "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
1955b9b2fafSBrian Feldman 	    "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
1965b9b2fafSBrian Feldman 	    "FFFFFFFF" "FFFFFFFF";
1975b9b2fafSBrian Feldman 
1985b9b2fafSBrian Feldman 	return (dh_new_group_asc(gen, group1));
1995b9b2fafSBrian Feldman }
2005b9b2fafSBrian Feldman 
201a04a10f8SKris Kennaway void
202a04a10f8SKris Kennaway dump_digest(unsigned char *digest, int len)
203a04a10f8SKris Kennaway {
204a04a10f8SKris Kennaway 	int i;
205a04a10f8SKris Kennaway 	for (i = 0; i< len; i++){
206a04a10f8SKris Kennaway 		fprintf(stderr, "%02x", digest[i]);
207a04a10f8SKris Kennaway 		if(i%2!=0)
208a04a10f8SKris Kennaway 			fprintf(stderr, " ");
209a04a10f8SKris Kennaway 	}
210a04a10f8SKris Kennaway 	fprintf(stderr, "\n");
211a04a10f8SKris Kennaway }
212a04a10f8SKris Kennaway 
213a04a10f8SKris Kennaway unsigned char *
214a04a10f8SKris Kennaway kex_hash(
215a04a10f8SKris Kennaway     char *client_version_string,
216a04a10f8SKris Kennaway     char *server_version_string,
217a04a10f8SKris Kennaway     char *ckexinit, int ckexinitlen,
218a04a10f8SKris Kennaway     char *skexinit, int skexinitlen,
219a04a10f8SKris Kennaway     char *serverhostkeyblob, int sbloblen,
220a04a10f8SKris Kennaway     BIGNUM *client_dh_pub,
221a04a10f8SKris Kennaway     BIGNUM *server_dh_pub,
222a04a10f8SKris Kennaway     BIGNUM *shared_secret)
223a04a10f8SKris Kennaway {
224a04a10f8SKris Kennaway 	Buffer b;
225a04a10f8SKris Kennaway 	static unsigned char digest[EVP_MAX_MD_SIZE];
226a04a10f8SKris Kennaway 	EVP_MD *evp_md = EVP_sha1();
227a04a10f8SKris Kennaway 	EVP_MD_CTX md;
228a04a10f8SKris Kennaway 
229a04a10f8SKris Kennaway 	buffer_init(&b);
230a04a10f8SKris Kennaway 	buffer_put_string(&b, client_version_string, strlen(client_version_string));
231a04a10f8SKris Kennaway 	buffer_put_string(&b, server_version_string, strlen(server_version_string));
232a04a10f8SKris Kennaway 
233a04a10f8SKris Kennaway 	/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
234a04a10f8SKris Kennaway 	buffer_put_int(&b, ckexinitlen+1);
235a04a10f8SKris Kennaway 	buffer_put_char(&b, SSH2_MSG_KEXINIT);
236a04a10f8SKris Kennaway 	buffer_append(&b, ckexinit, ckexinitlen);
237a04a10f8SKris Kennaway 	buffer_put_int(&b, skexinitlen+1);
238a04a10f8SKris Kennaway 	buffer_put_char(&b, SSH2_MSG_KEXINIT);
239a04a10f8SKris Kennaway 	buffer_append(&b, skexinit, skexinitlen);
240a04a10f8SKris Kennaway 
241a04a10f8SKris Kennaway 	buffer_put_string(&b, serverhostkeyblob, sbloblen);
242a04a10f8SKris Kennaway 	buffer_put_bignum2(&b, client_dh_pub);
243a04a10f8SKris Kennaway 	buffer_put_bignum2(&b, server_dh_pub);
244a04a10f8SKris Kennaway 	buffer_put_bignum2(&b, shared_secret);
245a04a10f8SKris Kennaway 
246a04a10f8SKris Kennaway #ifdef DEBUG_KEX
247a04a10f8SKris Kennaway 	buffer_dump(&b);
248a04a10f8SKris Kennaway #endif
249a04a10f8SKris Kennaway 
250a04a10f8SKris Kennaway 	EVP_DigestInit(&md, evp_md);
251a04a10f8SKris Kennaway 	EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
252a04a10f8SKris Kennaway 	EVP_DigestFinal(&md, digest, NULL);
253a04a10f8SKris Kennaway 
254a04a10f8SKris Kennaway 	buffer_free(&b);
255a04a10f8SKris Kennaway 
256a04a10f8SKris Kennaway #ifdef DEBUG_KEX
257a04a10f8SKris Kennaway 	dump_digest(digest, evp_md->md_size);
258a04a10f8SKris Kennaway #endif
259a04a10f8SKris Kennaway 	return digest;
260a04a10f8SKris Kennaway }
261a04a10f8SKris Kennaway 
262a04a10f8SKris Kennaway unsigned char *
2635b9b2fafSBrian Feldman kex_hash_gex(
2645b9b2fafSBrian Feldman     char *client_version_string,
2655b9b2fafSBrian Feldman     char *server_version_string,
2665b9b2fafSBrian Feldman     char *ckexinit, int ckexinitlen,
2675b9b2fafSBrian Feldman     char *skexinit, int skexinitlen,
2685b9b2fafSBrian Feldman     char *serverhostkeyblob, int sbloblen,
2695b9b2fafSBrian Feldman     int minbits, BIGNUM *prime, BIGNUM *gen,
2705b9b2fafSBrian Feldman     BIGNUM *client_dh_pub,
2715b9b2fafSBrian Feldman     BIGNUM *server_dh_pub,
2725b9b2fafSBrian Feldman     BIGNUM *shared_secret)
2735b9b2fafSBrian Feldman {
2745b9b2fafSBrian Feldman 	Buffer b;
2755b9b2fafSBrian Feldman 	static unsigned char digest[EVP_MAX_MD_SIZE];
2765b9b2fafSBrian Feldman 	EVP_MD *evp_md = EVP_sha1();
2775b9b2fafSBrian Feldman 	EVP_MD_CTX md;
2785b9b2fafSBrian Feldman 
2795b9b2fafSBrian Feldman 	buffer_init(&b);
2805b9b2fafSBrian Feldman 	buffer_put_string(&b, client_version_string, strlen(client_version_string));
2815b9b2fafSBrian Feldman 	buffer_put_string(&b, server_version_string, strlen(server_version_string));
2825b9b2fafSBrian Feldman 
2835b9b2fafSBrian Feldman 	/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
2845b9b2fafSBrian Feldman 	buffer_put_int(&b, ckexinitlen+1);
2855b9b2fafSBrian Feldman 	buffer_put_char(&b, SSH2_MSG_KEXINIT);
2865b9b2fafSBrian Feldman 	buffer_append(&b, ckexinit, ckexinitlen);
2875b9b2fafSBrian Feldman 	buffer_put_int(&b, skexinitlen+1);
2885b9b2fafSBrian Feldman 	buffer_put_char(&b, SSH2_MSG_KEXINIT);
2895b9b2fafSBrian Feldman 	buffer_append(&b, skexinit, skexinitlen);
2905b9b2fafSBrian Feldman 
2915b9b2fafSBrian Feldman 	buffer_put_string(&b, serverhostkeyblob, sbloblen);
2925b9b2fafSBrian Feldman 	buffer_put_int(&b, minbits);
2935b9b2fafSBrian Feldman 	buffer_put_bignum2(&b, prime);
2945b9b2fafSBrian Feldman 	buffer_put_bignum2(&b, gen);
2955b9b2fafSBrian Feldman 	buffer_put_bignum2(&b, client_dh_pub);
2965b9b2fafSBrian Feldman 	buffer_put_bignum2(&b, server_dh_pub);
2975b9b2fafSBrian Feldman 	buffer_put_bignum2(&b, shared_secret);
2985b9b2fafSBrian Feldman 
2995b9b2fafSBrian Feldman #ifdef DEBUG_KEX
3005b9b2fafSBrian Feldman 	buffer_dump(&b);
3015b9b2fafSBrian Feldman #endif
3025b9b2fafSBrian Feldman 
3035b9b2fafSBrian Feldman 	EVP_DigestInit(&md, evp_md);
3045b9b2fafSBrian Feldman 	EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
3055b9b2fafSBrian Feldman 	EVP_DigestFinal(&md, digest, NULL);
3065b9b2fafSBrian Feldman 
3075b9b2fafSBrian Feldman 	buffer_free(&b);
3085b9b2fafSBrian Feldman 
3095b9b2fafSBrian Feldman #ifdef DEBUG_KEX
3105b9b2fafSBrian Feldman 	dump_digest(digest, evp_md->md_size);
3115b9b2fafSBrian Feldman #endif
3125b9b2fafSBrian Feldman 	return digest;
3135b9b2fafSBrian Feldman }
3145b9b2fafSBrian Feldman 
3155b9b2fafSBrian Feldman unsigned char *
316a04a10f8SKris Kennaway derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
317a04a10f8SKris Kennaway {
318a04a10f8SKris Kennaway 	Buffer b;
319a04a10f8SKris Kennaway 	EVP_MD *evp_md = EVP_sha1();
320a04a10f8SKris Kennaway 	EVP_MD_CTX md;
321a04a10f8SKris Kennaway 	char c = id;
322a04a10f8SKris Kennaway 	int have;
323a04a10f8SKris Kennaway 	int mdsz = evp_md->md_size;
324a04a10f8SKris Kennaway 	unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
325a04a10f8SKris Kennaway 
326a04a10f8SKris Kennaway 	buffer_init(&b);
327a04a10f8SKris Kennaway 	buffer_put_bignum2(&b, shared_secret);
328a04a10f8SKris Kennaway 
329a04a10f8SKris Kennaway 	EVP_DigestInit(&md, evp_md);
330a04a10f8SKris Kennaway 	EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));	/* shared_secret K */
331a04a10f8SKris Kennaway 	EVP_DigestUpdate(&md, hash, mdsz);		/* transport-06 */
332a04a10f8SKris Kennaway 	EVP_DigestUpdate(&md, &c, 1);			/* key id */
333a04a10f8SKris Kennaway 	EVP_DigestUpdate(&md, hash, mdsz);		/* session id */
334a04a10f8SKris Kennaway 	EVP_DigestFinal(&md, digest, NULL);
335a04a10f8SKris Kennaway 
336a04a10f8SKris Kennaway 	/* expand */
337a04a10f8SKris Kennaway 	for (have = mdsz; need > have; have += mdsz) {
338a04a10f8SKris Kennaway 		EVP_DigestInit(&md, evp_md);
339a04a10f8SKris Kennaway 		EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
340a04a10f8SKris Kennaway 		EVP_DigestUpdate(&md, hash, mdsz);
341a04a10f8SKris Kennaway 		EVP_DigestUpdate(&md, digest, have);
342a04a10f8SKris Kennaway 		EVP_DigestFinal(&md, digest + have, NULL);
343a04a10f8SKris Kennaway 	}
344a04a10f8SKris Kennaway 	buffer_free(&b);
345a04a10f8SKris Kennaway #ifdef DEBUG_KEX
346a04a10f8SKris Kennaway 	fprintf(stderr, "Digest '%c'== ", c);
347a04a10f8SKris Kennaway 	dump_digest(digest, need);
348a04a10f8SKris Kennaway #endif
349a04a10f8SKris Kennaway 	return digest;
350a04a10f8SKris Kennaway }
351a04a10f8SKris Kennaway 
352a04a10f8SKris Kennaway #define NKEYS	6
353a04a10f8SKris Kennaway 
354a04a10f8SKris Kennaway #define	MAX_PROP	20
355a04a10f8SKris Kennaway #define	SEP	","
356a04a10f8SKris Kennaway 
357a04a10f8SKris Kennaway char *
358a04a10f8SKris Kennaway get_match(char *client, char *server)
359a04a10f8SKris Kennaway {
360a04a10f8SKris Kennaway 	char *sproposals[MAX_PROP];
361b66f2d16SKris Kennaway 	char *c, *s, *p, *ret, *cp, *sp;
362a04a10f8SKris Kennaway 	int i, j, nproposals;
363a04a10f8SKris Kennaway 
364b66f2d16SKris Kennaway 	c = cp = xstrdup(client);
365b66f2d16SKris Kennaway 	s = sp = xstrdup(server);
3662632b0c8SKris Kennaway 
367b66f2d16SKris Kennaway 	for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
368b66f2d16SKris Kennaway 	     (p = strsep(&sp, SEP)), i++) {
369a04a10f8SKris Kennaway 		if (i < MAX_PROP)
370a04a10f8SKris Kennaway 			sproposals[i] = p;
371a04a10f8SKris Kennaway 		else
372a04a10f8SKris Kennaway 			break;
373a04a10f8SKris Kennaway 	}
374a04a10f8SKris Kennaway 	nproposals = i;
375a04a10f8SKris Kennaway 
376b66f2d16SKris Kennaway 	for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
377b66f2d16SKris Kennaway 	     (p = strsep(&cp, SEP)), i++) {
3782632b0c8SKris Kennaway 		for (j = 0; j < nproposals; j++) {
3792632b0c8SKris Kennaway 			if (strcmp(p, sproposals[j]) == 0) {
3802632b0c8SKris Kennaway 				ret = xstrdup(p);
3812632b0c8SKris Kennaway 				xfree(c);
3822632b0c8SKris Kennaway 				xfree(s);
3832632b0c8SKris Kennaway 				return ret;
384a04a10f8SKris Kennaway 			}
3852632b0c8SKris Kennaway 		}
3862632b0c8SKris Kennaway 	}
3872632b0c8SKris Kennaway 	xfree(c);
3882632b0c8SKris Kennaway 	xfree(s);
389a04a10f8SKris Kennaway 	return NULL;
390a04a10f8SKris Kennaway }
391a04a10f8SKris Kennaway void
392a04a10f8SKris Kennaway choose_enc(Enc *enc, char *client, char *server)
393a04a10f8SKris Kennaway {
394a04a10f8SKris Kennaway 	char *name = get_match(client, server);
395a04a10f8SKris Kennaway 	if (name == NULL)
396a04a10f8SKris Kennaway 		fatal("no matching cipher found: client %s server %s", client, server);
3975b9b2fafSBrian Feldman 	enc->cipher = cipher_by_name(name);
3985b9b2fafSBrian Feldman 	if (enc->cipher == NULL)
3995b9b2fafSBrian Feldman 		fatal("matching cipher is not supported: %s", name);
400a04a10f8SKris Kennaway 	enc->name = name;
401a04a10f8SKris Kennaway 	enc->enabled = 0;
402a04a10f8SKris Kennaway 	enc->iv = NULL;
403a04a10f8SKris Kennaway 	enc->key = NULL;
404a04a10f8SKris Kennaway }
405a04a10f8SKris Kennaway void
406a04a10f8SKris Kennaway choose_mac(Mac *mac, char *client, char *server)
407a04a10f8SKris Kennaway {
408a04a10f8SKris Kennaway 	char *name = get_match(client, server);
409a04a10f8SKris Kennaway 	if (name == NULL)
410a04a10f8SKris Kennaway 		fatal("no matching mac found: client %s server %s", client, server);
411a04a10f8SKris Kennaway 	if (strcmp(name, "hmac-md5") == 0) {
412a04a10f8SKris Kennaway 		mac->md = EVP_md5();
413a04a10f8SKris Kennaway 	} else if (strcmp(name, "hmac-sha1") == 0) {
414a04a10f8SKris Kennaway 		mac->md = EVP_sha1();
415a04a10f8SKris Kennaway 	} else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
416a04a10f8SKris Kennaway 		mac->md = EVP_ripemd160();
417a04a10f8SKris Kennaway 	} else {
418a04a10f8SKris Kennaway 		fatal("unsupported mac %s", name);
419a04a10f8SKris Kennaway 	}
420a04a10f8SKris Kennaway 	mac->name = name;
421a04a10f8SKris Kennaway 	mac->mac_len = mac->md->md_size;
422a04a10f8SKris Kennaway 	mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
423a04a10f8SKris Kennaway 	mac->key = NULL;
424a04a10f8SKris Kennaway 	mac->enabled = 0;
425a04a10f8SKris Kennaway }
426a04a10f8SKris Kennaway void
427a04a10f8SKris Kennaway choose_comp(Comp *comp, char *client, char *server)
428a04a10f8SKris Kennaway {
429a04a10f8SKris Kennaway 	char *name = get_match(client, server);
430a04a10f8SKris Kennaway 	if (name == NULL)
431a04a10f8SKris Kennaway 		fatal("no matching comp found: client %s server %s", client, server);
432a04a10f8SKris Kennaway 	if (strcmp(name, "zlib") == 0) {
433a04a10f8SKris Kennaway 		comp->type = 1;
434a04a10f8SKris Kennaway 	} else if (strcmp(name, "none") == 0) {
435a04a10f8SKris Kennaway 		comp->type = 0;
436a04a10f8SKris Kennaway 	} else {
437a04a10f8SKris Kennaway 		fatal("unsupported comp %s", name);
438a04a10f8SKris Kennaway 	}
439a04a10f8SKris Kennaway 	comp->name = name;
440a04a10f8SKris Kennaway }
441a04a10f8SKris Kennaway void
442a04a10f8SKris Kennaway choose_kex(Kex *k, char *client, char *server)
443a04a10f8SKris Kennaway {
444a04a10f8SKris Kennaway 	k->name = get_match(client, server);
445a04a10f8SKris Kennaway 	if (k->name == NULL)
446a04a10f8SKris Kennaway 		fatal("no kex alg");
4475b9b2fafSBrian Feldman 	if (strcmp(k->name, KEX_DH1) == 0) {
4485b9b2fafSBrian Feldman 		k->kex_type = DH_GRP1_SHA1;
4495b9b2fafSBrian Feldman 	} else if (strcmp(k->name, KEX_DHGEX) == 0) {
4505b9b2fafSBrian Feldman 		k->kex_type = DH_GEX_SHA1;
4515b9b2fafSBrian Feldman 	} else
452a04a10f8SKris Kennaway 		fatal("bad kex alg %s", k->name);
453a04a10f8SKris Kennaway }
454a04a10f8SKris Kennaway void
455a04a10f8SKris Kennaway choose_hostkeyalg(Kex *k, char *client, char *server)
456a04a10f8SKris Kennaway {
457a04a10f8SKris Kennaway 	k->hostkeyalg = get_match(client, server);
458a04a10f8SKris Kennaway 	if (k->hostkeyalg == NULL)
459a04a10f8SKris Kennaway 		fatal("no hostkey alg");
460a04a10f8SKris Kennaway 	if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
461a04a10f8SKris Kennaway 		fatal("bad hostkey alg %s", k->hostkeyalg);
462a04a10f8SKris Kennaway }
463a04a10f8SKris Kennaway 
464a04a10f8SKris Kennaway Kex *
465a04a10f8SKris Kennaway kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
466a04a10f8SKris Kennaway {
467a04a10f8SKris Kennaway 	int mode;
468a04a10f8SKris Kennaway 	int ctos;				/* direction: if true client-to-server */
469a04a10f8SKris Kennaway 	int need;
470a04a10f8SKris Kennaway 	Kex *k;
471a04a10f8SKris Kennaway 
472a04a10f8SKris Kennaway 	k = xmalloc(sizeof(*k));
473a04a10f8SKris Kennaway 	memset(k, 0, sizeof(*k));
474a04a10f8SKris Kennaway 	k->server = server;
475a04a10f8SKris Kennaway 
476a04a10f8SKris Kennaway 	for (mode = 0; mode < MODE_MAX; mode++) {
477a04a10f8SKris Kennaway 		int nenc, nmac, ncomp;
478a04a10f8SKris Kennaway 		ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
479a04a10f8SKris Kennaway 		nenc  = ctos ? PROPOSAL_ENC_ALGS_CTOS  : PROPOSAL_ENC_ALGS_STOC;
480a04a10f8SKris Kennaway 		nmac  = ctos ? PROPOSAL_MAC_ALGS_CTOS  : PROPOSAL_MAC_ALGS_STOC;
481a04a10f8SKris Kennaway 		ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
482a04a10f8SKris Kennaway 		choose_enc (&k->enc [mode], cprop[nenc],  sprop[nenc]);
483a04a10f8SKris Kennaway 		choose_mac (&k->mac [mode], cprop[nmac],  sprop[nmac]);
484a04a10f8SKris Kennaway 		choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
485a04a10f8SKris Kennaway 		debug("kex: %s %s %s %s",
486a04a10f8SKris Kennaway 		    ctos ? "client->server" : "server->client",
487a04a10f8SKris Kennaway 		    k->enc[mode].name,
488a04a10f8SKris Kennaway 		    k->mac[mode].name,
489a04a10f8SKris Kennaway 		    k->comp[mode].name);
490a04a10f8SKris Kennaway 	}
491a04a10f8SKris Kennaway 	choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
492a04a10f8SKris Kennaway 	choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
493a04a10f8SKris Kennaway 	    sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
494a04a10f8SKris Kennaway 	need = 0;
495a04a10f8SKris Kennaway 	for (mode = 0; mode < MODE_MAX; mode++) {
4965b9b2fafSBrian Feldman 	    if (need < k->enc[mode].cipher->key_len)
4975b9b2fafSBrian Feldman 		    need = k->enc[mode].cipher->key_len;
4985b9b2fafSBrian Feldman 	    if (need < k->enc[mode].cipher->block_size)
4995b9b2fafSBrian Feldman 		    need = k->enc[mode].cipher->block_size;
500a04a10f8SKris Kennaway 	    if (need < k->mac[mode].key_len)
501a04a10f8SKris Kennaway 		    need = k->mac[mode].key_len;
502a04a10f8SKris Kennaway 	}
5032632b0c8SKris Kennaway 	/* XXX need runden? */
504a04a10f8SKris Kennaway 	k->we_need = need;
505a04a10f8SKris Kennaway 	return k;
506a04a10f8SKris Kennaway }
507a04a10f8SKris Kennaway 
508a04a10f8SKris Kennaway int
509a04a10f8SKris Kennaway kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
510a04a10f8SKris Kennaway {
511a04a10f8SKris Kennaway 	int i;
512a04a10f8SKris Kennaway 	int mode;
513a04a10f8SKris Kennaway 	int ctos;
514a04a10f8SKris Kennaway 	unsigned char *keys[NKEYS];
515a04a10f8SKris Kennaway 
516a04a10f8SKris Kennaway 	for (i = 0; i < NKEYS; i++)
517a04a10f8SKris Kennaway 		keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
518a04a10f8SKris Kennaway 
519a04a10f8SKris Kennaway 	for (mode = 0; mode < MODE_MAX; mode++) {
520a04a10f8SKris Kennaway 		ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
521a04a10f8SKris Kennaway 		k->enc[mode].iv  = keys[ctos ? 0 : 1];
522a04a10f8SKris Kennaway 		k->enc[mode].key = keys[ctos ? 2 : 3];
523a04a10f8SKris Kennaway 		k->mac[mode].key = keys[ctos ? 4 : 5];
524a04a10f8SKris Kennaway 	}
525a04a10f8SKris Kennaway 	return 0;
526a04a10f8SKris Kennaway }
527