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