xref: /netbsd-src/crypto/external/bsd/openssh/dist/kexdh.c (revision 17418e98f281f84e3d22de9717222f9c2ee84d3a)
1*17418e98Schristos /*	$NetBSD: kexdh.c,v 1.10 2021/03/05 17:47:16 christos Exp $	*/
2*17418e98Schristos /* $OpenBSD: kexdh.c,v 1.34 2020/12/04 02:29:25 djm Exp $ */
32d3b0f52Schristos 
4ca32bd8dSchristos /*
5aa36fcacSchristos  * Copyright (c) 2019 Markus Friedl.  All rights reserved.
6ca32bd8dSchristos  *
7ca32bd8dSchristos  * Redistribution and use in source and binary forms, with or without
8ca32bd8dSchristos  * modification, are permitted provided that the following conditions
9ca32bd8dSchristos  * are met:
10ca32bd8dSchristos  * 1. Redistributions of source code must retain the above copyright
11ca32bd8dSchristos  *    notice, this list of conditions and the following disclaimer.
12ca32bd8dSchristos  * 2. Redistributions in binary form must reproduce the above copyright
13ca32bd8dSchristos  *    notice, this list of conditions and the following disclaimer in the
14ca32bd8dSchristos  *    documentation and/or other materials provided with the distribution.
15ca32bd8dSchristos  *
16ca32bd8dSchristos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17ca32bd8dSchristos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18ca32bd8dSchristos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19ca32bd8dSchristos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20ca32bd8dSchristos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21ca32bd8dSchristos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22ca32bd8dSchristos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23ca32bd8dSchristos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24ca32bd8dSchristos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25ca32bd8dSchristos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26ca32bd8dSchristos  */
27ca32bd8dSchristos 
28313c6c94Schristos #include "includes.h"
29*17418e98Schristos __RCSID("$NetBSD: kexdh.c,v 1.10 2021/03/05 17:47:16 christos Exp $");
30ca32bd8dSchristos #include <sys/types.h>
31ca32bd8dSchristos 
32aa36fcacSchristos #include <stdio.h>
33aa36fcacSchristos #include <string.h>
34ca32bd8dSchristos #include <signal.h>
35ca32bd8dSchristos 
36e4d43b82Schristos #include "sshkey.h"
37ca32bd8dSchristos #include "kex.h"
38e4d43b82Schristos #include "sshbuf.h"
398a4530f9Schristos #include "digest.h"
40aa36fcacSchristos #include "ssherr.h"
41aa36fcacSchristos #include "dh.h"
422d3b0f52Schristos #include "log.h"
43ca32bd8dSchristos 
44e4d43b82Schristos int
kex_dh_keygen(struct kex * kex)45aa36fcacSchristos kex_dh_keygen(struct kex *kex)
46ca32bd8dSchristos {
47aa36fcacSchristos 	switch (kex->kex_type) {
48aa36fcacSchristos 	case KEX_DH_GRP1_SHA1:
49aa36fcacSchristos 		kex->dh = dh_new_group1();
50aa36fcacSchristos 		break;
51aa36fcacSchristos 	case KEX_DH_GRP14_SHA1:
52aa36fcacSchristos 	case KEX_DH_GRP14_SHA256:
53aa36fcacSchristos 		kex->dh = dh_new_group14();
54aa36fcacSchristos 		break;
55aa36fcacSchristos 	case KEX_DH_GRP16_SHA512:
56aa36fcacSchristos 		kex->dh = dh_new_group16();
57aa36fcacSchristos 		break;
58aa36fcacSchristos 	case KEX_DH_GRP18_SHA512:
59aa36fcacSchristos 		kex->dh = dh_new_group18();
60aa36fcacSchristos 		break;
61aa36fcacSchristos 	default:
62e4d43b82Schristos 		return SSH_ERR_INVALID_ARGUMENT;
63aa36fcacSchristos 	}
64aa36fcacSchristos 	if (kex->dh == NULL)
65e4d43b82Schristos 		return SSH_ERR_ALLOC_FAIL;
66aa36fcacSchristos 	return (dh_gen_key(kex->dh, kex->we_need * 8));
67aa36fcacSchristos }
68aa36fcacSchristos 
69aa36fcacSchristos int
kex_dh_compute_key(struct kex * kex,BIGNUM * dh_pub,struct sshbuf * out)70aa36fcacSchristos kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out)
71aa36fcacSchristos {
72aa36fcacSchristos 	BIGNUM *shared_secret = NULL;
73aa36fcacSchristos 	u_char *kbuf = NULL;
74aa36fcacSchristos 	size_t klen = 0;
75aa36fcacSchristos 	int kout, r;
76aa36fcacSchristos 
77aa36fcacSchristos #ifdef DEBUG_KEXDH
78aa36fcacSchristos 	fprintf(stderr, "dh_pub= ");
79aa36fcacSchristos 	BN_print_fp(stderr, dh_pub);
80aa36fcacSchristos 	fprintf(stderr, "\n");
81aa36fcacSchristos 	debug("bits %d", BN_num_bits(dh_pub));
82aa36fcacSchristos 	DHparams_print_fp(stderr, kex->dh);
83aa36fcacSchristos 	fprintf(stderr, "\n");
84aa36fcacSchristos #endif
85aa36fcacSchristos 
86aa36fcacSchristos 	if (!dh_pub_is_valid(kex->dh, dh_pub)) {
87aa36fcacSchristos 		r = SSH_ERR_MESSAGE_INCOMPLETE;
88aa36fcacSchristos 		goto out;
89aa36fcacSchristos 	}
90aa36fcacSchristos 	klen = DH_size(kex->dh);
91aa36fcacSchristos 	if ((kbuf = malloc(klen)) == NULL ||
92aa36fcacSchristos 	    (shared_secret = BN_new()) == NULL) {
93aa36fcacSchristos 		r = SSH_ERR_ALLOC_FAIL;
94aa36fcacSchristos 		goto out;
95aa36fcacSchristos 	}
96aa36fcacSchristos 	if ((kout = DH_compute_key(kbuf, dh_pub, kex->dh)) < 0 ||
97aa36fcacSchristos 	    BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
98aa36fcacSchristos 		r = SSH_ERR_LIBCRYPTO_ERROR;
99aa36fcacSchristos 		goto out;
100aa36fcacSchristos 	}
101aa36fcacSchristos #ifdef DEBUG_KEXDH
102aa36fcacSchristos 	dump_digest("shared secret", kbuf, kout);
103aa36fcacSchristos #endif
104aa36fcacSchristos 	r = sshbuf_put_bignum2(out, shared_secret);
105aa36fcacSchristos  out:
106aa36fcacSchristos 	freezero(kbuf, klen);
107aa36fcacSchristos 	BN_clear_free(shared_secret);
108e4d43b82Schristos 	return r;
109e4d43b82Schristos }
110aa36fcacSchristos 
111aa36fcacSchristos int
kex_dh_keypair(struct kex * kex)112aa36fcacSchristos kex_dh_keypair(struct kex *kex)
113aa36fcacSchristos {
114aa36fcacSchristos 	const BIGNUM *pub_key;
115aa36fcacSchristos 	struct sshbuf *buf = NULL;
116aa36fcacSchristos 	int r;
117aa36fcacSchristos 
118aa36fcacSchristos 	if ((r = kex_dh_keygen(kex)) != 0)
119aa36fcacSchristos 		return r;
120aa36fcacSchristos 	DH_get0_key(kex->dh, &pub_key, NULL);
121aa36fcacSchristos 	if ((buf = sshbuf_new()) == NULL)
122aa36fcacSchristos 		return SSH_ERR_ALLOC_FAIL;
123aa36fcacSchristos 	if ((r = sshbuf_put_bignum2(buf, pub_key)) != 0 ||
124aa36fcacSchristos 	    (r = sshbuf_get_u32(buf, NULL)) != 0)
125aa36fcacSchristos 		goto out;
126aa36fcacSchristos #ifdef DEBUG_KEXDH
127aa36fcacSchristos 	DHparams_print_fp(stderr, kex->dh);
128aa36fcacSchristos 	fprintf(stderr, "pub= ");
129aa36fcacSchristos 	BN_print_fp(stderr, pub_key);
130aa36fcacSchristos 	fprintf(stderr, "\n");
131ca32bd8dSchristos #endif
132aa36fcacSchristos 	kex->client_pub = buf;
133aa36fcacSchristos 	buf = NULL;
134aa36fcacSchristos  out:
135aa36fcacSchristos 	sshbuf_free(buf);
136aa36fcacSchristos 	return r;
137e4d43b82Schristos }
138aa36fcacSchristos 
139aa36fcacSchristos int
kex_dh_enc(struct kex * kex,const struct sshbuf * client_blob,struct sshbuf ** server_blobp,struct sshbuf ** shared_secretp)140aa36fcacSchristos kex_dh_enc(struct kex *kex, const struct sshbuf *client_blob,
141aa36fcacSchristos     struct sshbuf **server_blobp, struct sshbuf **shared_secretp)
142aa36fcacSchristos {
143aa36fcacSchristos 	const BIGNUM *pub_key;
144aa36fcacSchristos 	struct sshbuf *server_blob = NULL;
145aa36fcacSchristos 	int r;
146aa36fcacSchristos 
147aa36fcacSchristos 	*server_blobp = NULL;
148aa36fcacSchristos 	*shared_secretp = NULL;
149aa36fcacSchristos 
150aa36fcacSchristos 	if ((r = kex_dh_keygen(kex)) != 0)
151aa36fcacSchristos 		goto out;
152aa36fcacSchristos 	DH_get0_key(kex->dh, &pub_key, NULL);
153aa36fcacSchristos 	if ((server_blob = sshbuf_new()) == NULL) {
154aa36fcacSchristos 		r = SSH_ERR_ALLOC_FAIL;
155aa36fcacSchristos 		goto out;
156aa36fcacSchristos 	}
157aa36fcacSchristos 	if ((r = sshbuf_put_bignum2(server_blob, pub_key)) != 0 ||
158aa36fcacSchristos 	    (r = sshbuf_get_u32(server_blob, NULL)) != 0)
159aa36fcacSchristos 		goto out;
160aa36fcacSchristos 	if ((r = kex_dh_dec(kex, client_blob, shared_secretp)) != 0)
161aa36fcacSchristos 		goto out;
162aa36fcacSchristos 	*server_blobp = server_blob;
163aa36fcacSchristos 	server_blob = NULL;
164aa36fcacSchristos  out:
165aa36fcacSchristos 	DH_free(kex->dh);
166aa36fcacSchristos 	kex->dh = NULL;
167aa36fcacSchristos 	sshbuf_free(server_blob);
168aa36fcacSchristos 	return r;
169aa36fcacSchristos }
170aa36fcacSchristos 
171aa36fcacSchristos int
kex_dh_dec(struct kex * kex,const struct sshbuf * dh_blob,struct sshbuf ** shared_secretp)172aa36fcacSchristos kex_dh_dec(struct kex *kex, const struct sshbuf *dh_blob,
173aa36fcacSchristos     struct sshbuf **shared_secretp)
174aa36fcacSchristos {
175aa36fcacSchristos 	struct sshbuf *buf = NULL;
176aa36fcacSchristos 	BIGNUM *dh_pub = NULL;
177aa36fcacSchristos 	int r;
178aa36fcacSchristos 
179aa36fcacSchristos 	*shared_secretp = NULL;
180aa36fcacSchristos 
181aa36fcacSchristos 	if ((buf = sshbuf_new()) == NULL) {
182aa36fcacSchristos 		r = SSH_ERR_ALLOC_FAIL;
183aa36fcacSchristos 		goto out;
184aa36fcacSchristos 	}
185aa36fcacSchristos 	if ((r = sshbuf_put_stringb(buf, dh_blob)) != 0 ||
186aa36fcacSchristos 	    (r = sshbuf_get_bignum2(buf, &dh_pub)) != 0)
187aa36fcacSchristos 		goto out;
188aa36fcacSchristos 	sshbuf_reset(buf);
189aa36fcacSchristos 	if ((r = kex_dh_compute_key(kex, dh_pub, buf)) != 0)
190aa36fcacSchristos 		goto out;
191aa36fcacSchristos 	*shared_secretp = buf;
192aa36fcacSchristos 	buf = NULL;
193aa36fcacSchristos  out:
194*17418e98Schristos 	BN_free(dh_pub);
195aa36fcacSchristos 	DH_free(kex->dh);
196aa36fcacSchristos 	kex->dh = NULL;
197aa36fcacSchristos 	sshbuf_free(buf);
198aa36fcacSchristos 	return r;
199ca32bd8dSchristos }
200