wolfssl: Add wolfSSL plugin for cryptographic implementations
[strongswan.git] / src / libstrongswan / plugins / wolfssl / wolfssl_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 #ifndef NO_DH
26
27 #include <wolfssl/wolfcrypt/dh.h>
28
29 #include "wolfssl_diffie_hellman.h"
30 #include "wolfssl_util.h"
31
32 #include <utils/debug.h>
33
34 typedef struct private_wolfssl_diffie_hellman_t private_wolfssl_diffie_hellman_t;
35
36 /**
37 * Private data of an wolfssl_diffie_hellman_t object.
38 */
39 struct private_wolfssl_diffie_hellman_t {
40 /**
41 * Public wolfssl_diffie_hellman_t interface.
42 */
43 wolfssl_diffie_hellman_t public;
44
45 /**
46 * Diffie Hellman group number.
47 */
48 diffie_hellman_group_t group;
49
50 /**
51 * Diffie Hellman object
52 */
53 DhKey dh;
54
55 /**
56 * Random number generator to use with RSA operations.
57 */
58 WC_RNG rng;
59
60 /**
61 * Length of public values
62 */
63 int len;
64
65 /**
66 * Private key
67 */
68 chunk_t priv;
69
70 /**
71 * Public key
72 */
73 chunk_t pub;
74
75 /**
76 * Shared secret
77 */
78 chunk_t shared_secret;
79
80 /**
81 * True if shared secret is computed
82 */
83 bool computed;
84 };
85
86 METHOD(diffie_hellman_t, get_my_public_value, bool,
87 private_wolfssl_diffie_hellman_t *this, chunk_t *value)
88 {
89 /* Front pad the value with zeros to length of prime */
90 *value = chunk_alloc(this->len);
91 memset(value->ptr, 0, value->len - this->pub.len);
92 memcpy(value->ptr + value->len - this->pub.len, this->pub.ptr,
93 this->pub.len);
94 return TRUE;
95 }
96
97 METHOD(diffie_hellman_t, get_shared_secret, bool,
98 private_wolfssl_diffie_hellman_t *this, chunk_t *secret)
99 {
100 if (!this->computed)
101 {
102 return FALSE;
103 }
104
105 /* Front pad with zeros to length of prime */
106 *secret = chunk_alloc(this->len);
107 memset(secret->ptr, 0, secret->len);
108 memcpy(secret->ptr + secret->len - this->shared_secret.len,
109 this->shared_secret.ptr, this->shared_secret.len);
110 return TRUE;
111 }
112
113
114 METHOD(diffie_hellman_t, set_other_public_value, bool,
115 private_wolfssl_diffie_hellman_t *this, chunk_t value)
116 {
117 word32 len;
118
119 if (!diffie_hellman_verify_value(this->group, value))
120 {
121 return FALSE;
122 }
123
124 chunk_clear(&this->shared_secret);
125 this->shared_secret.ptr = malloc(this->len);
126 memset(this->shared_secret.ptr, 0xFF, this->shared_secret.len);
127 len = this->shared_secret.len;
128 if (wc_DhAgree(&this->dh, this->shared_secret.ptr, &len, this->priv.ptr,
129 this->priv.len, value.ptr, value.len) != 0)
130 {
131 DBG1(DBG_LIB, "DH shared secret computation failed");
132 return FALSE;
133 }
134 this->shared_secret.len = len;
135 this->computed = TRUE;
136 return TRUE;
137 }
138
139 METHOD(diffie_hellman_t, set_private_value, bool,
140 private_wolfssl_diffie_hellman_t *this, chunk_t value)
141 {
142 bool success = FALSE;
143 chunk_t g;
144 word32 len;
145 int ret;
146
147 chunk_clear(&this->priv);
148 this->priv = chunk_clone(value);
149
150 /* Calculate public value - g^priv mod p */
151 if (wolfssl_mp2chunk(&this->dh.g, &g))
152 {
153 len = this->pub.len;
154 ret = wc_DhAgree(&this->dh, this->pub.ptr, &len, this->priv.ptr,
155 this->priv.len, g.ptr, g.len);
156 if (ret == 0) {
157 this->pub.len = len;
158 success = TRUE;
159 }
160 }
161
162 free(g.ptr);
163 return success;
164 }
165
166 METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
167 private_wolfssl_diffie_hellman_t *this)
168 {
169 return this->group;
170 }
171
172 /**
173 * Lookup the modulus in modulo table
174 */
175 static status_t set_modulus(private_wolfssl_diffie_hellman_t *this)
176 {
177 diffie_hellman_params_t *params = diffie_hellman_get_params(this->group);
178 if (!params)
179 {
180 return NOT_FOUND;
181 }
182
183 this->len = params->prime.len;
184 if (wc_DhSetKey(&this->dh, params->prime.ptr, params->prime.len,
185 params->generator.ptr, params->generator.len) != 0)
186 {
187 return FAILED;
188 }
189
190 return SUCCESS;
191 }
192
193 METHOD(diffie_hellman_t, destroy, void,
194 private_wolfssl_diffie_hellman_t *this)
195 {
196 wc_FreeRng(&this->rng);
197 wc_FreeDhKey(&this->dh);
198 chunk_clear(&this->pub);
199 chunk_clear(&this->priv);
200 chunk_clear(&this->shared_secret);
201 free(this);
202 }
203
204 /**
205 * Maximum private key length when generating key
206 */
207 static int wolfssl_priv_key_size(int len)
208 {
209 if (len <= 128)
210 {
211 return 21;
212 }
213 if (len <= 256)
214 {
215 return 29;
216 }
217 if (len <= 384)
218 {
219 return 34;
220 }
221 if (len <= 512)
222 {
223 return 39;
224 }
225 if (len <= 640)
226 {
227 return 42;
228 }
229 if (len <= 768)
230 {
231 return 46;
232 }
233 if (len <= 896)
234 {
235 return 49;
236 }
237 if (len <= 1024)
238 {
239 return 52;
240 }
241 return len / 20;
242 }
243
244 /*
245 * Described in header.
246 */
247 wolfssl_diffie_hellman_t *wolfssl_diffie_hellman_create(
248 diffie_hellman_group_t group, ...)
249 {
250 private_wolfssl_diffie_hellman_t *this;
251 word32 privLen, pubLen;
252
253 INIT(this,
254 .public = {
255 .dh = {
256 .get_shared_secret = _get_shared_secret,
257 .set_other_public_value = _set_other_public_value,
258 .get_my_public_value = _get_my_public_value,
259 .set_private_value = _set_private_value,
260 .get_dh_group = _get_dh_group,
261 .destroy = _destroy,
262 },
263 },
264 );
265
266 if (wc_InitRng(&this->rng) != 0)
267 {
268 free(this);
269 return NULL;
270 }
271 if (wc_InitDhKey(&this->dh) != 0)
272 {
273 wc_FreeRng(&this->rng);
274 free(this);
275 return NULL;
276 }
277
278 this->group = group;
279 this->computed = FALSE;
280 this->priv = chunk_empty;
281 this->pub = chunk_empty;
282 this->shared_secret = chunk_empty;
283
284
285 if (group == MODP_CUSTOM)
286 {
287 chunk_t g, p;
288
289 VA_ARGS_GET(group, g, p);
290 this->len = p.len;
291 if (wc_DhSetKey(&this->dh, p.ptr, p.len, g.ptr, g.len) != 0)
292 {
293 destroy(this);
294 return NULL;
295 }
296 }
297 else
298 {
299 /* find a modulus according to group */
300 if (set_modulus(this) != SUCCESS)
301 {
302 destroy(this);
303 return NULL;
304 }
305 }
306
307 this->priv = chunk_alloc(wolfssl_priv_key_size(this->len));
308 this->pub = chunk_alloc(this->len);
309 privLen = this->priv.len;
310 pubLen = this->pub.len;
311 /* generate my public and private values */
312 if (wc_DhGenerateKeyPair(&this->dh, &this->rng, this->priv.ptr, &privLen,
313 this->pub.ptr, &pubLen) != 0)
314 {
315 destroy(this);
316 return NULL;
317 }
318 this->pub.len = pubLen;
319 this->priv.len = privLen;
320
321 return &this->public;
322 }
323
324 #endif /* NO_DH */