xref: /dflybsd-src/crypto/openssh/kexgexc.c (revision 95577b5e0147377b730485d25b052a4472277761)
1*ee116499SAntonio Huete Jimenez /* $OpenBSD: kexgexc.c,v 1.38 2021/12/19 22:08:06 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 
29e9778795SPeter Avalos #ifdef WITH_OPENSSL
30e9778795SPeter Avalos 
3118de8d7fSPeter Avalos #include <sys/types.h>
3218de8d7fSPeter Avalos 
339f304aafSPeter Avalos #include <openssl/dh.h>
349f304aafSPeter Avalos 
3518de8d7fSPeter Avalos #include <stdarg.h>
3618de8d7fSPeter Avalos #include <stdio.h>
3718de8d7fSPeter Avalos #include <string.h>
3818de8d7fSPeter Avalos #include <signal.h>
3918de8d7fSPeter Avalos 
40664f4763Szrj #include "openbsd-compat/openssl-compat.h"
41664f4763Szrj 
42e9778795SPeter Avalos #include "sshkey.h"
4318de8d7fSPeter Avalos #include "cipher.h"
44e9778795SPeter Avalos #include "digest.h"
4518de8d7fSPeter Avalos #include "kex.h"
4618de8d7fSPeter Avalos #include "log.h"
4718de8d7fSPeter Avalos #include "packet.h"
4818de8d7fSPeter Avalos #include "dh.h"
4918de8d7fSPeter Avalos #include "ssh2.h"
5018de8d7fSPeter Avalos #include "compat.h"
51e9778795SPeter Avalos #include "dispatch.h"
52e9778795SPeter Avalos #include "ssherr.h"
53e9778795SPeter Avalos #include "sshbuf.h"
54ce74bacaSMatthew Dillon #include "misc.h"
5518de8d7fSPeter Avalos 
56ce74bacaSMatthew Dillon static int input_kex_dh_gex_group(int, u_int32_t, struct ssh *);
57ce74bacaSMatthew Dillon static int input_kex_dh_gex_reply(int, u_int32_t, struct ssh *);
58e9778795SPeter Avalos 
59e9778795SPeter Avalos int
kexgex_client(struct ssh * ssh)60e9778795SPeter Avalos kexgex_client(struct ssh *ssh)
6118de8d7fSPeter Avalos {
62e9778795SPeter Avalos 	struct kex *kex = ssh->kex;
63e9778795SPeter Avalos 	int r;
64e9778795SPeter Avalos 	u_int nbits;
6518de8d7fSPeter Avalos 
6636e94dc5SPeter Avalos 	nbits = dh_estimate(kex->dh_need * 8);
6718de8d7fSPeter Avalos 
68e9778795SPeter Avalos 	kex->min = DH_GRP_MIN;
69e9778795SPeter Avalos 	kex->max = DH_GRP_MAX;
70e9778795SPeter Avalos 	kex->nbits = nbits;
7150a69bb5SSascha Wildner 	if (ssh->compat & SSH_BUG_DHGEX_LARGE)
72ce74bacaSMatthew Dillon 		kex->nbits = MINIMUM(kex->nbits, 4096);
7318de8d7fSPeter Avalos 	/* New GEX request */
74e9778795SPeter Avalos 	if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST)) != 0 ||
75e9778795SPeter Avalos 	    (r = sshpkt_put_u32(ssh, kex->min)) != 0 ||
76e9778795SPeter Avalos 	    (r = sshpkt_put_u32(ssh, kex->nbits)) != 0 ||
77e9778795SPeter Avalos 	    (r = sshpkt_put_u32(ssh, kex->max)) != 0 ||
78e9778795SPeter Avalos 	    (r = sshpkt_send(ssh)) != 0)
79e9778795SPeter Avalos 		goto out;
8018de8d7fSPeter Avalos 	debug("SSH2_MSG_KEX_DH_GEX_REQUEST(%u<%u<%u) sent",
81e9778795SPeter Avalos 	    kex->min, kex->nbits, kex->max);
8218de8d7fSPeter Avalos #ifdef DEBUG_KEXDH
8318de8d7fSPeter Avalos 	fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n",
84e9778795SPeter Avalos 	    kex->min, kex->nbits, kex->max);
8518de8d7fSPeter Avalos #endif
8650a69bb5SSascha Wildner 	debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP");
87e9778795SPeter Avalos 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP,
88e9778795SPeter Avalos 	    &input_kex_dh_gex_group);
89e9778795SPeter Avalos 	r = 0;
90e9778795SPeter Avalos  out:
91e9778795SPeter Avalos 	return r;
92e9778795SPeter Avalos }
9318de8d7fSPeter Avalos 
94e9778795SPeter Avalos static int
input_kex_dh_gex_group(int type,u_int32_t seq,struct ssh * ssh)95ce74bacaSMatthew Dillon input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh)
96e9778795SPeter Avalos {
97e9778795SPeter Avalos 	struct kex *kex = ssh->kex;
98e9778795SPeter Avalos 	BIGNUM *p = NULL, *g = NULL;
99664f4763Szrj 	const BIGNUM *pub_key;
100e9778795SPeter Avalos 	int r, bits;
10118de8d7fSPeter Avalos 
10250a69bb5SSascha Wildner 	debug("SSH2_MSG_KEX_DH_GEX_GROUP received");
10350a69bb5SSascha Wildner 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP, &kex_protocol_error);
10418de8d7fSPeter Avalos 
105664f4763Szrj 	if ((r = sshpkt_get_bignum2(ssh, &p)) != 0 ||
106664f4763Szrj 	    (r = sshpkt_get_bignum2(ssh, &g)) != 0 ||
107e9778795SPeter Avalos 	    (r = sshpkt_get_end(ssh)) != 0)
108e9778795SPeter Avalos 		goto out;
109e9778795SPeter Avalos 	if ((bits = BN_num_bits(p)) < 0 ||
110e9778795SPeter Avalos 	    (u_int)bits < kex->min || (u_int)bits > kex->max) {
111e9778795SPeter Avalos 		r = SSH_ERR_DH_GEX_OUT_OF_RANGE;
112e9778795SPeter Avalos 		goto out;
113e9778795SPeter Avalos 	}
114e9778795SPeter Avalos 	if ((kex->dh = dh_new_group(g, p)) == NULL) {
115e9778795SPeter Avalos 		r = SSH_ERR_ALLOC_FAIL;
116e9778795SPeter Avalos 		goto out;
117e9778795SPeter Avalos 	}
118e9778795SPeter Avalos 	p = g = NULL; /* belong to kex->dh now */
11918de8d7fSPeter Avalos 
120e9778795SPeter Avalos 	/* generate and send 'e', client DH public key */
121664f4763Szrj 	if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
122664f4763Szrj 		goto out;
123664f4763Szrj 	DH_get0_key(kex->dh, &pub_key, NULL);
124664f4763Szrj 	if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_INIT)) != 0 ||
125664f4763Szrj 	    (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 ||
126e9778795SPeter Avalos 	    (r = sshpkt_send(ssh)) != 0)
127e9778795SPeter Avalos 		goto out;
128e9778795SPeter Avalos 	debug("SSH2_MSG_KEX_DH_GEX_INIT sent");
12918de8d7fSPeter Avalos #ifdef DEBUG_KEXDH
130e9778795SPeter Avalos 	DHparams_print_fp(stderr, kex->dh);
13118de8d7fSPeter Avalos 	fprintf(stderr, "pub= ");
132664f4763Szrj 	BN_print_fp(stderr, pub_key);
13318de8d7fSPeter Avalos 	fprintf(stderr, "\n");
13418de8d7fSPeter Avalos #endif
13550a69bb5SSascha Wildner 	debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY");
136e9778795SPeter Avalos 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REPLY, &input_kex_dh_gex_reply);
137e9778795SPeter Avalos 	r = 0;
138e9778795SPeter Avalos out:
139e9778795SPeter Avalos 	BN_clear_free(p);
140e9778795SPeter Avalos 	BN_clear_free(g);
141e9778795SPeter Avalos 	return r;
142e9778795SPeter Avalos }
14318de8d7fSPeter Avalos 
144e9778795SPeter Avalos static int
input_kex_dh_gex_reply(int type,u_int32_t seq,struct ssh * ssh)145ce74bacaSMatthew Dillon input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
146e9778795SPeter Avalos {
147e9778795SPeter Avalos 	struct kex *kex = ssh->kex;
148664f4763Szrj 	BIGNUM *dh_server_pub = NULL;
149664f4763Szrj 	const BIGNUM *pub_key, *dh_p, *dh_g;
150664f4763Szrj 	struct sshbuf *shared_secret = NULL;
151664f4763Szrj 	struct sshbuf *tmp = NULL, *server_host_key_blob = NULL;
152e9778795SPeter Avalos 	struct sshkey *server_host_key = NULL;
153664f4763Szrj 	u_char *signature = NULL;
154e9778795SPeter Avalos 	u_char hash[SSH_DIGEST_MAX_LENGTH];
155664f4763Szrj 	size_t slen, hashlen;
156664f4763Szrj 	int r;
15718de8d7fSPeter Avalos 
15850a69bb5SSascha Wildner 	debug("SSH2_MSG_KEX_DH_GEX_REPLY received");
15950a69bb5SSascha Wildner 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REPLY, &kex_protocol_error);
16050a69bb5SSascha Wildner 
16118de8d7fSPeter Avalos 	/* key, cert */
162664f4763Szrj 	if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0)
163e9778795SPeter Avalos 		goto out;
164664f4763Szrj 	/* sshkey_fromb() consumes its buffer, so make a copy */
165664f4763Szrj 	if ((tmp = sshbuf_fromb(server_host_key_blob)) == NULL) {
166e9778795SPeter Avalos 		r = SSH_ERR_ALLOC_FAIL;
167e9778795SPeter Avalos 		goto out;
168e9778795SPeter Avalos 	}
169664f4763Szrj 	if ((r = sshkey_fromb(tmp, &server_host_key)) != 0 ||
170664f4763Szrj 	    (r = kex_verify_host_key(ssh, server_host_key)) != 0)
171664f4763Szrj 		goto out;
172664f4763Szrj 	/* DH parameter f, server public DH key, signed H */
173664f4763Szrj 	if ((r = sshpkt_get_bignum2(ssh, &dh_server_pub)) != 0 ||
174e9778795SPeter Avalos 	    (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
175e9778795SPeter Avalos 	    (r = sshpkt_get_end(ssh)) != 0)
176e9778795SPeter Avalos 		goto out;
177664f4763Szrj 	if ((shared_secret = sshbuf_new()) == NULL) {
178e9778795SPeter Avalos 		r = SSH_ERR_ALLOC_FAIL;
179e9778795SPeter Avalos 		goto out;
180e9778795SPeter Avalos 	}
181664f4763Szrj 	if ((r = kex_dh_compute_key(kex, dh_server_pub, shared_secret)) != 0)
182e9778795SPeter Avalos 		goto out;
183e9778795SPeter Avalos 	if (ssh->compat & SSH_OLD_DHGEX)
184e9778795SPeter Avalos 		kex->min = kex->max = -1;
18518de8d7fSPeter Avalos 
18618de8d7fSPeter Avalos 	/* calc and verify H */
187664f4763Szrj 	DH_get0_key(kex->dh, &pub_key, NULL);
188664f4763Szrj 	DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g);
189e9778795SPeter Avalos 	hashlen = sizeof(hash);
190e9778795SPeter Avalos 	if ((r = kexgex_hash(
19136e94dc5SPeter Avalos 	    kex->hash_alg,
192664f4763Szrj 	    kex->client_version,
193664f4763Szrj 	    kex->server_version,
194664f4763Szrj 	    kex->my,
195664f4763Szrj 	    kex->peer,
196664f4763Szrj 	    server_host_key_blob,
197e9778795SPeter Avalos 	    kex->min, kex->nbits, kex->max,
198664f4763Szrj 	    dh_p, dh_g,
199664f4763Szrj 	    pub_key,
20018de8d7fSPeter Avalos 	    dh_server_pub,
201664f4763Szrj 	    sshbuf_ptr(shared_secret), sshbuf_len(shared_secret),
202e9778795SPeter Avalos 	    hash, &hashlen)) != 0)
203e9778795SPeter Avalos 		goto out;
20418de8d7fSPeter Avalos 
205e9778795SPeter Avalos 	if ((r = sshkey_verify(server_host_key, signature, slen, hash,
2060cbfa66cSDaniel Fojt 	    hashlen, kex->hostkey_alg, ssh->compat, NULL)) != 0)
207e9778795SPeter Avalos 		goto out;
20818de8d7fSPeter Avalos 
209*ee116499SAntonio Huete Jimenez 	if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) != 0 ||
210*ee116499SAntonio Huete Jimenez 	    (r = kex_send_newkeys(ssh)) != 0)
211*ee116499SAntonio Huete Jimenez 		goto out;
212*ee116499SAntonio Huete Jimenez 
213*ee116499SAntonio Huete Jimenez 	/* save initial signature and hostkey */
214*ee116499SAntonio Huete Jimenez 	if ((kex->flags & KEX_INITIAL) != 0) {
215*ee116499SAntonio Huete Jimenez 		if (kex->initial_hostkey != NULL || kex->initial_sig != NULL) {
216*ee116499SAntonio Huete Jimenez 			r = SSH_ERR_INTERNAL_ERROR;
217*ee116499SAntonio Huete Jimenez 			goto out;
218*ee116499SAntonio Huete Jimenez 		}
219*ee116499SAntonio Huete Jimenez 		if ((kex->initial_sig = sshbuf_new()) == NULL) {
220*ee116499SAntonio Huete Jimenez 			r = SSH_ERR_ALLOC_FAIL;
221*ee116499SAntonio Huete Jimenez 			goto out;
222*ee116499SAntonio Huete Jimenez 		}
223*ee116499SAntonio Huete Jimenez 		if ((r = sshbuf_put(kex->initial_sig, signature, slen)) != 0)
224*ee116499SAntonio Huete Jimenez 			goto out;
225*ee116499SAntonio Huete Jimenez 		kex->initial_hostkey = server_host_key;
226*ee116499SAntonio Huete Jimenez 		server_host_key = NULL;
227*ee116499SAntonio Huete Jimenez 	}
228*ee116499SAntonio Huete Jimenez 	/* success */
229e9778795SPeter Avalos  out:
230e9778795SPeter Avalos 	explicit_bzero(hash, sizeof(hash));
231e9778795SPeter Avalos 	DH_free(kex->dh);
232e9778795SPeter Avalos 	kex->dh = NULL;
233e9778795SPeter Avalos 	BN_clear_free(dh_server_pub);
234664f4763Szrj 	sshbuf_free(shared_secret);
235e9778795SPeter Avalos 	sshkey_free(server_host_key);
236664f4763Szrj 	sshbuf_free(tmp);
237664f4763Szrj 	sshbuf_free(server_host_key_blob);
238e9778795SPeter Avalos 	free(signature);
239e9778795SPeter Avalos 	return r;
240e9778795SPeter Avalos }
241e9778795SPeter Avalos #endif /* WITH_OPENSSL */
242