008e15fbde6c06c4caec74ce65b87e2ac7974c13
[strongswan.git] / src / libstrongswan / plugins / botan / botan_diffie_hellman.c
1 /*
2 * Copyright (C) 2018 René Korthaus
3 * Copyright (C) 2018 Konstantinos Kolelis
4 * Rohde & Schwarz Cybersecurity GmbH
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25 #include "botan_diffie_hellman.h"
26
27 #include <botan/build.h>
28
29 #ifdef BOTAN_HAS_DIFFIE_HELLMAN
30
31 #include "botan_util.h"
32
33 #include <botan/ffi.h>
34
35 #include <utils/debug.h>
36
37 typedef struct private_botan_diffie_hellman_t private_botan_diffie_hellman_t;
38
39 /**
40 * Private data of an botan_diffie_hellman_t object.
41 */
42 struct private_botan_diffie_hellman_t {
43
44 /**
45 * Public botan_diffie_hellman_t interface
46 */
47 botan_diffie_hellman_t public;
48
49 /**
50 * Diffie Hellman group number
51 */
52 diffie_hellman_group_t group;
53
54 /**
55 * Private key
56 */
57 botan_privkey_t dh_key;
58
59 /**
60 * Diffie hellman shared secret
61 */
62 chunk_t shared_secret;
63
64 /**
65 * Generator value
66 */
67 botan_mp_t g;
68
69 /**
70 * Modulus
71 */
72 botan_mp_t p;
73 };
74
75 /**
76 * Load a DH private key
77 */
78 bool load_private_key(private_botan_diffie_hellman_t *this, chunk_t value)
79 {
80 botan_mp_t xa;
81
82 if (!chunk_to_botan_mp(value, &xa))
83 {
84 return FALSE;
85 }
86
87 if (botan_privkey_destroy(this->dh_key) ||
88 botan_privkey_load_dh(&this->dh_key, this->p, this->g, xa))
89 {
90 botan_mp_destroy(xa);
91 return FALSE;
92 }
93 botan_mp_destroy(xa);
94 return TRUE;
95 }
96
97 METHOD(diffie_hellman_t, set_other_public_value, bool,
98 private_botan_diffie_hellman_t *this, chunk_t value)
99 {
100 botan_pk_op_ka_t op;
101
102 if (!diffie_hellman_verify_value(this->group, value))
103 {
104 return FALSE;
105 }
106
107 if (botan_pk_op_key_agreement_create(&op, this->dh_key, "Raw", 0))
108 {
109 return FALSE;
110 }
111
112 chunk_clear(&this->shared_secret);
113
114 if (botan_pk_op_key_agreement_size(op, &this->shared_secret.len))
115 {
116 botan_pk_op_key_agreement_destroy(op);
117 return FALSE;
118 }
119
120 this->shared_secret = chunk_alloc(this->shared_secret.len);
121 if (botan_pk_op_key_agreement(op, this->shared_secret.ptr,
122 &this->shared_secret.len, value.ptr,
123 value.len, NULL, 0))
124 {
125 chunk_clear(&this->shared_secret);
126 botan_pk_op_key_agreement_destroy(op);
127 return FALSE;
128 }
129 botan_pk_op_key_agreement_destroy(op);
130 return TRUE;
131 }
132
133 METHOD(diffie_hellman_t, get_my_public_value, bool,
134 private_botan_diffie_hellman_t *this, chunk_t *value)
135 {
136 *value = chunk_empty;
137
138 /* get key size of public key first */
139 if (botan_pk_op_key_agreement_export_public(this->dh_key, NULL, &value->len)
140 != BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
141 {
142 return FALSE;
143 }
144
145 *value = chunk_alloc(value->len);
146 if (botan_pk_op_key_agreement_export_public(this->dh_key, value->ptr,
147 &value->len))
148 {
149 chunk_clear(value);
150 return FALSE;
151 }
152 return TRUE;
153 }
154
155 METHOD(diffie_hellman_t, set_private_value, bool,
156 private_botan_diffie_hellman_t *this, chunk_t value)
157 {
158 chunk_clear(&this->shared_secret);
159 return load_private_key(this, value);
160 }
161
162 METHOD(diffie_hellman_t, get_shared_secret, bool,
163 private_botan_diffie_hellman_t *this, chunk_t *secret)
164 {
165 if (!this->shared_secret.len)
166 {
167 return FALSE;
168 }
169 *secret = chunk_clone(this->shared_secret);
170 return TRUE;
171 }
172
173 METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
174 private_botan_diffie_hellman_t *this)
175 {
176 return this->group;
177 }
178
179 METHOD(diffie_hellman_t, destroy, void,
180 private_botan_diffie_hellman_t *this)
181 {
182 botan_mp_destroy(this->p);
183 botan_mp_destroy(this->g);
184 botan_privkey_destroy(this->dh_key);
185 chunk_clear(&this->shared_secret);
186 free(this);
187 }
188
189 /*
190 * Generic internal constructor
191 */
192 static botan_diffie_hellman_t *create_generic(diffie_hellman_group_t group,
193 chunk_t g, chunk_t p, size_t exp_len)
194 {
195 private_botan_diffie_hellman_t *this;
196 chunk_t random;
197 rng_t *rng;
198
199 INIT(this,
200 .public = {
201 .dh = {
202 .get_shared_secret = _get_shared_secret,
203 .set_other_public_value = _set_other_public_value,
204 .get_my_public_value = _get_my_public_value,
205 .set_private_value = _set_private_value,
206 .get_dh_group = _get_dh_group,
207 .destroy = _destroy,
208 },
209 },
210 .group = group,
211 );
212
213 if (!chunk_to_botan_mp(p, &this->p))
214 {
215 destroy(this);
216 return NULL;
217 }
218
219 if (!chunk_to_botan_mp(g, &this->g))
220 {
221 destroy(this);
222 return NULL;
223 }
224
225 rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
226 if (!rng || !rng->allocate_bytes(rng, exp_len, &random))
227 {
228 DESTROY_IF(rng);
229 destroy(this);
230 return NULL;
231 }
232 rng->destroy(rng);
233
234 if (!load_private_key(this, random))
235 {
236 chunk_clear(&random);
237 destroy(this);
238 return NULL;
239 }
240 chunk_clear(&random);
241 return &this->public;
242 }
243
244 /*
245 * Described in header.
246 */
247 botan_diffie_hellman_t *botan_diffie_hellman_create(
248 diffie_hellman_group_t group, ...)
249 {
250 diffie_hellman_params_t *params;
251 chunk_t g, p;
252
253 if (group == MODP_CUSTOM)
254 {
255 VA_ARGS_GET(group, g, p);
256 return create_generic(group, g, p, p.len);
257 }
258
259 params = diffie_hellman_get_params(group);
260 if (!params)
261 {
262 return NULL;
263 }
264 return create_generic(group, params->generator, params->prime,
265 params->exp_len);
266 }
267
268 #endif