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