botan: Simplify DH/ECDH key derivation
[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 if (!diffie_hellman_verify_value(this->group, value))
101 {
102 return FALSE;
103 }
104
105 chunk_clear(&this->shared_secret);
106
107 return botan_dh_key_derivation(this->dh_key, value, &this->shared_secret);
108 }
109
110 METHOD(diffie_hellman_t, get_my_public_value, bool,
111 private_botan_diffie_hellman_t *this, chunk_t *value)
112 {
113 *value = chunk_empty;
114
115 /* get key size of public key first */
116 if (botan_pk_op_key_agreement_export_public(this->dh_key, NULL, &value->len)
117 != BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
118 {
119 return FALSE;
120 }
121
122 *value = chunk_alloc(value->len);
123 if (botan_pk_op_key_agreement_export_public(this->dh_key, value->ptr,
124 &value->len))
125 {
126 chunk_clear(value);
127 return FALSE;
128 }
129 return TRUE;
130 }
131
132 METHOD(diffie_hellman_t, set_private_value, bool,
133 private_botan_diffie_hellman_t *this, chunk_t value)
134 {
135 chunk_clear(&this->shared_secret);
136 return load_private_key(this, value);
137 }
138
139 METHOD(diffie_hellman_t, get_shared_secret, bool,
140 private_botan_diffie_hellman_t *this, chunk_t *secret)
141 {
142 if (!this->shared_secret.len)
143 {
144 return FALSE;
145 }
146 *secret = chunk_clone(this->shared_secret);
147 return TRUE;
148 }
149
150 METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
151 private_botan_diffie_hellman_t *this)
152 {
153 return this->group;
154 }
155
156 METHOD(diffie_hellman_t, destroy, void,
157 private_botan_diffie_hellman_t *this)
158 {
159 botan_mp_destroy(this->p);
160 botan_mp_destroy(this->g);
161 botan_privkey_destroy(this->dh_key);
162 chunk_clear(&this->shared_secret);
163 free(this);
164 }
165
166 /*
167 * Generic internal constructor
168 */
169 static botan_diffie_hellman_t *create_generic(diffie_hellman_group_t group,
170 chunk_t g, chunk_t p, size_t exp_len)
171 {
172 private_botan_diffie_hellman_t *this;
173 chunk_t random;
174 rng_t *rng;
175
176 INIT(this,
177 .public = {
178 .dh = {
179 .get_shared_secret = _get_shared_secret,
180 .set_other_public_value = _set_other_public_value,
181 .get_my_public_value = _get_my_public_value,
182 .set_private_value = _set_private_value,
183 .get_dh_group = _get_dh_group,
184 .destroy = _destroy,
185 },
186 },
187 .group = group,
188 );
189
190 if (!chunk_to_botan_mp(p, &this->p))
191 {
192 destroy(this);
193 return NULL;
194 }
195
196 if (!chunk_to_botan_mp(g, &this->g))
197 {
198 destroy(this);
199 return NULL;
200 }
201
202 rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
203 if (!rng || !rng->allocate_bytes(rng, exp_len, &random))
204 {
205 DESTROY_IF(rng);
206 destroy(this);
207 return NULL;
208 }
209 rng->destroy(rng);
210
211 if (!load_private_key(this, random))
212 {
213 chunk_clear(&random);
214 destroy(this);
215 return NULL;
216 }
217 chunk_clear(&random);
218 return &this->public;
219 }
220
221 /*
222 * Described in header.
223 */
224 botan_diffie_hellman_t *botan_diffie_hellman_create(
225 diffie_hellman_group_t group, ...)
226 {
227 diffie_hellman_params_t *params;
228 chunk_t g, p;
229
230 if (group == MODP_CUSTOM)
231 {
232 VA_ARGS_GET(group, g, p);
233 return create_generic(group, g, p, p.len);
234 }
235
236 params = diffie_hellman_get_params(group);
237 if (!params)
238 {
239 return NULL;
240 }
241 return create_generic(group, params->generator, params->prime,
242 params->exp_len);
243 }
244
245 #endif