xref: /dflybsd-src/crypto/openssh/kexgexs.c (revision 36e94dc5bac047676e52d6d94a07db1b31c653e3)
1*36e94dc5SPeter Avalos /* $OpenBSD: kexgexs.c,v 1.19 2014/02/02 03:44:31 djm Exp $ */
218de8d7fSPeter Avalos /*
318de8d7fSPeter Avalos  * Copyright (c) 2000 Niels Provos.  All rights reserved.
418de8d7fSPeter Avalos  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
518de8d7fSPeter Avalos  *
618de8d7fSPeter Avalos  * Redistribution and use in source and binary forms, with or without
718de8d7fSPeter Avalos  * modification, are permitted provided that the following conditions
818de8d7fSPeter Avalos  * are met:
918de8d7fSPeter Avalos  * 1. Redistributions of source code must retain the above copyright
1018de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer.
1118de8d7fSPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
1218de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
1318de8d7fSPeter Avalos  *    documentation and/or other materials provided with the distribution.
1418de8d7fSPeter Avalos  *
1518de8d7fSPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1618de8d7fSPeter Avalos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1718de8d7fSPeter Avalos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1818de8d7fSPeter Avalos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1918de8d7fSPeter Avalos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2018de8d7fSPeter Avalos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2118de8d7fSPeter Avalos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2218de8d7fSPeter Avalos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2318de8d7fSPeter Avalos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2418de8d7fSPeter Avalos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2518de8d7fSPeter Avalos  */
2618de8d7fSPeter Avalos 
2718de8d7fSPeter Avalos #include "includes.h"
2818de8d7fSPeter Avalos 
2918de8d7fSPeter Avalos #include <sys/param.h>
3018de8d7fSPeter Avalos 
3118de8d7fSPeter Avalos #include <stdarg.h>
3218de8d7fSPeter Avalos #include <stdio.h>
3318de8d7fSPeter Avalos #include <string.h>
3418de8d7fSPeter Avalos #include <signal.h>
3518de8d7fSPeter Avalos 
369f304aafSPeter Avalos #include <openssl/dh.h>
379f304aafSPeter Avalos 
3818de8d7fSPeter Avalos #include "xmalloc.h"
3918de8d7fSPeter Avalos #include "buffer.h"
4018de8d7fSPeter Avalos #include "key.h"
4118de8d7fSPeter Avalos #include "cipher.h"
4218de8d7fSPeter Avalos #include "kex.h"
4318de8d7fSPeter Avalos #include "log.h"
4418de8d7fSPeter Avalos #include "packet.h"
4518de8d7fSPeter Avalos #include "dh.h"
4618de8d7fSPeter Avalos #include "ssh2.h"
4718de8d7fSPeter Avalos #include "compat.h"
4818de8d7fSPeter Avalos #ifdef GSSAPI
4918de8d7fSPeter Avalos #include "ssh-gss.h"
5018de8d7fSPeter Avalos #endif
5118de8d7fSPeter Avalos #include "monitor_wrap.h"
5218de8d7fSPeter Avalos 
5318de8d7fSPeter Avalos void
5418de8d7fSPeter Avalos kexgex_server(Kex *kex)
5518de8d7fSPeter Avalos {
5618de8d7fSPeter Avalos 	BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
57856ea928SPeter Avalos 	Key *server_host_public, *server_host_private;
5818de8d7fSPeter Avalos 	DH *dh;
5918de8d7fSPeter Avalos 	u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
6018de8d7fSPeter Avalos 	u_int sbloblen, klen, slen, hashlen;
61cb5eb4f1SPeter Avalos 	int omin = -1, min = -1, omax = -1, max = -1, onbits = -1, nbits = -1;
62cb5eb4f1SPeter Avalos 	int type, kout;
6318de8d7fSPeter Avalos 
64856ea928SPeter Avalos 	if (kex->load_host_public_key == NULL ||
65856ea928SPeter Avalos 	    kex->load_host_private_key == NULL)
6618de8d7fSPeter Avalos 		fatal("Cannot load hostkey");
67856ea928SPeter Avalos 	server_host_public = kex->load_host_public_key(kex->hostkey_type);
68856ea928SPeter Avalos 	if (server_host_public == NULL)
6918de8d7fSPeter Avalos 		fatal("Unsupported hostkey type %d", kex->hostkey_type);
70856ea928SPeter Avalos 	server_host_private = kex->load_host_private_key(kex->hostkey_type);
7118de8d7fSPeter Avalos 
7218de8d7fSPeter Avalos 	type = packet_read();
7318de8d7fSPeter Avalos 	switch (type) {
7418de8d7fSPeter Avalos 	case SSH2_MSG_KEX_DH_GEX_REQUEST:
7518de8d7fSPeter Avalos 		debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
76cb5eb4f1SPeter Avalos 		omin = min = packet_get_int();
77cb5eb4f1SPeter Avalos 		onbits = nbits = packet_get_int();
78cb5eb4f1SPeter Avalos 		omax = max = packet_get_int();
7918de8d7fSPeter Avalos 		min = MAX(DH_GRP_MIN, min);
8018de8d7fSPeter Avalos 		max = MIN(DH_GRP_MAX, max);
81cb5eb4f1SPeter Avalos 		nbits = MAX(DH_GRP_MIN, nbits);
82cb5eb4f1SPeter Avalos 		nbits = MIN(DH_GRP_MAX, nbits);
8318de8d7fSPeter Avalos 		break;
8418de8d7fSPeter Avalos 	case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:
8518de8d7fSPeter Avalos 		debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received");
86cb5eb4f1SPeter Avalos 		onbits = nbits = packet_get_int();
8718de8d7fSPeter Avalos 		/* unused for old GEX */
88cb5eb4f1SPeter Avalos 		omin = min = DH_GRP_MIN;
89cb5eb4f1SPeter Avalos 		omax = max = DH_GRP_MAX;
9018de8d7fSPeter Avalos 		break;
9118de8d7fSPeter Avalos 	default:
9218de8d7fSPeter Avalos 		fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type);
9318de8d7fSPeter Avalos 	}
9418de8d7fSPeter Avalos 	packet_check_eom();
9518de8d7fSPeter Avalos 
96cb5eb4f1SPeter Avalos 	if (omax < omin || onbits < omin || omax < onbits)
9718de8d7fSPeter Avalos 		fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d",
98cb5eb4f1SPeter Avalos 		    omin, onbits, omax);
9918de8d7fSPeter Avalos 
10018de8d7fSPeter Avalos 	/* Contact privileged parent */
10118de8d7fSPeter Avalos 	dh = PRIVSEP(choose_dh(min, nbits, max));
10218de8d7fSPeter Avalos 	if (dh == NULL)
10318de8d7fSPeter Avalos 		packet_disconnect("Protocol error: no matching DH grp found");
10418de8d7fSPeter Avalos 
10518de8d7fSPeter Avalos 	debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
10618de8d7fSPeter Avalos 	packet_start(SSH2_MSG_KEX_DH_GEX_GROUP);
10718de8d7fSPeter Avalos 	packet_put_bignum2(dh->p);
10818de8d7fSPeter Avalos 	packet_put_bignum2(dh->g);
10918de8d7fSPeter Avalos 	packet_send();
11018de8d7fSPeter Avalos 
11118de8d7fSPeter Avalos 	/* flush */
11218de8d7fSPeter Avalos 	packet_write_wait();
11318de8d7fSPeter Avalos 
11418de8d7fSPeter Avalos 	/* Compute our exchange value in parallel with the client */
11518de8d7fSPeter Avalos 	dh_gen_key(dh, kex->we_need * 8);
11618de8d7fSPeter Avalos 
11718de8d7fSPeter Avalos 	debug("expecting SSH2_MSG_KEX_DH_GEX_INIT");
11818de8d7fSPeter Avalos 	packet_read_expect(SSH2_MSG_KEX_DH_GEX_INIT);
11918de8d7fSPeter Avalos 
12018de8d7fSPeter Avalos 	/* key, cert */
12118de8d7fSPeter Avalos 	if ((dh_client_pub = BN_new()) == NULL)
12218de8d7fSPeter Avalos 		fatal("dh_client_pub == NULL");
12318de8d7fSPeter Avalos 	packet_get_bignum2(dh_client_pub);
12418de8d7fSPeter Avalos 	packet_check_eom();
12518de8d7fSPeter Avalos 
12618de8d7fSPeter Avalos #ifdef DEBUG_KEXDH
12718de8d7fSPeter Avalos 	fprintf(stderr, "dh_client_pub= ");
12818de8d7fSPeter Avalos 	BN_print_fp(stderr, dh_client_pub);
12918de8d7fSPeter Avalos 	fprintf(stderr, "\n");
13018de8d7fSPeter Avalos 	debug("bits %d", BN_num_bits(dh_client_pub));
13118de8d7fSPeter Avalos #endif
13218de8d7fSPeter Avalos 
13318de8d7fSPeter Avalos #ifdef DEBUG_KEXDH
13418de8d7fSPeter Avalos 	DHparams_print_fp(stderr, dh);
13518de8d7fSPeter Avalos 	fprintf(stderr, "pub= ");
13618de8d7fSPeter Avalos 	BN_print_fp(stderr, dh->pub_key);
13718de8d7fSPeter Avalos 	fprintf(stderr, "\n");
13818de8d7fSPeter Avalos #endif
13918de8d7fSPeter Avalos 	if (!dh_pub_is_valid(dh, dh_client_pub))
14018de8d7fSPeter Avalos 		packet_disconnect("bad client public DH value");
14118de8d7fSPeter Avalos 
14218de8d7fSPeter Avalos 	klen = DH_size(dh);
14318de8d7fSPeter Avalos 	kbuf = xmalloc(klen);
14418de8d7fSPeter Avalos 	if ((kout = DH_compute_key(kbuf, dh_client_pub, dh)) < 0)
14518de8d7fSPeter Avalos 		fatal("DH_compute_key: failed");
14618de8d7fSPeter Avalos #ifdef DEBUG_KEXDH
14718de8d7fSPeter Avalos 	dump_digest("shared secret", kbuf, kout);
14818de8d7fSPeter Avalos #endif
14918de8d7fSPeter Avalos 	if ((shared_secret = BN_new()) == NULL)
15018de8d7fSPeter Avalos 		fatal("kexgex_server: BN_new failed");
15118de8d7fSPeter Avalos 	if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
15218de8d7fSPeter Avalos 		fatal("kexgex_server: BN_bin2bn failed");
153*36e94dc5SPeter Avalos 	explicit_bzero(kbuf, klen);
154*36e94dc5SPeter Avalos 	free(kbuf);
15518de8d7fSPeter Avalos 
156856ea928SPeter Avalos 	key_to_blob(server_host_public, &server_host_key_blob, &sbloblen);
15718de8d7fSPeter Avalos 
15818de8d7fSPeter Avalos 	if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD)
159cb5eb4f1SPeter Avalos 		omin = min = omax = max = -1;
16018de8d7fSPeter Avalos 
16118de8d7fSPeter Avalos 	/* calc H */
16218de8d7fSPeter Avalos 	kexgex_hash(
163*36e94dc5SPeter Avalos 	    kex->hash_alg,
16418de8d7fSPeter Avalos 	    kex->client_version_string,
16518de8d7fSPeter Avalos 	    kex->server_version_string,
16618de8d7fSPeter Avalos 	    buffer_ptr(&kex->peer), buffer_len(&kex->peer),
16718de8d7fSPeter Avalos 	    buffer_ptr(&kex->my), buffer_len(&kex->my),
16818de8d7fSPeter Avalos 	    server_host_key_blob, sbloblen,
169cb5eb4f1SPeter Avalos 	    omin, onbits, omax,
17018de8d7fSPeter Avalos 	    dh->p, dh->g,
17118de8d7fSPeter Avalos 	    dh_client_pub,
17218de8d7fSPeter Avalos 	    dh->pub_key,
17318de8d7fSPeter Avalos 	    shared_secret,
17418de8d7fSPeter Avalos 	    &hash, &hashlen
17518de8d7fSPeter Avalos 	);
17618de8d7fSPeter Avalos 	BN_clear_free(dh_client_pub);
17718de8d7fSPeter Avalos 
17818de8d7fSPeter Avalos 	/* save session id := H */
17918de8d7fSPeter Avalos 	if (kex->session_id == NULL) {
18018de8d7fSPeter Avalos 		kex->session_id_len = hashlen;
18118de8d7fSPeter Avalos 		kex->session_id = xmalloc(kex->session_id_len);
18218de8d7fSPeter Avalos 		memcpy(kex->session_id, hash, kex->session_id_len);
18318de8d7fSPeter Avalos 	}
18418de8d7fSPeter Avalos 
18518de8d7fSPeter Avalos 	/* sign H */
186*36e94dc5SPeter Avalos 	kex->sign(server_host_private, server_host_public, &signature, &slen,
187*36e94dc5SPeter Avalos 	    hash, hashlen);
18818de8d7fSPeter Avalos 
18918de8d7fSPeter Avalos 	/* destroy_sensitive_data(); */
19018de8d7fSPeter Avalos 
19118de8d7fSPeter Avalos 	/* send server hostkey, DH pubkey 'f' and singed H */
19218de8d7fSPeter Avalos 	debug("SSH2_MSG_KEX_DH_GEX_REPLY sent");
19318de8d7fSPeter Avalos 	packet_start(SSH2_MSG_KEX_DH_GEX_REPLY);
19418de8d7fSPeter Avalos 	packet_put_string(server_host_key_blob, sbloblen);
19518de8d7fSPeter Avalos 	packet_put_bignum2(dh->pub_key);	/* f */
19618de8d7fSPeter Avalos 	packet_put_string(signature, slen);
19718de8d7fSPeter Avalos 	packet_send();
19818de8d7fSPeter Avalos 
199*36e94dc5SPeter Avalos 	free(signature);
200*36e94dc5SPeter Avalos 	free(server_host_key_blob);
20118de8d7fSPeter Avalos 	/* have keys, free DH */
20218de8d7fSPeter Avalos 	DH_free(dh);
20318de8d7fSPeter Avalos 
204*36e94dc5SPeter Avalos 	kex_derive_keys_bn(kex, hash, hashlen, shared_secret);
20518de8d7fSPeter Avalos 	BN_clear_free(shared_secret);
20618de8d7fSPeter Avalos 
20718de8d7fSPeter Avalos 	kex_finish(kex);
20818de8d7fSPeter Avalos }
209