xref: /freebsd/crypto/openssh/kexgexc.c (revision d0c8c0bcc279fcf7568c5e97c15c115cbf83be4c)
1d0c8c0bcSDag-Erling Smørgrav /*
2d0c8c0bcSDag-Erling Smørgrav  * Copyright (c) 2000 Niels Provos.  All rights reserved.
3d0c8c0bcSDag-Erling Smørgrav  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
4d0c8c0bcSDag-Erling Smørgrav  *
5d0c8c0bcSDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
6d0c8c0bcSDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
7d0c8c0bcSDag-Erling Smørgrav  * are met:
8d0c8c0bcSDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
9d0c8c0bcSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer.
10d0c8c0bcSDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
11d0c8c0bcSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
12d0c8c0bcSDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
13d0c8c0bcSDag-Erling Smørgrav  *
14d0c8c0bcSDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15d0c8c0bcSDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16d0c8c0bcSDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17d0c8c0bcSDag-Erling Smørgrav  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18d0c8c0bcSDag-Erling Smørgrav  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19d0c8c0bcSDag-Erling Smørgrav  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20d0c8c0bcSDag-Erling Smørgrav  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21d0c8c0bcSDag-Erling Smørgrav  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22d0c8c0bcSDag-Erling Smørgrav  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23d0c8c0bcSDag-Erling Smørgrav  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24d0c8c0bcSDag-Erling Smørgrav  */
25d0c8c0bcSDag-Erling Smørgrav 
26d0c8c0bcSDag-Erling Smørgrav #include "includes.h"
27d0c8c0bcSDag-Erling Smørgrav RCSID("$OpenBSD: kexgexc.c,v 1.1 2003/02/16 17:09:57 markus Exp $");
28d0c8c0bcSDag-Erling Smørgrav 
29d0c8c0bcSDag-Erling Smørgrav #include "xmalloc.h"
30d0c8c0bcSDag-Erling Smørgrav #include "key.h"
31d0c8c0bcSDag-Erling Smørgrav #include "kex.h"
32d0c8c0bcSDag-Erling Smørgrav #include "log.h"
33d0c8c0bcSDag-Erling Smørgrav #include "packet.h"
34d0c8c0bcSDag-Erling Smørgrav #include "dh.h"
35d0c8c0bcSDag-Erling Smørgrav #include "ssh2.h"
36d0c8c0bcSDag-Erling Smørgrav #include "compat.h"
37d0c8c0bcSDag-Erling Smørgrav 
38d0c8c0bcSDag-Erling Smørgrav void
39d0c8c0bcSDag-Erling Smørgrav kexgex_client(Kex *kex)
40d0c8c0bcSDag-Erling Smørgrav {
41d0c8c0bcSDag-Erling Smørgrav 	BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
42d0c8c0bcSDag-Erling Smørgrav 	BIGNUM *p = NULL, *g = NULL;
43d0c8c0bcSDag-Erling Smørgrav 	Key *server_host_key;
44d0c8c0bcSDag-Erling Smørgrav 	u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
45d0c8c0bcSDag-Erling Smørgrav 	u_int klen, kout, slen, sbloblen;
46d0c8c0bcSDag-Erling Smørgrav 	int min, max, nbits;
47d0c8c0bcSDag-Erling Smørgrav 	DH *dh;
48d0c8c0bcSDag-Erling Smørgrav 
49d0c8c0bcSDag-Erling Smørgrav 	nbits = dh_estimate(kex->we_need * 8);
50d0c8c0bcSDag-Erling Smørgrav 
51d0c8c0bcSDag-Erling Smørgrav 	if (datafellows & SSH_OLD_DHGEX) {
52d0c8c0bcSDag-Erling Smørgrav 		debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD sent");
53d0c8c0bcSDag-Erling Smørgrav 
54d0c8c0bcSDag-Erling Smørgrav 		/* Old GEX request */
55d0c8c0bcSDag-Erling Smørgrav 		packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD);
56d0c8c0bcSDag-Erling Smørgrav 		packet_put_int(nbits);
57d0c8c0bcSDag-Erling Smørgrav 		min = DH_GRP_MIN;
58d0c8c0bcSDag-Erling Smørgrav 		max = DH_GRP_MAX;
59d0c8c0bcSDag-Erling Smørgrav 	} else {
60d0c8c0bcSDag-Erling Smørgrav 		debug("SSH2_MSG_KEX_DH_GEX_REQUEST sent");
61d0c8c0bcSDag-Erling Smørgrav 
62d0c8c0bcSDag-Erling Smørgrav 		/* New GEX request */
63d0c8c0bcSDag-Erling Smørgrav 		min = DH_GRP_MIN;
64d0c8c0bcSDag-Erling Smørgrav 		max = DH_GRP_MAX;
65d0c8c0bcSDag-Erling Smørgrav 		packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
66d0c8c0bcSDag-Erling Smørgrav 		packet_put_int(min);
67d0c8c0bcSDag-Erling Smørgrav 		packet_put_int(nbits);
68d0c8c0bcSDag-Erling Smørgrav 		packet_put_int(max);
69d0c8c0bcSDag-Erling Smørgrav 	}
70d0c8c0bcSDag-Erling Smørgrav #ifdef DEBUG_KEXDH
71d0c8c0bcSDag-Erling Smørgrav 	fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n",
72d0c8c0bcSDag-Erling Smørgrav 	    min, nbits, max);
73d0c8c0bcSDag-Erling Smørgrav #endif
74d0c8c0bcSDag-Erling Smørgrav 	packet_send();
75d0c8c0bcSDag-Erling Smørgrav 
76d0c8c0bcSDag-Erling Smørgrav 	debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP");
77d0c8c0bcSDag-Erling Smørgrav 	packet_read_expect(SSH2_MSG_KEX_DH_GEX_GROUP);
78d0c8c0bcSDag-Erling Smørgrav 
79d0c8c0bcSDag-Erling Smørgrav 	if ((p = BN_new()) == NULL)
80d0c8c0bcSDag-Erling Smørgrav 		fatal("BN_new");
81d0c8c0bcSDag-Erling Smørgrav 	packet_get_bignum2(p);
82d0c8c0bcSDag-Erling Smørgrav 	if ((g = BN_new()) == NULL)
83d0c8c0bcSDag-Erling Smørgrav 		fatal("BN_new");
84d0c8c0bcSDag-Erling Smørgrav 	packet_get_bignum2(g);
85d0c8c0bcSDag-Erling Smørgrav 	packet_check_eom();
86d0c8c0bcSDag-Erling Smørgrav 
87d0c8c0bcSDag-Erling Smørgrav 	if (BN_num_bits(p) < min || BN_num_bits(p) > max)
88d0c8c0bcSDag-Erling Smørgrav 		fatal("DH_GEX group out of range: %d !< %d !< %d",
89d0c8c0bcSDag-Erling Smørgrav 		    min, BN_num_bits(p), max);
90d0c8c0bcSDag-Erling Smørgrav 
91d0c8c0bcSDag-Erling Smørgrav 	dh = dh_new_group(g, p);
92d0c8c0bcSDag-Erling Smørgrav 	dh_gen_key(dh, kex->we_need * 8);
93d0c8c0bcSDag-Erling Smørgrav 
94d0c8c0bcSDag-Erling Smørgrav #ifdef DEBUG_KEXDH
95d0c8c0bcSDag-Erling Smørgrav 	DHparams_print_fp(stderr, dh);
96d0c8c0bcSDag-Erling Smørgrav 	fprintf(stderr, "pub= ");
97d0c8c0bcSDag-Erling Smørgrav 	BN_print_fp(stderr, dh->pub_key);
98d0c8c0bcSDag-Erling Smørgrav 	fprintf(stderr, "\n");
99d0c8c0bcSDag-Erling Smørgrav #endif
100d0c8c0bcSDag-Erling Smørgrav 
101d0c8c0bcSDag-Erling Smørgrav 	debug("SSH2_MSG_KEX_DH_GEX_INIT sent");
102d0c8c0bcSDag-Erling Smørgrav 	/* generate and send 'e', client DH public key */
103d0c8c0bcSDag-Erling Smørgrav 	packet_start(SSH2_MSG_KEX_DH_GEX_INIT);
104d0c8c0bcSDag-Erling Smørgrav 	packet_put_bignum2(dh->pub_key);
105d0c8c0bcSDag-Erling Smørgrav 	packet_send();
106d0c8c0bcSDag-Erling Smørgrav 
107d0c8c0bcSDag-Erling Smørgrav 	debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY");
108d0c8c0bcSDag-Erling Smørgrav 	packet_read_expect(SSH2_MSG_KEX_DH_GEX_REPLY);
109d0c8c0bcSDag-Erling Smørgrav 
110d0c8c0bcSDag-Erling Smørgrav 	/* key, cert */
111d0c8c0bcSDag-Erling Smørgrav 	server_host_key_blob = packet_get_string(&sbloblen);
112d0c8c0bcSDag-Erling Smørgrav 	server_host_key = key_from_blob(server_host_key_blob, sbloblen);
113d0c8c0bcSDag-Erling Smørgrav 	if (server_host_key == NULL)
114d0c8c0bcSDag-Erling Smørgrav 		fatal("cannot decode server_host_key_blob");
115d0c8c0bcSDag-Erling Smørgrav 	if (server_host_key->type != kex->hostkey_type)
116d0c8c0bcSDag-Erling Smørgrav 		fatal("type mismatch for decoded server_host_key_blob");
117d0c8c0bcSDag-Erling Smørgrav 	if (kex->verify_host_key == NULL)
118d0c8c0bcSDag-Erling Smørgrav 		fatal("cannot verify server_host_key");
119d0c8c0bcSDag-Erling Smørgrav 	if (kex->verify_host_key(server_host_key) == -1)
120d0c8c0bcSDag-Erling Smørgrav 		fatal("server_host_key verification failed");
121d0c8c0bcSDag-Erling Smørgrav 
122d0c8c0bcSDag-Erling Smørgrav 	/* DH paramter f, server public DH key */
123d0c8c0bcSDag-Erling Smørgrav 	if ((dh_server_pub = BN_new()) == NULL)
124d0c8c0bcSDag-Erling Smørgrav 		fatal("dh_server_pub == NULL");
125d0c8c0bcSDag-Erling Smørgrav 	packet_get_bignum2(dh_server_pub);
126d0c8c0bcSDag-Erling Smørgrav 
127d0c8c0bcSDag-Erling Smørgrav #ifdef DEBUG_KEXDH
128d0c8c0bcSDag-Erling Smørgrav 	fprintf(stderr, "dh_server_pub= ");
129d0c8c0bcSDag-Erling Smørgrav 	BN_print_fp(stderr, dh_server_pub);
130d0c8c0bcSDag-Erling Smørgrav 	fprintf(stderr, "\n");
131d0c8c0bcSDag-Erling Smørgrav 	debug("bits %d", BN_num_bits(dh_server_pub));
132d0c8c0bcSDag-Erling Smørgrav #endif
133d0c8c0bcSDag-Erling Smørgrav 
134d0c8c0bcSDag-Erling Smørgrav 	/* signed H */
135d0c8c0bcSDag-Erling Smørgrav 	signature = packet_get_string(&slen);
136d0c8c0bcSDag-Erling Smørgrav 	packet_check_eom();
137d0c8c0bcSDag-Erling Smørgrav 
138d0c8c0bcSDag-Erling Smørgrav 	if (!dh_pub_is_valid(dh, dh_server_pub))
139d0c8c0bcSDag-Erling Smørgrav 		packet_disconnect("bad server public DH value");
140d0c8c0bcSDag-Erling Smørgrav 
141d0c8c0bcSDag-Erling Smørgrav 	klen = DH_size(dh);
142d0c8c0bcSDag-Erling Smørgrav 	kbuf = xmalloc(klen);
143d0c8c0bcSDag-Erling Smørgrav 	kout = DH_compute_key(kbuf, dh_server_pub, dh);
144d0c8c0bcSDag-Erling Smørgrav #ifdef DEBUG_KEXDH
145d0c8c0bcSDag-Erling Smørgrav 	dump_digest("shared secret", kbuf, kout);
146d0c8c0bcSDag-Erling Smørgrav #endif
147d0c8c0bcSDag-Erling Smørgrav 	if ((shared_secret = BN_new()) == NULL)
148d0c8c0bcSDag-Erling Smørgrav 		fatal("kexgex_client: BN_new failed");
149d0c8c0bcSDag-Erling Smørgrav 	BN_bin2bn(kbuf, kout, shared_secret);
150d0c8c0bcSDag-Erling Smørgrav 	memset(kbuf, 0, klen);
151d0c8c0bcSDag-Erling Smørgrav 	xfree(kbuf);
152d0c8c0bcSDag-Erling Smørgrav 
153d0c8c0bcSDag-Erling Smørgrav 	if (datafellows & SSH_OLD_DHGEX)
154d0c8c0bcSDag-Erling Smørgrav 		min = max = -1;
155d0c8c0bcSDag-Erling Smørgrav 
156d0c8c0bcSDag-Erling Smørgrav 	/* calc and verify H */
157d0c8c0bcSDag-Erling Smørgrav 	hash = kexgex_hash(
158d0c8c0bcSDag-Erling Smørgrav 	    kex->client_version_string,
159d0c8c0bcSDag-Erling Smørgrav 	    kex->server_version_string,
160d0c8c0bcSDag-Erling Smørgrav 	    buffer_ptr(&kex->my), buffer_len(&kex->my),
161d0c8c0bcSDag-Erling Smørgrav 	    buffer_ptr(&kex->peer), buffer_len(&kex->peer),
162d0c8c0bcSDag-Erling Smørgrav 	    server_host_key_blob, sbloblen,
163d0c8c0bcSDag-Erling Smørgrav 	    min, nbits, max,
164d0c8c0bcSDag-Erling Smørgrav 	    dh->p, dh->g,
165d0c8c0bcSDag-Erling Smørgrav 	    dh->pub_key,
166d0c8c0bcSDag-Erling Smørgrav 	    dh_server_pub,
167d0c8c0bcSDag-Erling Smørgrav 	    shared_secret
168d0c8c0bcSDag-Erling Smørgrav 	);
169d0c8c0bcSDag-Erling Smørgrav 	/* have keys, free DH */
170d0c8c0bcSDag-Erling Smørgrav 	DH_free(dh);
171d0c8c0bcSDag-Erling Smørgrav 	xfree(server_host_key_blob);
172d0c8c0bcSDag-Erling Smørgrav 	BN_clear_free(dh_server_pub);
173d0c8c0bcSDag-Erling Smørgrav 
174d0c8c0bcSDag-Erling Smørgrav 	if (key_verify(server_host_key, signature, slen, hash, 20) != 1)
175d0c8c0bcSDag-Erling Smørgrav 		fatal("key_verify failed for server_host_key");
176d0c8c0bcSDag-Erling Smørgrav 	key_free(server_host_key);
177d0c8c0bcSDag-Erling Smørgrav 	xfree(signature);
178d0c8c0bcSDag-Erling Smørgrav 
179d0c8c0bcSDag-Erling Smørgrav 	/* save session id */
180d0c8c0bcSDag-Erling Smørgrav 	if (kex->session_id == NULL) {
181d0c8c0bcSDag-Erling Smørgrav 		kex->session_id_len = 20;
182d0c8c0bcSDag-Erling Smørgrav 		kex->session_id = xmalloc(kex->session_id_len);
183d0c8c0bcSDag-Erling Smørgrav 		memcpy(kex->session_id, hash, kex->session_id_len);
184d0c8c0bcSDag-Erling Smørgrav 	}
185d0c8c0bcSDag-Erling Smørgrav 	kex_derive_keys(kex, hash, shared_secret);
186d0c8c0bcSDag-Erling Smørgrav 	BN_clear_free(shared_secret);
187d0c8c0bcSDag-Erling Smørgrav 
188d0c8c0bcSDag-Erling Smørgrav 	kex_finish(kex);
189d0c8c0bcSDag-Erling Smørgrav }
190