]>
Commit | Line | Data |
---|---|---|
c92eade8 SP |
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 { | |
d3329ee5 | 40 | |
c92eade8 SP |
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 | ||
c92eade8 SP |
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; | |
c92eade8 SP |
75 | }; |
76 | ||
77 | METHOD(diffie_hellman_t, get_my_public_value, bool, | |
78 | private_wolfssl_diffie_hellman_t *this, chunk_t *value) | |
79 | { | |
d3329ee5 | 80 | *value = chunk_copy_pad(chunk_alloc(this->len), this->pub, 0x00); |
c92eade8 SP |
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 | { | |
d3329ee5 | 87 | if (!this->shared_secret.len) |
c92eade8 SP |
88 | { |
89 | return FALSE; | |
90 | } | |
d3329ee5 | 91 | *secret = chunk_copy_pad(chunk_alloc(this->len), this->shared_secret, 0x00); |
c92eade8 SP |
92 | return TRUE; |
93 | } | |
94 | ||
c92eade8 SP |
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); | |
d3329ee5 | 106 | this->shared_secret = chunk_alloc(this->len); |
c92eade8 SP |
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"); | |
d3329ee5 | 111 | chunk_free(&this->shared_secret); |
c92eade8 SP |
112 | return FALSE; |
113 | } | |
114 | this->shared_secret.len = len; | |
c92eade8 SP |
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; | |
c92eade8 SP |
124 | |
125 | chunk_clear(&this->priv); | |
126 | this->priv = chunk_clone(value); | |
127 | ||
d3329ee5 | 128 | /* calculate public value - g^priv mod p */ |
c92eade8 SP |
129 | if (wolfssl_mp2chunk(&this->dh.g, &g)) |
130 | { | |
131 | len = this->pub.len; | |
d3329ee5 TB |
132 | if (wc_DhAgree(&this->dh, this->pub.ptr, &len, this->priv.ptr, |
133 | this->priv.len, g.ptr, g.len) == 0) | |
134 | { | |
c92eade8 SP |
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 | ||
c92eade8 SP |
150 | METHOD(diffie_hellman_t, destroy, void, |
151 | private_wolfssl_diffie_hellman_t *this) | |
152 | { | |
c92eade8 SP |
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 | ||
d3329ee5 TB |
200 | /** |
201 | * Generic internal constructor | |
c92eade8 | 202 | */ |
d3329ee5 TB |
203 | static wolfssl_diffie_hellman_t *create_generic(diffie_hellman_group_t group, |
204 | chunk_t g, chunk_t p) | |
c92eade8 SP |
205 | { |
206 | private_wolfssl_diffie_hellman_t *this; | |
207 | word32 privLen, pubLen; | |
d3329ee5 | 208 | WC_RNG rng; |
c92eade8 SP |
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 | }, | |
d3329ee5 TB |
221 | .group = group, |
222 | .len = p.len, | |
c92eade8 SP |
223 | ); |
224 | ||
c92eade8 SP |
225 | if (wc_InitDhKey(&this->dh) != 0) |
226 | { | |
c92eade8 SP |
227 | free(this); |
228 | return NULL; | |
229 | } | |
230 | ||
d3329ee5 | 231 | if (wc_DhSetKey(&this->dh, p.ptr, p.len, g.ptr, g.len) != 0) |
c92eade8 | 232 | { |
d3329ee5 TB |
233 | destroy(this); |
234 | return NULL; | |
c92eade8 | 235 | } |
d3329ee5 TB |
236 | |
237 | if (wc_InitRng(&rng) != 0) | |
c92eade8 | 238 | { |
d3329ee5 TB |
239 | destroy(this); |
240 | return NULL; | |
c92eade8 SP |
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 */ | |
d3329ee5 | 248 | if (wc_DhGenerateKeyPair(&this->dh, &rng, this->priv.ptr, &privLen, |
c92eade8 SP |
249 | this->pub.ptr, &pubLen) != 0) |
250 | { | |
d3329ee5 | 251 | wc_FreeRng(&rng); |
c92eade8 SP |
252 | destroy(this); |
253 | return NULL; | |
254 | } | |
255 | this->pub.len = pubLen; | |
256 | this->priv.len = privLen; | |
d3329ee5 | 257 | wc_FreeRng(&rng); |
c92eade8 SP |
258 | |
259 | return &this->public; | |
260 | } | |
261 | ||
d3329ee5 TB |
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 | ||
c92eade8 | 285 | #endif /* NO_DH */ |