1 /* $OpenBSD: kexecdh.c,v 1.10 2019/01/21 10:40:11 djm Exp $ */
2 /*
3 * Copyright (c) 2010 Damien Miller. All rights reserved.
4 * Copyright (c) 2019 Markus Friedl. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "includes.h"
28
29 #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
30
31 #include <sys/types.h>
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <signal.h>
36
37 #include <openssl/ecdh.h>
38
39 #include "sshkey.h"
40 #include "kex.h"
41 #include "sshbuf.h"
42 #include "digest.h"
43 #include "ssherr.h"
44
45 static int
46 kex_ecdh_dec_key_group(struct kex *, const struct sshbuf *, EC_KEY *key,
47 const EC_GROUP *, struct sshbuf **);
48
49 int
kex_ecdh_keypair(struct kex * kex)50 kex_ecdh_keypair(struct kex *kex)
51 {
52 EC_KEY *client_key = NULL;
53 const EC_GROUP *group;
54 const EC_POINT *public_key;
55 struct sshbuf *buf = NULL;
56 int r;
57
58 if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) {
59 r = SSH_ERR_ALLOC_FAIL;
60 goto out;
61 }
62 if (EC_KEY_generate_key(client_key) != 1) {
63 r = SSH_ERR_LIBCRYPTO_ERROR;
64 goto out;
65 }
66 group = EC_KEY_get0_group(client_key);
67 public_key = EC_KEY_get0_public_key(client_key);
68
69 if ((buf = sshbuf_new()) == NULL) {
70 r = SSH_ERR_ALLOC_FAIL;
71 goto out;
72 }
73 if ((r = sshbuf_put_ec(buf, public_key, group)) != 0 ||
74 (r = sshbuf_get_u32(buf, NULL)) != 0)
75 goto out;
76 #ifdef DEBUG_KEXECDH
77 fputs("client private key:\n", stderr);
78 sshkey_dump_ec_key(client_key);
79 #endif
80 kex->ec_client_key = client_key;
81 kex->ec_group = group;
82 client_key = NULL; /* owned by the kex */
83 kex->client_pub = buf;
84 buf = NULL;
85 out:
86 EC_KEY_free(client_key);
87 sshbuf_free(buf);
88 return r;
89 }
90
91 int
kex_ecdh_enc(struct kex * kex,const struct sshbuf * client_blob,struct sshbuf ** server_blobp,struct sshbuf ** shared_secretp)92 kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob,
93 struct sshbuf **server_blobp, struct sshbuf **shared_secretp)
94 {
95 const EC_GROUP *group;
96 const EC_POINT *pub_key;
97 EC_KEY *server_key = NULL;
98 struct sshbuf *server_blob = NULL;
99 int r;
100
101 *server_blobp = NULL;
102 *shared_secretp = NULL;
103
104 if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) {
105 r = SSH_ERR_ALLOC_FAIL;
106 goto out;
107 }
108 if (EC_KEY_generate_key(server_key) != 1) {
109 r = SSH_ERR_LIBCRYPTO_ERROR;
110 goto out;
111 }
112 group = EC_KEY_get0_group(server_key);
113
114 #ifdef DEBUG_KEXECDH
115 fputs("server private key:\n", stderr);
116 sshkey_dump_ec_key(server_key);
117 #endif
118 pub_key = EC_KEY_get0_public_key(server_key);
119 if ((server_blob = sshbuf_new()) == NULL) {
120 r = SSH_ERR_ALLOC_FAIL;
121 goto out;
122 }
123 if ((r = sshbuf_put_ec(server_blob, pub_key, group)) != 0 ||
124 (r = sshbuf_get_u32(server_blob, NULL)) != 0)
125 goto out;
126 if ((r = kex_ecdh_dec_key_group(kex, client_blob, server_key, group,
127 shared_secretp)) != 0)
128 goto out;
129 *server_blobp = server_blob;
130 server_blob = NULL;
131 out:
132 EC_KEY_free(server_key);
133 sshbuf_free(server_blob);
134 return r;
135 }
136
137 static int
kex_ecdh_dec_key_group(struct kex * kex,const struct sshbuf * ec_blob,EC_KEY * key,const EC_GROUP * group,struct sshbuf ** shared_secretp)138 kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob,
139 EC_KEY *key, const EC_GROUP *group, struct sshbuf **shared_secretp)
140 {
141 struct sshbuf *buf = NULL;
142 BIGNUM *shared_secret = NULL;
143 EC_POINT *dh_pub = NULL;
144 u_char *kbuf = NULL;
145 size_t klen = 0;
146 int r;
147
148 *shared_secretp = NULL;
149
150 if ((buf = sshbuf_new()) == NULL) {
151 r = SSH_ERR_ALLOC_FAIL;
152 goto out;
153 }
154 if ((r = sshbuf_put_stringb(buf, ec_blob)) != 0)
155 goto out;
156 if ((dh_pub = EC_POINT_new(group)) == NULL) {
157 r = SSH_ERR_ALLOC_FAIL;
158 goto out;
159 }
160 if ((r = sshbuf_get_ec(buf, dh_pub, group)) != 0) {
161 goto out;
162 }
163 sshbuf_reset(buf);
164
165 #ifdef DEBUG_KEXECDH
166 fputs("public key:\n", stderr);
167 sshkey_dump_ec_point(group, dh_pub);
168 #endif
169 if (sshkey_ec_validate_public(group, dh_pub) != 0) {
170 r = SSH_ERR_MESSAGE_INCOMPLETE;
171 goto out;
172 }
173 klen = (EC_GROUP_get_degree(group) + 7) / 8;
174 if ((kbuf = malloc(klen)) == NULL ||
175 (shared_secret = BN_new()) == NULL) {
176 r = SSH_ERR_ALLOC_FAIL;
177 goto out;
178 }
179 if (ECDH_compute_key(kbuf, klen, dh_pub, key, NULL) != (int)klen ||
180 BN_bin2bn(kbuf, klen, shared_secret) == NULL) {
181 r = SSH_ERR_LIBCRYPTO_ERROR;
182 goto out;
183 }
184 #ifdef DEBUG_KEXECDH
185 dump_digest("shared secret", kbuf, klen);
186 #endif
187 if ((r = sshbuf_put_bignum2(buf, shared_secret)) != 0)
188 goto out;
189 *shared_secretp = buf;
190 buf = NULL;
191 out:
192 EC_POINT_clear_free(dh_pub);
193 BN_clear_free(shared_secret);
194 freezero(kbuf, klen);
195 sshbuf_free(buf);
196 return r;
197 }
198
199 int
kex_ecdh_dec(struct kex * kex,const struct sshbuf * server_blob,struct sshbuf ** shared_secretp)200 kex_ecdh_dec(struct kex *kex, const struct sshbuf *server_blob,
201 struct sshbuf **shared_secretp)
202 {
203 int r;
204
205 r = kex_ecdh_dec_key_group(kex, server_blob, kex->ec_client_key,
206 kex->ec_group, shared_secretp);
207 EC_KEY_free(kex->ec_client_key);
208 kex->ec_client_key = NULL;
209 return r;
210 }
211
212 #else
213
214 #include "ssherr.h"
215
216 struct kex;
217 struct sshbuf;
218 struct sshkey;
219
220 int
kex_ecdh_keypair(struct kex * kex)221 kex_ecdh_keypair(struct kex *kex)
222 {
223 return SSH_ERR_SIGN_ALG_UNSUPPORTED;
224 }
225
226 int
kex_ecdh_enc(struct kex * kex,const struct sshbuf * client_blob,struct sshbuf ** server_blobp,struct sshbuf ** shared_secretp)227 kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob,
228 struct sshbuf **server_blobp, struct sshbuf **shared_secretp)
229 {
230 return SSH_ERR_SIGN_ALG_UNSUPPORTED;
231 }
232
233 int
kex_ecdh_dec(struct kex * kex,const struct sshbuf * server_blob,struct sshbuf ** shared_secretp)234 kex_ecdh_dec(struct kex *kex, const struct sshbuf *server_blob,
235 struct sshbuf **shared_secretp)
236 {
237 return SSH_ERR_SIGN_ALG_UNSUPPORTED;
238 }
239 #endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */
240