kernel-netlink: Use correct config option name for HW offloading check
[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 /**
42 * Public wolfssl_diffie_hellman_t interface.
43 */
44 wolfssl_diffie_hellman_t public;
45
46 /**
47 * Diffie Hellman group number.
48 */
49 diffie_hellman_group_t group;
50
51 /**
52 * Diffie Hellman object
53 */
54 DhKey dh;
55
56 /**
57 * Length of public values
58 */
59 int len;
60
61 /**
62 * Private key
63 */
64 chunk_t priv;
65
66 /**
67 * Public key
68 */
69 chunk_t pub;
70
71 /**
72 * Shared secret
73 */
74 chunk_t shared_secret;
75 };
76
77 METHOD(diffie_hellman_t, get_my_public_value, bool,
78 private_wolfssl_diffie_hellman_t *this, chunk_t *value)
79 {
80 *value = chunk_copy_pad(chunk_alloc(this->len), this->pub, 0x00);
81 return TRUE;
82 }
83
84 METHOD(diffie_hellman_t, get_shared_secret, bool,
85 private_wolfssl_diffie_hellman_t *this, chunk_t *secret)
86 {
87 if (!this->shared_secret.len)
88 {
89 return FALSE;
90 }
91 *secret = chunk_copy_pad(chunk_alloc(this->len), this->shared_secret, 0x00);
92 return TRUE;
93 }
94
95 METHOD(diffie_hellman_t, set_other_public_value, bool,
96 private_wolfssl_diffie_hellman_t *this, chunk_t value)
97 {
98 word32 len;
99
100 if (!diffie_hellman_verify_value(this->group, value))
101 {
102 return FALSE;
103 }
104
105 chunk_clear(&this->shared_secret);
106 this->shared_secret = chunk_alloc(this->len);
107 if (wc_DhAgree(&this->dh, this->shared_secret.ptr, &len, this->priv.ptr,
108 this->priv.len, value.ptr, value.len) != 0)
109 {
110 DBG1(DBG_LIB, "DH shared secret computation failed");
111 chunk_free(&this->shared_secret);
112 return FALSE;
113 }
114 this->shared_secret.len = len;
115 return TRUE;
116 }
117
118 METHOD(diffie_hellman_t, set_private_value, bool,
119 private_wolfssl_diffie_hellman_t *this, chunk_t value)
120 {
121 bool success = FALSE;
122 chunk_t g;
123 word32 len;
124
125 chunk_clear(&this->priv);
126 this->priv = chunk_clone(value);
127
128 /* calculate public value - g^priv mod p */
129 if (wolfssl_mp2chunk(&this->dh.g, &g))
130 {
131 len = this->pub.len;
132 if (wc_DhAgree(&this->dh, this->pub.ptr, &len, this->priv.ptr,
133 this->priv.len, g.ptr, g.len) == 0)
134 {
135 this->pub.len = len;
136 success = TRUE;
137 }
138 }
139
140 free(g.ptr);
141 return success;
142 }
143
144 METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
145 private_wolfssl_diffie_hellman_t *this)
146 {
147 return this->group;
148 }
149
150 METHOD(diffie_hellman_t, destroy, void,
151 private_wolfssl_diffie_hellman_t *this)
152 {
153 wc_FreeDhKey(&this->dh);
154 chunk_clear(&this->pub);
155 chunk_clear(&this->priv);
156 chunk_clear(&this->shared_secret);
157 free(this);
158 }
159
160 /**
161 * Maximum private key length when generating key
162 */
163 static int wolfssl_priv_key_size(int len)
164 {
165 if (len <= 128)
166 {
167 return 21;
168 }
169 if (len <= 256)
170 {
171 return 29;
172 }
173 if (len <= 384)
174 {
175 return 34;
176 }
177 if (len <= 512)
178 {
179 return 39;
180 }
181 if (len <= 640)
182 {
183 return 42;
184 }
185 if (len <= 768)
186 {
187 return 46;
188 }
189 if (len <= 896)
190 {
191 return 49;
192 }
193 if (len <= 1024)
194 {
195 return 52;
196 }
197 return len / 20;
198 }
199
200 /**
201 * Generic internal constructor
202 */
203 static wolfssl_diffie_hellman_t *create_generic(diffie_hellman_group_t group,
204 chunk_t g, chunk_t p)
205 {
206 private_wolfssl_diffie_hellman_t *this;
207 word32 privLen, pubLen;
208 WC_RNG rng;
209
210 INIT(this,
211 .public = {
212 .dh = {
213 .get_shared_secret = _get_shared_secret,
214 .set_other_public_value = _set_other_public_value,
215 .get_my_public_value = _get_my_public_value,
216 .set_private_value = _set_private_value,
217 .get_dh_group = _get_dh_group,
218 .destroy = _destroy,
219 },
220 },
221 .group = group,
222 .len = p.len,
223 );
224
225 if (wc_InitDhKey(&this->dh) != 0)
226 {
227 free(this);
228 return NULL;
229 }
230
231 if (wc_DhSetKey(&this->dh, p.ptr, p.len, g.ptr, g.len) != 0)
232 {
233 destroy(this);
234 return NULL;
235 }
236
237 if (wc_InitRng(&rng) != 0)
238 {
239 destroy(this);
240 return NULL;
241 }
242
243 this->priv = chunk_alloc(wolfssl_priv_key_size(this->len));
244 this->pub = chunk_alloc(this->len);
245 privLen = this->priv.len;
246 pubLen = this->pub.len;
247 /* generate my public and private values */
248 if (wc_DhGenerateKeyPair(&this->dh, &rng, this->priv.ptr, &privLen,
249 this->pub.ptr, &pubLen) != 0)
250 {
251 wc_FreeRng(&rng);
252 destroy(this);
253 return NULL;
254 }
255 this->pub.len = pubLen;
256 this->priv.len = privLen;
257 wc_FreeRng(&rng);
258
259 return &this->public;
260 }
261
262 /*
263 * Described in header
264 */
265 wolfssl_diffie_hellman_t *wolfssl_diffie_hellman_create(
266 diffie_hellman_group_t group, ...)
267 {
268 diffie_hellman_params_t *params;
269 chunk_t g, p;
270
271 if (group == MODP_CUSTOM)
272 {
273 VA_ARGS_GET(group, g, p);
274 return create_generic(group, g, p);
275 }
276 params = diffie_hellman_get_params(group);
277 if (!params)
278 {
279 return NULL;
280 }
281 /* wolfSSL doesn't support optimized exponent sizes according to RFC 3526 */
282 return create_generic(group, params->generator, params->prime);
283 }
284
285 #endif /* NO_DH */