]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/plugins/wolfssl/wolfssl_x_diffie_hellman.c
wolfssl: Add support for x448 Diffie-Hellman
[thirdparty/strongswan.git] / src / libstrongswan / plugins / wolfssl / wolfssl_x_diffie_hellman.c
CommitLineData
c92eade8 1/*
59a987b8
TB
2 * Copyright (C) 2020 Tobias Brunner
3 * HSR Hochschule fuer Technik Rapperswil
4 *
c92eade8
SP
5 * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
26#include "wolfssl_common.h"
27
59a987b8 28#if defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)
c92eade8
SP
29
30#include "wolfssl_x_diffie_hellman.h"
31
32#include <utils/debug.h>
33
59a987b8 34#ifdef HAVE_CURVE25519
c92eade8 35#include <wolfssl/wolfcrypt/curve25519.h>
59a987b8
TB
36#endif
37#ifdef HAVE_CURVE448
38#include <wolfssl/wolfcrypt/curve448.h>
39#endif
40
c92eade8
SP
41#include <wolfssl/wolfcrypt/fe_operations.h>
42
43typedef struct private_diffie_hellman_t private_diffie_hellman_t;
44
45/**
46 * Private data
47 */
48struct private_diffie_hellman_t {
49 /**
50 * Public interface.
51 */
52 diffie_hellman_t public;
53
54 /**
55 * Diffie Hellman group number.
56 */
57 diffie_hellman_group_t group;
58
59 /**
60 * Private (public) key
61 */
59a987b8
TB
62 union {
63#ifdef HAVE_CURVE25519
64 curve25519_key key25519;
65#endif
66#ifdef HAVE_CURVE448
67 curve448_key key448;
68#endif
69 } key;
c92eade8
SP
70
71 /**
72 * Shared secret
73 */
74 chunk_t shared_secret;
c92eade8
SP
75};
76
59a987b8 77#ifdef HAVE_CURVE25519
c92eade8 78
59a987b8 79METHOD(diffie_hellman_t, set_other_public_value_25519, bool,
c92eade8
SP
80 private_diffie_hellman_t *this, chunk_t value)
81{
59a987b8 82 word32 len = CURVE25519_KEYSIZE;
c92eade8 83 curve25519_key pub;
d3329ee5 84 int ret;
c92eade8
SP
85
86 if (!diffie_hellman_verify_value(this->group, value))
87 {
88 return FALSE;
89 }
90
91 ret = wc_curve25519_init(&pub);
d3329ee5 92 if (ret != 0)
c92eade8
SP
93 {
94 DBG1(DBG_LIB, "%N public key initialization failed",
95 diffie_hellman_group_names, this->group);
96 return FALSE;
97 }
98
99 ret = wc_curve25519_import_public_ex(value.ptr, value.len, &pub,
100 EC25519_LITTLE_ENDIAN);
101 if (ret != 0)
102 {
103 DBG1(DBG_LIB, "%N public value is malformed",
104 diffie_hellman_group_names, this->group);
105 return FALSE;
106 }
107
108 chunk_clear(&this->shared_secret);
59a987b8
TB
109 this->shared_secret = chunk_alloc(len);
110 if (wc_curve25519_shared_secret_ex(&this->key.key25519, &pub,
111 this->shared_secret.ptr, &len, EC25519_LITTLE_ENDIAN) != 0)
c92eade8
SP
112 {
113 DBG1(DBG_LIB, "%N shared secret computation failed",
114 diffie_hellman_group_names, this->group);
d3329ee5 115 chunk_clear(&this->shared_secret);
c92eade8
SP
116 wc_curve25519_free(&pub);
117 return FALSE;
118 }
c92eade8
SP
119 wc_curve25519_free(&pub);
120 return TRUE;
121}
122
59a987b8 123METHOD(diffie_hellman_t, get_my_public_value_25519, bool,
c92eade8
SP
124 private_diffie_hellman_t *this, chunk_t *value)
125{
126 word32 len = CURVE25519_KEYSIZE;
127
128 *value = chunk_alloc(len);
59a987b8 129 if (wc_curve25519_export_public_ex(&this->key.key25519, value->ptr, &len,
c92eade8
SP
130 EC25519_LITTLE_ENDIAN) != 0)
131 {
132 chunk_free(value);
133 return FALSE;
134 }
135 return TRUE;
136}
137
59a987b8 138METHOD(diffie_hellman_t, set_private_value_25519, bool,
c92eade8
SP
139 private_diffie_hellman_t *this, chunk_t value)
140{
c92eade8 141 curve25519_key pub;
d3329ee5
TB
142 u_char basepoint[CURVE25519_KEYSIZE] = {9};
143 word32 len = CURVE25519_KEYSIZE;
144 int ret;
c92eade8
SP
145
146 ret = wc_curve25519_init(&pub);
d3329ee5 147 /* create base point for calculating public key */
c92eade8
SP
148 if (ret == 0)
149 {
150 ret = wc_curve25519_import_public_ex(basepoint, CURVE25519_KEYSIZE,
151 &pub, EC25519_LITTLE_ENDIAN);
152 }
153 if (ret == 0)
154 {
59a987b8
TB
155 ret = wc_curve25519_import_private_ex(value.ptr, value.len,
156 &this->key.key25519, EC25519_LITTLE_ENDIAN);
157 }
158 if (ret == 0)
159 {
160 ret = wc_curve25519_shared_secret_ex(&this->key.key25519, &pub,
161 this->key.key25519.p.point, &len,
162 EC25519_LITTLE_ENDIAN);
163 }
164 return ret == 0;
165}
166
167#endif /* HAVE_CURVE25519 */
168
169#ifdef HAVE_CURVE448
170
171METHOD(diffie_hellman_t, set_other_public_value_448, bool,
172 private_diffie_hellman_t *this, chunk_t value)
173{
174 word32 len = CURVE448_KEY_SIZE;
175 curve448_key pub;
176 int ret;
177
178 if (!diffie_hellman_verify_value(this->group, value))
179 {
180 return FALSE;
181 }
182
183 ret = wc_curve448_init(&pub);
184 if (ret != 0)
185 {
186 DBG1(DBG_LIB, "%N public key initialization failed",
187 diffie_hellman_group_names, this->group);
188 return FALSE;
189 }
190
191 ret = wc_curve448_import_public_ex(value.ptr, value.len, &pub,
192 EC448_LITTLE_ENDIAN);
193 if (ret != 0)
194 {
195 DBG1(DBG_LIB, "%N public value is malformed",
196 diffie_hellman_group_names, this->group);
197 return FALSE;
198 }
199
200 chunk_clear(&this->shared_secret);
201 this->shared_secret = chunk_alloc(len);
202 if (wc_curve448_shared_secret_ex(&this->key.key448, &pub,
203 this->shared_secret.ptr, &len, EC448_LITTLE_ENDIAN) != 0)
204 {
205 DBG1(DBG_LIB, "%N shared secret computation failed",
206 diffie_hellman_group_names, this->group);
207 chunk_clear(&this->shared_secret);
208 wc_curve448_free(&pub);
209 return FALSE;
210 }
211 wc_curve448_free(&pub);
212 return TRUE;
213}
214
215METHOD(diffie_hellman_t, get_my_public_value_448, bool,
216 private_diffie_hellman_t *this, chunk_t *value)
217{
218 word32 len = CURVE448_KEY_SIZE;
219
220 *value = chunk_alloc(len);
221 if (wc_curve448_export_public_ex(&this->key.key448, value->ptr, &len,
222 EC448_LITTLE_ENDIAN) != 0)
223 {
224 chunk_free(value);
225 return FALSE;
226 }
227 return TRUE;
228}
229
230METHOD(diffie_hellman_t, set_private_value_448, bool,
231 private_diffie_hellman_t *this, chunk_t value)
232{
233 curve448_key pub;
234 u_char basepoint[CURVE448_KEY_SIZE] = {5};
235 word32 len = CURVE448_KEY_SIZE;
236 int ret;
237
238 ret = wc_curve448_init(&pub);
239 /* create base point for calculating public key */
240 if (ret == 0)
241 {
242 ret = wc_curve448_import_public_ex(basepoint, CURVE448_KEY_SIZE,
243 &pub, EC448_LITTLE_ENDIAN);
c92eade8
SP
244 }
245 if (ret == 0)
246 {
59a987b8
TB
247 ret = wc_curve448_import_private_ex(value.ptr, value.len,
248 &this->key.key448, EC448_LITTLE_ENDIAN);
249 }
250 if (ret == 0)
251 {
252 ret = wc_curve448_shared_secret_ex(&this->key.key448, &pub,
253 this->key.key448.p, &len,
254 EC448_LITTLE_ENDIAN);
c92eade8 255 }
c92eade8
SP
256 return ret == 0;
257}
258
59a987b8
TB
259#endif /* HAVE_CURVE448 */
260
c92eade8
SP
261METHOD(diffie_hellman_t, get_shared_secret, bool,
262 private_diffie_hellman_t *this, chunk_t *secret)
263{
d3329ee5 264 if (!this->shared_secret.len)
c92eade8
SP
265 {
266 return FALSE;
267 }
268 *secret = chunk_clone(this->shared_secret);
269 return TRUE;
270}
271
272METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
273 private_diffie_hellman_t *this)
274{
275 return this->group;
276}
277
278METHOD(diffie_hellman_t, destroy, void,
279 private_diffie_hellman_t *this)
280{
59a987b8
TB
281 if (this->group == CURVE_25519)
282 {
283#ifdef HAVE_CURVE25519
284 wc_curve25519_free(&this->key.key25519);
285#endif
286 }
287 else if (this->group == CURVE_448)
288 {
289#ifdef HAVE_CURVE448
290 wc_curve448_free(&this->key.key448);
291#endif
292 }
c92eade8
SP
293 chunk_clear(&this->shared_secret);
294 free(this);
295}
296
297/*
298 * Described in header
299 */
300diffie_hellman_t *wolfssl_x_diffie_hellman_create(diffie_hellman_group_t group)
301{
302 private_diffie_hellman_t *this;
303 WC_RNG rng;
59a987b8 304 int ret = -1;
c92eade8 305
c92eade8
SP
306 INIT(this,
307 .public = {
308 .get_shared_secret = _get_shared_secret,
c92eade8
SP
309 .get_dh_group = _get_dh_group,
310 .destroy = _destroy,
311 },
312 .group = group,
313 );
314
c92eade8
SP
315 if (wc_InitRng(&rng) != 0)
316 {
d3329ee5
TB
317 DBG1(DBG_LIB, "initializing a random number generator failed");
318 destroy(this);
c92eade8
SP
319 return NULL;
320 }
59a987b8
TB
321
322 if (group == CURVE_25519)
323 {
324#ifdef HAVE_CURVE25519
325 this->public.set_other_public_value = _set_other_public_value_25519;
326 this->public.get_my_public_value = _get_my_public_value_25519;
327 this->public.set_private_value = _set_private_value_25519;
328
329 if (wc_curve25519_init(&this->key.key25519) != 0)
330 {
331 DBG1(DBG_LIB, "initializing key failed");
332 free(this);
333 return NULL;
334 }
335 ret = wc_curve25519_make_key(&rng, CURVE25519_KEYSIZE,
336 &this->key.key25519);
337#endif
338 }
339 else if (group == CURVE_448)
340 {
341#ifdef HAVE_CURVE448
342 this->public.set_other_public_value = _set_other_public_value_448;
343 this->public.get_my_public_value = _get_my_public_value_448;
344 this->public.set_private_value = _set_private_value_448;
345
346 if (wc_curve448_init(&this->key.key448) != 0)
347 {
348 DBG1(DBG_LIB, "initializing key failed");
349 free(this);
350 return NULL;
351 }
352 ret = wc_curve448_make_key(&rng, CURVE448_KEY_SIZE, &this->key.key448);
353#endif
354 }
c92eade8
SP
355 wc_FreeRng(&rng);
356 if (ret != 0)
357 {
d3329ee5
TB
358 DBG1(DBG_LIB, "making a key failed");
359 destroy(this);
c92eade8
SP
360 return NULL;
361 }
362 return &this->public;
363}
364
59a987b8 365#endif /* HAVE_CURVE25519 || HAVE_CURVE448 */