wolfssl: Add wolfSSL plugin for cryptographic implementations
[strongswan.git] / src / libstrongswan / plugins / wolfssl / wolfssl_ec_diffie_hellman.c
1 /*
2 * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23 #include "wolfssl_common.h"
24
25 #ifdef HAVE_ECC_DHE
26
27 #include <wolfssl/wolfcrypt/ecc.h>
28
29 #include "wolfssl_ec_diffie_hellman.h"
30 #include "wolfssl_util.h"
31
32 #include <utils/debug.h>
33
34 typedef struct private_wolfssl_ec_diffie_hellman_t private_wolfssl_ec_diffie_hellman_t;
35
36 /**
37 * Private data of an wolfssl_ec_diffie_hellman_t object.
38 */
39 struct private_wolfssl_ec_diffie_hellman_t {
40 /**
41 * Public wolfssl_ec_diffie_hellman_t interface.
42 */
43 wolfssl_ec_diffie_hellman_t public;
44
45 /**
46 * Diffie Hellman group number.
47 */
48 diffie_hellman_group_t group;
49
50 /**
51 * EC curve id for creating keys
52 */
53 ecc_curve_id curve_id;
54
55 /**
56 * Size of an ordinate in bytes
57 */
58 int keysize;
59
60 /**
61 * EC private (public) key
62 */
63 ecc_key key;
64
65 /**
66 * Other public key
67 */
68 ecc_point *pub_key;
69
70 /**
71 * Shared secret
72 */
73 chunk_t shared_secret;
74
75 /**
76 * Random number generator
77 */
78 WC_RNG rng;
79
80 /**
81 * True if shared secret is computed
82 */
83 bool computed;
84 };
85
86 /**
87 * Convert a chunk to an ecc_point (which must already exist). The x and y
88 * coordinates of the point have to be concatenated in the chunk.
89 */
90 static bool chunk2ecp(chunk_t chunk, ecc_point *point)
91 {
92 if (!wolfssl_mp_split(chunk, point->x, point->y))
93 return FALSE;
94 if (mp_set(point->z, 1) != 0)
95 return FALSE;
96 return TRUE;
97 }
98
99 /**
100 * Convert an ec_point to a chunk by concatenating the x and y coordinates of
101 * the point. This function allocates memory for the chunk.
102 */
103 static bool ecp2chunk(int keysize, ecc_point *point, chunk_t *chunk,
104 bool x_coordinate_only)
105 {
106 mp_int *y = NULL;
107
108 if (!x_coordinate_only)
109 {
110 keysize *= 2;
111 y = point->y;
112 }
113 return wolfssl_mp_cat(keysize, point->x, y, chunk);
114 }
115
116
117 /**
118 * Perform the elliptic curve scalar multiplication.
119 */
120 static bool wolfssl_ecc_multiply(const ecc_set_type *ecc_set, mp_int *scalar,
121 ecc_point* point, ecc_point* r)
122 {
123 int ret;
124 mp_int a, prime;
125
126 ret = mp_init(&a);
127 if (ret != 0)
128 {
129 return FALSE;
130 }
131 ret = mp_init(&prime);
132 if (ret != 0)
133 {
134 mp_free(&a);
135 return FALSE;
136 }
137
138 ret = mp_read_radix(&a, ecc_set->Af, MP_RADIX_HEX);
139 if (ret == 0)
140 {
141 ret = mp_read_radix(&prime, ecc_set->prime, MP_RADIX_HEX);
142 }
143 if (ret == 0)
144 {
145 /* Multiply the point by our secret */
146 ret = wc_ecc_mulmod(scalar, point, r, &a, &prime, 1);
147 }
148
149 mp_free(&prime);
150 mp_free(&a);
151
152 return ret == 0;
153 }
154
155 /**
156 * Compute the shared secret.
157 *
158 * We cannot use the function wc_ecc_shared_secret() because that returns only
159 * the x coordinate of the shared secret point (which is defined, for instance,
160 * in 'NIST SP 800-56A').
161 * However, we need both coordinates as RFC 4753 says: "The Diffie-Hellman
162 * public value is obtained by concatenating the x and y values. The format
163 * of the Diffie-Hellman shared secret value is the same as that of the
164 * Diffie-Hellman public value."
165 */
166 static bool compute_shared_key(private_wolfssl_ec_diffie_hellman_t *this,
167 chunk_t *shared_secret)
168 {
169 bool success = FALSE;
170 ecc_point* secret;
171 bool x_coordinate_only;
172
173 if ((secret = wc_ecc_new_point()) == NULL)
174 {
175 return FALSE;
176 }
177
178 if (wolfssl_ecc_multiply(this->key.dp, &this->key.k, this->pub_key, secret))
179 {
180 /*
181 * The default setting ecp_x_coordinate_only = TRUE
182 * applies the following errata for RFC 4753:
183 * http://www.rfc-editor.org/errata_search.php?eid=9
184 */
185 x_coordinate_only = lib->settings->get_bool(lib->settings,
186 "%s.ecp_x_coordinate_only", TRUE, lib->ns);
187 success = ecp2chunk(this->keysize, secret, shared_secret,
188 x_coordinate_only);
189 }
190
191 wc_ecc_del_point(secret);
192 return success;
193 }
194
195 METHOD(diffie_hellman_t, set_other_public_value, bool,
196 private_wolfssl_ec_diffie_hellman_t *this, chunk_t value)
197 {
198 if (!diffie_hellman_verify_value(this->group, value))
199 {
200 return FALSE;
201 }
202
203 if (!chunk2ecp(value, this->pub_key))
204 {
205 DBG1(DBG_LIB, "ECDH public value is malformed");
206 return FALSE;
207 }
208
209 chunk_clear(&this->shared_secret);
210
211 if (!compute_shared_key(this, &this->shared_secret))
212 {
213 DBG1(DBG_LIB, "ECDH shared secret computation failed");
214 return FALSE;
215 }
216
217 this->computed = TRUE;
218 return TRUE;
219 }
220
221 METHOD(diffie_hellman_t, get_my_public_value, bool,
222 private_wolfssl_ec_diffie_hellman_t *this,chunk_t *value)
223 {
224 return ecp2chunk(this->keysize, &this->key.pubkey, value, FALSE);
225 }
226
227 METHOD(diffie_hellman_t, set_private_value, bool,
228 private_wolfssl_ec_diffie_hellman_t *this, chunk_t value)
229 {
230 bool success = FALSE;
231 ecc_point *base;
232 int ret;
233
234 if ((base = wc_ecc_new_point()) == NULL)
235 {
236 return FALSE;
237 }
238
239 ret = mp_read_unsigned_bin(&this->key.k, value.ptr, value.len);
240 /* Get base point */
241 if (ret == 0)
242 {
243 ret = mp_read_radix(base->x, this->key.dp->Gx, MP_RADIX_HEX);
244 }
245 if (ret == 0)
246 {
247 ret = mp_read_radix(base->y, this->key.dp->Gy, MP_RADIX_HEX);
248 }
249 if (ret == 0)
250 {
251 ret = mp_set(base->z, 1);
252 }
253 if (ret == 0)
254 {
255 /* Calculate public key */
256 success = wolfssl_ecc_multiply(this->key.dp, &this->key.k, base,
257 &this->key.pubkey);
258 }
259
260 wc_ecc_del_point(base);
261
262 return success;
263 }
264
265 METHOD(diffie_hellman_t, get_shared_secret, bool,
266 private_wolfssl_ec_diffie_hellman_t *this, chunk_t *secret)
267 {
268 if (!this->computed)
269 {
270 return FALSE;
271 }
272 *secret = chunk_clone(this->shared_secret);
273 return TRUE;
274 }
275
276 METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
277 private_wolfssl_ec_diffie_hellman_t *this)
278 {
279 return this->group;
280 }
281
282 METHOD(diffie_hellman_t, destroy, void,
283 private_wolfssl_ec_diffie_hellman_t *this)
284 {
285 wc_FreeRng(&this->rng);
286 wc_ecc_del_point(this->pub_key);
287 wc_ecc_free(&this->key);
288 chunk_clear(&this->shared_secret);
289 free(this);
290 }
291
292 /*
293 * Described in header.
294 */
295 wolfssl_ec_diffie_hellman_t *wolfssl_ec_diffie_hellman_create(diffie_hellman_group_t group)
296 {
297 private_wolfssl_ec_diffie_hellman_t *this;
298
299 INIT(this,
300 .public = {
301 .dh = {
302 .get_shared_secret = _get_shared_secret,
303 .set_other_public_value = _set_other_public_value,
304 .get_my_public_value = _get_my_public_value,
305 .set_private_value = _set_private_value,
306 .get_dh_group = _get_dh_group,
307 .destroy = _destroy,
308 },
309 },
310 .group = group,
311 );
312
313 if (wc_ecc_init(&this->key) != 0)
314 {
315 DBG1(DBG_LIB, "key init failed, ecdh create failed");
316 free(this);
317 return NULL;
318 }
319 if ((this->pub_key = wc_ecc_new_point()) == NULL)
320 {
321 wc_ecc_free(&this->key);
322 DBG1(DBG_LIB, "pub_key init failed, ecdh create failed");
323 free(this);
324 return NULL;
325 }
326 if (wc_InitRng(&this->rng) != 0)
327 {
328 wc_ecc_del_point(this->pub_key);
329 wc_ecc_free(&this->key);
330 DBG1(DBG_LIB, "RNG init failed, ecdh create failed");
331 free(this);
332 return NULL;
333 }
334
335 switch (group)
336 {
337 case ECP_192_BIT:
338 this->curve_id = ECC_SECP192R1;
339 this->keysize = 192 / 8;
340 break;
341 case ECP_224_BIT:
342 this->curve_id = ECC_SECP224R1;
343 this->keysize = 224 / 8;
344 break;
345 case ECP_256_BIT:
346 this->curve_id = ECC_SECP256R1;
347 this->keysize = 256 / 8;
348 break;
349 case ECP_384_BIT:
350 this->curve_id = ECC_SECP384R1;
351 this->keysize = 384 / 8;
352 break;
353 case ECP_521_BIT:
354 this->curve_id = ECC_SECP521R1;
355 this->keysize = (521 + 7) / 8;
356 break;
357 #ifdef HAVE_BRAINPOOL
358 case ECP_224_BP:
359 this->curve_id = ECC_BRAINPOOLP224R1;
360 this->keysize = 224 / 8;
361 break;
362 case ECP_256_BP:
363 this->curve_id = ECC_BRAINPOOLP256R1;
364 this->keysize = 256 / 8;
365 break;
366 case ECP_384_BP:
367 this->curve_id = ECC_BRAINPOOLP384R1;
368 this->keysize = 384 / 8;
369 break;
370 case ECP_512_BP:
371 this->curve_id = ECC_BRAINPOOLP512R1;
372 this->keysize = 512 / 8;
373 break;
374 #endif
375 default:
376 DBG1(DBG_LIB, "EC group not supported");
377 destroy(this);
378 return NULL;
379 }
380
381 /* generate an EC private (public) key */
382 if (wc_ecc_make_key_ex(&this->rng, this->keysize, &this->key,
383 this->curve_id) != 0)
384 {
385 DBG1(DBG_LIB, "Make key failed, wolfssl ECDH create failed");
386 destroy(this);
387 return NULL;
388 }
389
390 return &this->public;
391 }
392 #endif /* HAVE_ECC_DHE */