]>
Commit | Line | Data |
---|---|---|
aaca72d6 | 1 | /* $OpenBSD: kexecdh.c,v 1.10 2019/01/21 10:40:11 djm Exp $ */ |
eb8b60e3 | 2 | /* |
eb8b60e3 | 3 | * Copyright (c) 2010 Damien Miller. All rights reserved. |
92dda34e | 4 | * Copyright (c) 2019 Markus Friedl. All rights reserved. |
eb8b60e3 DM |
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 | ||
c79ff077 DM |
27 | #include "includes.h" |
28 | ||
72ef7c14 | 29 | #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) |
6af914a1 | 30 | |
eb8b60e3 DM |
31 | #include <sys/types.h> |
32 | ||
92dda34e | 33 | #include <stdio.h> |
eb8b60e3 | 34 | #include <string.h> |
92dda34e | 35 | #include <signal.h> |
eb8b60e3 | 36 | |
eb8b60e3 DM |
37 | #include <openssl/ecdh.h> |
38 | ||
57d10cbe | 39 | #include "sshkey.h" |
eb8b60e3 | 40 | #include "kex.h" |
57d10cbe | 41 | #include "sshbuf.h" |
b3051d01 | 42 | #include "digest.h" |
57d10cbe | 43 | #include "ssherr.h" |
eb8b60e3 | 44 | |
92dda34e | 45 | static int |
71e67fff | 46 | kex_ecdh_dec_key_group(struct kex *, const struct sshbuf *, EC_KEY *key, |
92dda34e | 47 | const EC_GROUP *, struct sshbuf **); |
48 | ||
57d10cbe | 49 | int |
92dda34e | 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 */ | |
aaca72d6 | 83 | kex->client_pub = buf; |
92dda34e | 84 | buf = NULL; |
85 | out: | |
86 | EC_KEY_free(client_key); | |
87 | sshbuf_free(buf); | |
88 | return r; | |
89 | } | |
90 | ||
91 | int | |
71e67fff | 92 | kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob, |
92dda34e | 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; | |
71e67fff | 126 | if ((r = kex_ecdh_dec_key_group(kex, client_blob, server_key, group, |
92dda34e | 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 | |
71e67fff | 138 | kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, |
92dda34e | 139 | EC_KEY *key, const EC_GROUP *group, struct sshbuf **shared_secretp) |
eb8b60e3 | 140 | { |
92dda34e | 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; | |
57d10cbe | 146 | int r; |
eb8b60e3 | 147 | |
92dda34e | 148 | *shared_secretp = NULL; |
149 | ||
150 | if ((buf = sshbuf_new()) == NULL) { | |
151 | r = SSH_ERR_ALLOC_FAIL; | |
152 | goto out; | |
153 | } | |
71e67fff | 154 | if ((r = sshbuf_put_stringb(buf, ec_blob)) != 0) |
92dda34e | 155 | goto out; |
92dda34e | 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; | |
57d10cbe | 162 | } |
92dda34e | 163 | sshbuf_reset(buf); |
164 | ||
165 | #ifdef DEBUG_KEXECDH | |
166 | fputs("public key:\n", stderr); | |
167 | sshkey_dump_ec_point(group, dh_pub); | |
eb8b60e3 | 168 | #endif |
92dda34e | 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; | |
57d10cbe | 183 | } |
92dda34e | 184 | #ifdef DEBUG_KEXECDH |
185 | dump_digest("shared secret", kbuf, klen); | |
eb8b60e3 | 186 | #endif |
92dda34e | 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 | |
71e67fff | 200 | kex_ecdh_dec(struct kex *kex, const struct sshbuf *server_blob, |
92dda34e | 201 | struct sshbuf **shared_secretp) |
202 | { | |
203 | int r; | |
204 | ||
71e67fff | 205 | r = kex_ecdh_dec_key_group(kex, server_blob, kex->ec_client_key, |
92dda34e | 206 | kex->ec_group, shared_secretp); |
207 | EC_KEY_free(kex->ec_client_key); | |
208 | kex->ec_client_key = NULL; | |
209 | return r; | |
eb8b60e3 | 210 | } |
97370f6c DT |
211 | |
212 | #else | |
213 | ||
fa5bd810 DT |
214 | #include "ssherr.h" |
215 | ||
edd1d3a6 DM |
216 | struct kex; |
217 | struct sshbuf; | |
218 | struct sshkey; | |
97370f6c DT |
219 | |
220 | int | |
221 | kex_ecdh_keypair(struct kex *kex) | |
222 | { | |
223 | return SSH_ERR_SIGN_ALG_UNSUPPORTED; | |
224 | } | |
225 | ||
226 | int | |
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 | |
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 | } | |
72ef7c14 | 239 | #endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */ |