wolfssl: Add wolfSSL plugin for cryptographic implementations
[strongswan.git] / src / libstrongswan / plugins / wolfssl / wolfssl_x_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_CURVE25519
26
27 #include "wolfssl_x_diffie_hellman.h"
28
29 #include <utils/debug.h>
30
31 #include <wolfssl/wolfcrypt/curve25519.h>
32 #include <wolfssl/wolfcrypt/fe_operations.h>
33
34 typedef struct private_diffie_hellman_t private_diffie_hellman_t;
35
36 /**
37 * Private data
38 */
39 struct private_diffie_hellman_t {
40 /**
41 * Public interface.
42 */
43 diffie_hellman_t public;
44
45 /**
46 * Diffie Hellman group number.
47 */
48 diffie_hellman_group_t group;
49
50 /**
51 * Private (public) key
52 */
53 curve25519_key key;
54
55 /**
56 * Shared secret
57 */
58 chunk_t shared_secret;
59
60 /**
61 * True if shared secret is computed
62 */
63 bool computed;
64 };
65
66 /**
67 * Compute the shared secret
68 */
69 static bool compute_shared_key(private_diffie_hellman_t *this,
70 curve25519_key *pub, chunk_t *shared_secret)
71 {
72 int ret;
73 word32 len = CURVE25519_KEYSIZE;
74
75 *shared_secret = chunk_alloc(len);
76 ret = wc_curve25519_shared_secret_ex(&this->key, pub, shared_secret->ptr,
77 &len, EC25519_LITTLE_ENDIAN);
78 return ret == 0;
79 }
80
81 METHOD(diffie_hellman_t, set_other_public_value, bool,
82 private_diffie_hellman_t *this, chunk_t value)
83 {
84 int ret;
85 curve25519_key pub;
86
87 if (!diffie_hellman_verify_value(this->group, value))
88 {
89 return FALSE;
90 }
91
92 ret = wc_curve25519_init(&pub);
93 if (ret < 0)
94 {
95 DBG1(DBG_LIB, "%N public key initialization failed",
96 diffie_hellman_group_names, this->group);
97 return FALSE;
98 }
99
100 ret = wc_curve25519_import_public_ex(value.ptr, value.len, &pub,
101 EC25519_LITTLE_ENDIAN);
102 if (ret != 0)
103 {
104 DBG1(DBG_LIB, "%N public value is malformed",
105 diffie_hellman_group_names, this->group);
106 return FALSE;
107 }
108
109 chunk_clear(&this->shared_secret);
110
111 if (!compute_shared_key(this, &pub, &this->shared_secret))
112 {
113 DBG1(DBG_LIB, "%N shared secret computation failed",
114 diffie_hellman_group_names, this->group);
115 wc_curve25519_free(&pub);
116 return FALSE;
117 }
118 this->computed = TRUE;
119 wc_curve25519_free(&pub);
120 return TRUE;
121 }
122
123 METHOD(diffie_hellman_t, get_my_public_value, bool,
124 private_diffie_hellman_t *this, chunk_t *value)
125 {
126 word32 len = CURVE25519_KEYSIZE;
127
128 *value = chunk_alloc(len);
129 if (wc_curve25519_export_public_ex(&this->key, value->ptr, &len,
130 EC25519_LITTLE_ENDIAN) != 0)
131 {
132 chunk_free(value);
133 return FALSE;
134 }
135 return TRUE;
136 }
137
138 METHOD(diffie_hellman_t, set_private_value, bool,
139 private_diffie_hellman_t *this, chunk_t value)
140 {
141 int ret;
142 unsigned char basepoint[CURVE25519_KEYSIZE] = {9};
143 curve25519_key pub;
144 int len;
145
146 ret = wc_curve25519_init(&pub);
147 /* Create base point for calculating public key */
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 {
155 ret = wc_curve25519_import_private_ex(value.ptr, value.len, &this->key,
156 EC25519_LITTLE_ENDIAN);
157 }
158 if (ret == 0)
159 {
160 len = CURVE25519_KEYSIZE;
161 ret = wc_curve25519_shared_secret_ex(&this->key, &pub,
162 this->key.p.point, &len, EC25519_LITTLE_ENDIAN);
163 if (ret > 0)
164 {
165 ret = 0;
166 }
167 }
168
169 return ret == 0;
170 }
171
172 METHOD(diffie_hellman_t, get_shared_secret, bool,
173 private_diffie_hellman_t *this, chunk_t *secret)
174 {
175 if (!this->computed)
176 {
177 return FALSE;
178 }
179 *secret = chunk_clone(this->shared_secret);
180 return TRUE;
181 }
182
183 METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
184 private_diffie_hellman_t *this)
185 {
186 return this->group;
187 }
188
189 METHOD(diffie_hellman_t, destroy, void,
190 private_diffie_hellman_t *this)
191 {
192 wc_curve25519_free(&this->key);
193 chunk_clear(&this->shared_secret);
194 free(this);
195 }
196
197 /*
198 * Described in header
199 */
200 diffie_hellman_t *wolfssl_x_diffie_hellman_create(diffie_hellman_group_t group)
201 {
202 private_diffie_hellman_t *this;
203 WC_RNG rng;
204 int ret;
205
206 switch (group)
207 {
208 case CURVE_25519:
209 break;
210 default:
211 return NULL;
212 }
213
214 INIT(this,
215 .public = {
216 .get_shared_secret = _get_shared_secret,
217 .set_other_public_value = _set_other_public_value,
218 .get_my_public_value = _get_my_public_value,
219 .set_private_value = _set_private_value,
220 .get_dh_group = _get_dh_group,
221 .destroy = _destroy,
222 },
223 .group = group,
224 );
225
226 if (wc_curve25519_init(&this->key) != 0)
227 {
228 DBG1(DBG_LIB, "Initializing key failed");
229 free(this);
230 return NULL;
231 }
232
233 if (wc_InitRng(&rng) != 0)
234 {
235 DBG1(DBG_LIB, "Initializing a random number generator failed");
236 free(this);
237 return NULL;
238 }
239 ret = wc_curve25519_make_key(&rng, CURVE25519_KEYSIZE, &this->key);
240 wc_FreeRng(&rng);
241 if (ret != 0)
242 {
243 DBG1(DBG_LIB, "Making a key failed");
244 free(this);
245 return NULL;
246 }
247 return &this->public;
248 }
249
250 #endif /* HAVE_CURVE25519 */