kex.c revision 61209
160573Skris/*
260573Skris * Copyright (c) 2000 Markus Friedl.  All rights reserved.
360573Skris *
460573Skris * Redistribution and use in source and binary forms, with or without
560573Skris * modification, are permitted provided that the following conditions
660573Skris * are met:
760573Skris * 1. Redistributions of source code must retain the above copyright
860573Skris *    notice, this list of conditions and the following disclaimer.
960573Skris * 2. Redistributions in binary form must reproduce the above copyright
1060573Skris *    notice, this list of conditions and the following disclaimer in the
1160573Skris *    documentation and/or other materials provided with the distribution.
1260573Skris * 3. All advertising materials mentioning features or use of this software
1360573Skris *    must display the following acknowledgement:
1460573Skris *      This product includes software developed by Markus Friedl.
1560573Skris * 4. The name of the author may not be used to endorse or promote products
1660573Skris *    derived from this software without specific prior written permission.
1760573Skris *
1860573Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1960573Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2060573Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2160573Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2260573Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2360573Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2460573Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2560573Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2660573Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2760573Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2860573Skris */
2960573Skris
3060573Skris#include "includes.h"
3161209SkrisRCSID("$Id: kex.c,v 1.7 2000/05/25 20:45:20 markus Exp $");
3260573Skris
3360573Skris#include "ssh.h"
3460573Skris#include "ssh2.h"
3560573Skris#include "xmalloc.h"
3660573Skris#include "buffer.h"
3760573Skris#include "bufaux.h"
3861209Skris#include "packet.h"
3960573Skris#include "cipher.h"
4060573Skris#include "compat.h"
4160573Skris
4260573Skris#include <openssl/bn.h>
4360573Skris#include <openssl/dh.h>
4460573Skris
4560573Skris#include <openssl/crypto.h>
4660573Skris#include <openssl/bio.h>
4760573Skris#include <openssl/bn.h>
4860573Skris#include <openssl/dh.h>
4960573Skris#include <openssl/pem.h>
5060573Skris
5160573Skris#include "kex.h"
5260573Skris
5361209Skris#define KEX_COOKIE_LEN	16
5461209Skris
5560573SkrisBuffer *
5660573Skriskex_init(char *myproposal[PROPOSAL_MAX])
5760573Skris{
5861209Skris	int first_kex_packet_follows = 0;
5961209Skris	unsigned char cookie[KEX_COOKIE_LEN];
6060573Skris	u_int32_t rand = 0;
6160573Skris	int i;
6260573Skris	Buffer *ki = xmalloc(sizeof(*ki));
6361209Skris	for (i = 0; i < KEX_COOKIE_LEN; i++) {
6460573Skris		if (i % 4 == 0)
6560573Skris			rand = arc4random();
6660573Skris		cookie[i] = rand & 0xff;
6760573Skris		rand >>= 8;
6860573Skris	}
6960573Skris	buffer_init(ki);
7060573Skris	buffer_append(ki, (char *)cookie, sizeof cookie);
7160573Skris	for (i = 0; i < PROPOSAL_MAX; i++)
7260573Skris		buffer_put_cstring(ki, myproposal[i]);
7361209Skris	buffer_put_char(ki, first_kex_packet_follows);
7461209Skris	buffer_put_int(ki, 0);				/* uint32 reserved */
7560573Skris	return ki;
7660573Skris}
7760573Skris
7861209Skris/* send kexinit, parse and save reply */
7961209Skrisvoid
8061209Skriskex_exchange_kexinit(
8161209Skris    Buffer *my_kexinit, Buffer *peer_kexint,
8261209Skris    char *peer_proposal[PROPOSAL_MAX])
8361209Skris{
8461209Skris	int i;
8561209Skris	char *ptr;
8661209Skris	int plen;
8761209Skris
8861209Skris	debug("send KEXINIT");
8961209Skris	packet_start(SSH2_MSG_KEXINIT);
9061209Skris	packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));
9161209Skris	packet_send();
9261209Skris	packet_write_wait();
9361209Skris	debug("done");
9461209Skris
9561209Skris	/*
9661209Skris	 * read and save raw KEXINIT payload in buffer. this is used during
9761209Skris	 * computation of the session_id and the session keys.
9861209Skris	 */
9961209Skris	debug("wait KEXINIT");
10061209Skris	packet_read_expect(&plen, SSH2_MSG_KEXINIT);
10161209Skris	ptr = packet_get_raw(&plen);
10261209Skris	buffer_append(peer_kexint, ptr, plen);
10361209Skris
10461209Skris	/* parse packet and save algorithm proposal */
10561209Skris	/* skip cookie */
10661209Skris	for (i = 0; i < KEX_COOKIE_LEN; i++)
10761209Skris		packet_get_char();
10861209Skris	/* extract kex init proposal strings */
10961209Skris	for (i = 0; i < PROPOSAL_MAX; i++) {
11061209Skris		peer_proposal[i] = packet_get_string(NULL);
11161209Skris		debug("got kexinit: %s", peer_proposal[i]);
11261209Skris	}
11361209Skris	/* first kex follow / reserved */
11461209Skris	i = packet_get_char();
11561209Skris	debug("first kex follow: %d ", i);
11661209Skris	i = packet_get_int();
11761209Skris	debug("reserved: %d ", i);
11861209Skris	packet_done();
11961209Skris	debug("done");
12061209Skris}
12161209Skris
12260573Skris/* diffie-hellman-group1-sha1 */
12360573Skris
12460573Skrisint
12560573Skrisdh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
12660573Skris{
12760573Skris	int i;
12860573Skris	int n = BN_num_bits(dh_pub);
12960573Skris	int bits_set = 0;
13060573Skris
13160573Skris	/* we only accept g==2 */
13260573Skris	if (!BN_is_word(dh->g, 2)) {
13360573Skris		log("invalid DH base != 2");
13460573Skris		return 0;
13560573Skris	}
13660573Skris	if (dh_pub->neg) {
13760573Skris		log("invalid public DH value: negativ");
13860573Skris		return 0;
13960573Skris	}
14060573Skris	for (i = 0; i <= n; i++)
14160573Skris		if (BN_is_bit_set(dh_pub, i))
14260573Skris			bits_set++;
14360573Skris	debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
14460573Skris
14560573Skris	/* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
14660573Skris	if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
14760573Skris		return 1;
14860573Skris	log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
14960573Skris	return 0;
15060573Skris}
15160573Skris
15260573SkrisDH *
15360573Skrisdh_new_group1()
15460573Skris{
15560573Skris	static char *group1 =
15660573Skris	    "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
15760573Skris	    "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
15860573Skris	    "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
15960573Skris	    "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
16060573Skris	    "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
16160573Skris	    "FFFFFFFF" "FFFFFFFF";
16260573Skris	DH *dh;
16360573Skris	int ret, tries = 0;
16460573Skris	dh = DH_new();
16560573Skris	if(dh == NULL)
16660573Skris		fatal("DH_new");
16760573Skris	ret = BN_hex2bn(&dh->p, group1);
16860573Skris	if(ret<0)
16960573Skris		fatal("BN_hex2bn");
17060573Skris	dh->g = BN_new();
17160573Skris	if(dh->g == NULL)
17260573Skris		fatal("DH_new g");
17360573Skris	BN_set_word(dh->g, 2);
17460573Skris	do {
17560573Skris		if (DH_generate_key(dh) == 0)
17660573Skris			fatal("DH_generate_key");
17760573Skris		if (tries++ > 10)
17860573Skris			fatal("dh_new_group1: too many bad keys: giving up");
17960573Skris	} while (!dh_pub_is_valid(dh, dh->pub_key));
18060573Skris	return dh;
18160573Skris}
18260573Skris
18360573Skrisvoid
18460573Skrisdump_digest(unsigned char *digest, int len)
18560573Skris{
18660573Skris	int i;
18760573Skris	for (i = 0; i< len; i++){
18860573Skris		fprintf(stderr, "%02x", digest[i]);
18960573Skris		if(i%2!=0)
19060573Skris			fprintf(stderr, " ");
19160573Skris	}
19260573Skris	fprintf(stderr, "\n");
19360573Skris}
19460573Skris
19560573Skrisunsigned char *
19660573Skriskex_hash(
19760573Skris    char *client_version_string,
19860573Skris    char *server_version_string,
19960573Skris    char *ckexinit, int ckexinitlen,
20060573Skris    char *skexinit, int skexinitlen,
20160573Skris    char *serverhostkeyblob, int sbloblen,
20260573Skris    BIGNUM *client_dh_pub,
20360573Skris    BIGNUM *server_dh_pub,
20460573Skris    BIGNUM *shared_secret)
20560573Skris{
20660573Skris	Buffer b;
20760573Skris	static unsigned char digest[EVP_MAX_MD_SIZE];
20860573Skris	EVP_MD *evp_md = EVP_sha1();
20960573Skris	EVP_MD_CTX md;
21060573Skris
21160573Skris	buffer_init(&b);
21260573Skris	buffer_put_string(&b, client_version_string, strlen(client_version_string));
21360573Skris	buffer_put_string(&b, server_version_string, strlen(server_version_string));
21460573Skris
21560573Skris	/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
21660573Skris	buffer_put_int(&b, ckexinitlen+1);
21760573Skris	buffer_put_char(&b, SSH2_MSG_KEXINIT);
21860573Skris	buffer_append(&b, ckexinit, ckexinitlen);
21960573Skris	buffer_put_int(&b, skexinitlen+1);
22060573Skris	buffer_put_char(&b, SSH2_MSG_KEXINIT);
22160573Skris	buffer_append(&b, skexinit, skexinitlen);
22260573Skris
22360573Skris	buffer_put_string(&b, serverhostkeyblob, sbloblen);
22460573Skris	buffer_put_bignum2(&b, client_dh_pub);
22560573Skris	buffer_put_bignum2(&b, server_dh_pub);
22660573Skris	buffer_put_bignum2(&b, shared_secret);
22760573Skris
22860573Skris#ifdef DEBUG_KEX
22960573Skris	buffer_dump(&b);
23060573Skris#endif
23160573Skris
23260573Skris	EVP_DigestInit(&md, evp_md);
23360573Skris	EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
23460573Skris	EVP_DigestFinal(&md, digest, NULL);
23560573Skris
23660573Skris	buffer_free(&b);
23760573Skris
23860573Skris#ifdef DEBUG_KEX
23960573Skris	dump_digest(digest, evp_md->md_size);
24060573Skris#endif
24160573Skris	return digest;
24260573Skris}
24360573Skris
24460573Skrisunsigned char *
24560573Skrisderive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
24660573Skris{
24760573Skris	Buffer b;
24860573Skris	EVP_MD *evp_md = EVP_sha1();
24960573Skris	EVP_MD_CTX md;
25060573Skris	char c = id;
25160573Skris	int have;
25260573Skris	int mdsz = evp_md->md_size;
25360573Skris	unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
25460573Skris
25560573Skris	buffer_init(&b);
25660573Skris	buffer_put_bignum2(&b, shared_secret);
25760573Skris
25860573Skris	EVP_DigestInit(&md, evp_md);
25960573Skris	EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));	/* shared_secret K */
26060573Skris	EVP_DigestUpdate(&md, hash, mdsz);		/* transport-06 */
26160573Skris	EVP_DigestUpdate(&md, &c, 1);			/* key id */
26260573Skris	EVP_DigestUpdate(&md, hash, mdsz);		/* session id */
26360573Skris	EVP_DigestFinal(&md, digest, NULL);
26460573Skris
26560573Skris	/* expand */
26660573Skris	for (have = mdsz; need > have; have += mdsz) {
26760573Skris		EVP_DigestInit(&md, evp_md);
26860573Skris		EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
26960573Skris		EVP_DigestUpdate(&md, hash, mdsz);
27060573Skris		EVP_DigestUpdate(&md, digest, have);
27160573Skris		EVP_DigestFinal(&md, digest + have, NULL);
27260573Skris	}
27360573Skris	buffer_free(&b);
27460573Skris#ifdef DEBUG_KEX
27560573Skris	fprintf(stderr, "Digest '%c'== ", c);
27660573Skris	dump_digest(digest, need);
27760573Skris#endif
27860573Skris	return digest;
27960573Skris}
28060573Skris
28160573Skris#define NKEYS	6
28260573Skris
28360573Skris#define	MAX_PROP	20
28460573Skris#define	SEP	","
28560573Skris
28660573Skrischar *
28760573Skrisget_match(char *client, char *server)
28860573Skris{
28960573Skris	char *sproposals[MAX_PROP];
29061209Skris	char *c, *s, *p, *ret;
29160573Skris	int i, j, nproposals;
29260573Skris
29361209Skris	c = xstrdup(client);
29461209Skris	s = xstrdup(server);
29561209Skris
29661209Skris	for ((p = strtok(s, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
29760573Skris		if (i < MAX_PROP)
29860573Skris			sproposals[i] = p;
29960573Skris		else
30060573Skris			break;
30160573Skris	}
30260573Skris	nproposals = i;
30360573Skris
30461209Skris	for ((p = strtok(c, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
30561209Skris		for (j = 0; j < nproposals; j++) {
30661209Skris			if (strcmp(p, sproposals[j]) == 0) {
30761209Skris				ret = xstrdup(p);
30861209Skris				xfree(c);
30961209Skris				xfree(s);
31061209Skris				return ret;
31161209Skris			}
31261209Skris		}
31360573Skris	}
31461209Skris	xfree(c);
31561209Skris	xfree(s);
31660573Skris	return NULL;
31760573Skris}
31860573Skrisvoid
31960573Skrischoose_enc(Enc *enc, char *client, char *server)
32060573Skris{
32160573Skris	char *name = get_match(client, server);
32260573Skris	if (name == NULL)
32360573Skris		fatal("no matching cipher found: client %s server %s", client, server);
32460573Skris	enc->type = cipher_number(name);
32560573Skris
32660573Skris	switch (enc->type) {
32760573Skris	case SSH_CIPHER_3DES_CBC:
32860573Skris		enc->key_len = 24;
32960573Skris		enc->iv_len = 8;
33060573Skris		enc->block_size = 8;
33160573Skris		break;
33260573Skris	case SSH_CIPHER_BLOWFISH_CBC:
33360573Skris	case SSH_CIPHER_CAST128_CBC:
33460573Skris		enc->key_len = 16;
33560573Skris		enc->iv_len = 8;
33660573Skris		enc->block_size = 8;
33760573Skris		break;
33860573Skris	case SSH_CIPHER_ARCFOUR:
33960573Skris		enc->key_len = 16;
34060573Skris		enc->iv_len = 0;
34160573Skris		enc->block_size = 8;
34260573Skris		break;
34360573Skris	default:
34460573Skris		fatal("unsupported cipher %s", name);
34560573Skris	}
34660573Skris	enc->name = name;
34760573Skris	enc->enabled = 0;
34860573Skris	enc->iv = NULL;
34960573Skris	enc->key = NULL;
35060573Skris}
35160573Skrisvoid
35260573Skrischoose_mac(Mac *mac, char *client, char *server)
35360573Skris{
35460573Skris	char *name = get_match(client, server);
35560573Skris	if (name == NULL)
35660573Skris		fatal("no matching mac found: client %s server %s", client, server);
35760573Skris	if (strcmp(name, "hmac-md5") == 0) {
35860573Skris		mac->md = EVP_md5();
35960573Skris	} else if (strcmp(name, "hmac-sha1") == 0) {
36060573Skris		mac->md = EVP_sha1();
36160573Skris	} else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
36260573Skris		mac->md = EVP_ripemd160();
36360573Skris	} else {
36460573Skris		fatal("unsupported mac %s", name);
36560573Skris	}
36660573Skris	mac->name = name;
36760573Skris	mac->mac_len = mac->md->md_size;
36860573Skris	mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
36960573Skris	mac->key = NULL;
37060573Skris	mac->enabled = 0;
37160573Skris}
37260573Skrisvoid
37360573Skrischoose_comp(Comp *comp, char *client, char *server)
37460573Skris{
37560573Skris	char *name = get_match(client, server);
37660573Skris	if (name == NULL)
37760573Skris		fatal("no matching comp found: client %s server %s", client, server);
37860573Skris	if (strcmp(name, "zlib") == 0) {
37960573Skris		comp->type = 1;
38060573Skris	} else if (strcmp(name, "none") == 0) {
38160573Skris		comp->type = 0;
38260573Skris	} else {
38360573Skris		fatal("unsupported comp %s", name);
38460573Skris	}
38560573Skris	comp->name = name;
38660573Skris}
38760573Skrisvoid
38860573Skrischoose_kex(Kex *k, char *client, char *server)
38960573Skris{
39060573Skris	k->name = get_match(client, server);
39160573Skris	if (k->name == NULL)
39260573Skris		fatal("no kex alg");
39360573Skris	if (strcmp(k->name, KEX_DH1) != 0)
39460573Skris		fatal("bad kex alg %s", k->name);
39560573Skris}
39660573Skrisvoid
39760573Skrischoose_hostkeyalg(Kex *k, char *client, char *server)
39860573Skris{
39960573Skris	k->hostkeyalg = get_match(client, server);
40060573Skris	if (k->hostkeyalg == NULL)
40160573Skris		fatal("no hostkey alg");
40260573Skris	if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
40360573Skris		fatal("bad hostkey alg %s", k->hostkeyalg);
40460573Skris}
40560573Skris
40660573SkrisKex *
40760573Skriskex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
40860573Skris{
40960573Skris	int mode;
41060573Skris	int ctos;				/* direction: if true client-to-server */
41160573Skris	int need;
41260573Skris	Kex *k;
41360573Skris
41460573Skris	k = xmalloc(sizeof(*k));
41560573Skris	memset(k, 0, sizeof(*k));
41660573Skris	k->server = server;
41760573Skris
41860573Skris	for (mode = 0; mode < MODE_MAX; mode++) {
41960573Skris		int nenc, nmac, ncomp;
42060573Skris		ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
42160573Skris		nenc  = ctos ? PROPOSAL_ENC_ALGS_CTOS  : PROPOSAL_ENC_ALGS_STOC;
42260573Skris		nmac  = ctos ? PROPOSAL_MAC_ALGS_CTOS  : PROPOSAL_MAC_ALGS_STOC;
42360573Skris		ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
42460573Skris		choose_enc (&k->enc [mode], cprop[nenc],  sprop[nenc]);
42560573Skris		choose_mac (&k->mac [mode], cprop[nmac],  sprop[nmac]);
42660573Skris		choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
42760573Skris		debug("kex: %s %s %s %s",
42860573Skris		    ctos ? "client->server" : "server->client",
42960573Skris		    k->enc[mode].name,
43060573Skris		    k->mac[mode].name,
43160573Skris		    k->comp[mode].name);
43260573Skris	}
43360573Skris	choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
43460573Skris	choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
43560573Skris	    sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
43660573Skris	need = 0;
43760573Skris	for (mode = 0; mode < MODE_MAX; mode++) {
43860573Skris	    if (need < k->enc[mode].key_len)
43960573Skris		    need = k->enc[mode].key_len;
44060573Skris	    if (need < k->enc[mode].iv_len)
44160573Skris		    need = k->enc[mode].iv_len;
44260573Skris	    if (need < k->mac[mode].key_len)
44360573Skris		    need = k->mac[mode].key_len;
44460573Skris	}
44561209Skris	/* XXX need runden? */
44660573Skris	k->we_need = need;
44760573Skris	return k;
44860573Skris}
44960573Skris
45060573Skrisint
45160573Skriskex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
45260573Skris{
45360573Skris	int i;
45460573Skris	int mode;
45560573Skris	int ctos;
45660573Skris	unsigned char *keys[NKEYS];
45760573Skris
45860573Skris	for (i = 0; i < NKEYS; i++)
45960573Skris		keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
46060573Skris
46160573Skris	for (mode = 0; mode < MODE_MAX; mode++) {
46260573Skris		ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
46360573Skris		k->enc[mode].iv  = keys[ctos ? 0 : 1];
46460573Skris		k->enc[mode].key = keys[ctos ? 2 : 3];
46560573Skris		k->mac[mode].key = keys[ctos ? 4 : 5];
46660573Skris	}
46760573Skris	return 0;
46860573Skris}
469