xref: /dflybsd-src/crypto/openssh/kexdh.c (revision 50a69bb51183a7916e776f2c9f5fa64c999f1a2f)
1*50a69bb5SSascha Wildner /* $OpenBSD: kexdh.c,v 1.34 2020/12/04 02:29:25 djm Exp $ */
218de8d7fSPeter Avalos /*
3664f4763Szrj  * Copyright (c) 2019 Markus Friedl.  All rights reserved.
418de8d7fSPeter Avalos  *
518de8d7fSPeter Avalos  * Redistribution and use in source and binary forms, with or without
618de8d7fSPeter Avalos  * modification, are permitted provided that the following conditions
718de8d7fSPeter Avalos  * are met:
818de8d7fSPeter Avalos  * 1. Redistributions of source code must retain the above copyright
918de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer.
1018de8d7fSPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
1118de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
1218de8d7fSPeter Avalos  *    documentation and/or other materials provided with the distribution.
1318de8d7fSPeter Avalos  *
1418de8d7fSPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1518de8d7fSPeter Avalos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1618de8d7fSPeter Avalos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1718de8d7fSPeter Avalos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1818de8d7fSPeter Avalos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1918de8d7fSPeter Avalos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2018de8d7fSPeter Avalos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2118de8d7fSPeter Avalos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2218de8d7fSPeter Avalos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2318de8d7fSPeter Avalos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2418de8d7fSPeter Avalos  */
2518de8d7fSPeter Avalos 
2618de8d7fSPeter Avalos #include "includes.h"
2718de8d7fSPeter Avalos 
28e9778795SPeter Avalos #ifdef WITH_OPENSSL
29e9778795SPeter Avalos 
3018de8d7fSPeter Avalos #include <sys/types.h>
3118de8d7fSPeter Avalos 
32664f4763Szrj #include <stdio.h>
33664f4763Szrj #include <string.h>
34*50a69bb5SSascha Wildner #include <signal.h>
3518de8d7fSPeter Avalos 
36664f4763Szrj #include "openbsd-compat/openssl-compat.h"
37664f4763Szrj #include <openssl/dh.h>
3818de8d7fSPeter Avalos 
39e9778795SPeter Avalos #include "sshkey.h"
4018de8d7fSPeter Avalos #include "kex.h"
41e9778795SPeter Avalos #include "sshbuf.h"
4236e94dc5SPeter Avalos #include "digest.h"
43664f4763Szrj #include "ssherr.h"
44664f4763Szrj #include "dh.h"
45*50a69bb5SSascha Wildner #include "log.h"
4618de8d7fSPeter Avalos 
47e9778795SPeter Avalos int
kex_dh_keygen(struct kex * kex)48664f4763Szrj kex_dh_keygen(struct kex *kex)
4918de8d7fSPeter Avalos {
50664f4763Szrj 	switch (kex->kex_type) {
51664f4763Szrj 	case KEX_DH_GRP1_SHA1:
52664f4763Szrj 		kex->dh = dh_new_group1();
53664f4763Szrj 		break;
54664f4763Szrj 	case KEX_DH_GRP14_SHA1:
55664f4763Szrj 	case KEX_DH_GRP14_SHA256:
56664f4763Szrj 		kex->dh = dh_new_group14();
57664f4763Szrj 		break;
58664f4763Szrj 	case KEX_DH_GRP16_SHA512:
59664f4763Szrj 		kex->dh = dh_new_group16();
60664f4763Szrj 		break;
61664f4763Szrj 	case KEX_DH_GRP18_SHA512:
62664f4763Szrj 		kex->dh = dh_new_group18();
63664f4763Szrj 		break;
64664f4763Szrj 	default:
65e9778795SPeter Avalos 		return SSH_ERR_INVALID_ARGUMENT;
66664f4763Szrj 	}
67664f4763Szrj 	if (kex->dh == NULL)
68e9778795SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
69664f4763Szrj 	return (dh_gen_key(kex->dh, kex->we_need * 8));
70664f4763Szrj }
71664f4763Szrj 
72664f4763Szrj int
kex_dh_compute_key(struct kex * kex,BIGNUM * dh_pub,struct sshbuf * out)73664f4763Szrj kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out)
74664f4763Szrj {
75664f4763Szrj 	BIGNUM *shared_secret = NULL;
76664f4763Szrj 	u_char *kbuf = NULL;
77664f4763Szrj 	size_t klen = 0;
78664f4763Szrj 	int kout, r;
79664f4763Szrj 
80664f4763Szrj #ifdef DEBUG_KEXDH
81664f4763Szrj 	fprintf(stderr, "dh_pub= ");
82664f4763Szrj 	BN_print_fp(stderr, dh_pub);
83664f4763Szrj 	fprintf(stderr, "\n");
84664f4763Szrj 	debug("bits %d", BN_num_bits(dh_pub));
85664f4763Szrj 	DHparams_print_fp(stderr, kex->dh);
86664f4763Szrj 	fprintf(stderr, "\n");
87664f4763Szrj #endif
88664f4763Szrj 
89664f4763Szrj 	if (!dh_pub_is_valid(kex->dh, dh_pub)) {
90664f4763Szrj 		r = SSH_ERR_MESSAGE_INCOMPLETE;
91664f4763Szrj 		goto out;
92664f4763Szrj 	}
93664f4763Szrj 	klen = DH_size(kex->dh);
94664f4763Szrj 	if ((kbuf = malloc(klen)) == NULL ||
95664f4763Szrj 	    (shared_secret = BN_new()) == NULL) {
96664f4763Szrj 		r = SSH_ERR_ALLOC_FAIL;
97664f4763Szrj 		goto out;
98664f4763Szrj 	}
99664f4763Szrj 	if ((kout = DH_compute_key(kbuf, dh_pub, kex->dh)) < 0 ||
100664f4763Szrj 	    BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
101664f4763Szrj 		r = SSH_ERR_LIBCRYPTO_ERROR;
102664f4763Szrj 		goto out;
103664f4763Szrj 	}
104664f4763Szrj #ifdef DEBUG_KEXDH
105664f4763Szrj 	dump_digest("shared secret", kbuf, kout);
106664f4763Szrj #endif
107664f4763Szrj 	r = sshbuf_put_bignum2(out, shared_secret);
108664f4763Szrj  out:
109664f4763Szrj 	freezero(kbuf, klen);
110664f4763Szrj 	BN_clear_free(shared_secret);
111e9778795SPeter Avalos 	return r;
11218de8d7fSPeter Avalos }
113664f4763Szrj 
114664f4763Szrj int
kex_dh_keypair(struct kex * kex)115664f4763Szrj kex_dh_keypair(struct kex *kex)
116664f4763Szrj {
117664f4763Szrj 	const BIGNUM *pub_key;
118664f4763Szrj 	struct sshbuf *buf = NULL;
119664f4763Szrj 	int r;
120664f4763Szrj 
121664f4763Szrj 	if ((r = kex_dh_keygen(kex)) != 0)
122664f4763Szrj 		return r;
123664f4763Szrj 	DH_get0_key(kex->dh, &pub_key, NULL);
124664f4763Szrj 	if ((buf = sshbuf_new()) == NULL)
125664f4763Szrj 		return SSH_ERR_ALLOC_FAIL;
126664f4763Szrj 	if ((r = sshbuf_put_bignum2(buf, pub_key)) != 0 ||
127664f4763Szrj 	    (r = sshbuf_get_u32(buf, NULL)) != 0)
128664f4763Szrj 		goto out;
129664f4763Szrj #ifdef DEBUG_KEXDH
130664f4763Szrj 	DHparams_print_fp(stderr, kex->dh);
131664f4763Szrj 	fprintf(stderr, "pub= ");
132664f4763Szrj 	BN_print_fp(stderr, pub_key);
133664f4763Szrj 	fprintf(stderr, "\n");
134e9778795SPeter Avalos #endif
135664f4763Szrj 	kex->client_pub = buf;
136664f4763Szrj 	buf = NULL;
137664f4763Szrj  out:
138664f4763Szrj 	sshbuf_free(buf);
139664f4763Szrj 	return r;
140e9778795SPeter Avalos }
141664f4763Szrj 
142664f4763Szrj int
kex_dh_enc(struct kex * kex,const struct sshbuf * client_blob,struct sshbuf ** server_blobp,struct sshbuf ** shared_secretp)143664f4763Szrj kex_dh_enc(struct kex *kex, const struct sshbuf *client_blob,
144664f4763Szrj     struct sshbuf **server_blobp, struct sshbuf **shared_secretp)
145664f4763Szrj {
146664f4763Szrj 	const BIGNUM *pub_key;
147664f4763Szrj 	struct sshbuf *server_blob = NULL;
148664f4763Szrj 	int r;
149664f4763Szrj 
150664f4763Szrj 	*server_blobp = NULL;
151664f4763Szrj 	*shared_secretp = NULL;
152664f4763Szrj 
153664f4763Szrj 	if ((r = kex_dh_keygen(kex)) != 0)
154664f4763Szrj 		goto out;
155664f4763Szrj 	DH_get0_key(kex->dh, &pub_key, NULL);
156664f4763Szrj 	if ((server_blob = sshbuf_new()) == NULL) {
157664f4763Szrj 		r = SSH_ERR_ALLOC_FAIL;
158664f4763Szrj 		goto out;
159664f4763Szrj 	}
160664f4763Szrj 	if ((r = sshbuf_put_bignum2(server_blob, pub_key)) != 0 ||
161664f4763Szrj 	    (r = sshbuf_get_u32(server_blob, NULL)) != 0)
162664f4763Szrj 		goto out;
163664f4763Szrj 	if ((r = kex_dh_dec(kex, client_blob, shared_secretp)) != 0)
164664f4763Szrj 		goto out;
165664f4763Szrj 	*server_blobp = server_blob;
166664f4763Szrj 	server_blob = NULL;
167664f4763Szrj  out:
168664f4763Szrj 	DH_free(kex->dh);
169664f4763Szrj 	kex->dh = NULL;
170664f4763Szrj 	sshbuf_free(server_blob);
171664f4763Szrj 	return r;
172664f4763Szrj }
173664f4763Szrj 
174664f4763Szrj int
kex_dh_dec(struct kex * kex,const struct sshbuf * dh_blob,struct sshbuf ** shared_secretp)175664f4763Szrj kex_dh_dec(struct kex *kex, const struct sshbuf *dh_blob,
176664f4763Szrj     struct sshbuf **shared_secretp)
177664f4763Szrj {
178664f4763Szrj 	struct sshbuf *buf = NULL;
179664f4763Szrj 	BIGNUM *dh_pub = NULL;
180664f4763Szrj 	int r;
181664f4763Szrj 
182664f4763Szrj 	*shared_secretp = NULL;
183664f4763Szrj 
184664f4763Szrj 	if ((buf = sshbuf_new()) == NULL) {
185664f4763Szrj 		r = SSH_ERR_ALLOC_FAIL;
186664f4763Szrj 		goto out;
187664f4763Szrj 	}
188664f4763Szrj 	if ((r = sshbuf_put_stringb(buf, dh_blob)) != 0 ||
189664f4763Szrj 	    (r = sshbuf_get_bignum2(buf, &dh_pub)) != 0)
190664f4763Szrj 		goto out;
191664f4763Szrj 	sshbuf_reset(buf);
192664f4763Szrj 	if ((r = kex_dh_compute_key(kex, dh_pub, buf)) != 0)
193664f4763Szrj 		goto out;
194664f4763Szrj 	*shared_secretp = buf;
195664f4763Szrj 	buf = NULL;
196664f4763Szrj  out:
197*50a69bb5SSascha Wildner 	BN_free(dh_pub);
198664f4763Szrj 	DH_free(kex->dh);
199664f4763Szrj 	kex->dh = NULL;
200664f4763Szrj 	sshbuf_free(buf);
201664f4763Szrj 	return r;
202e9778795SPeter Avalos }
203e9778795SPeter Avalos #endif /* WITH_OPENSSL */
204