a482bc0289540fdd9112883abbd46cbaa391d397
[strongswan.git] / src / libstrongswan / plugins / botan / botan_ec_diffie_hellman.c
1 /*
2 * Copyright (C) 2018 René Korthaus
3 * Rohde & Schwarz Cybersecurity GmbH
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23
24 #include "botan_ec_diffie_hellman.h"
25
26 #include <botan/build.h>
27
28 #ifdef BOTAN_HAS_ECDH
29
30 #include "botan_util.h"
31
32 #include <utils/debug.h>
33
34 #include <botan/ffi.h>
35
36 typedef struct private_botan_ec_diffie_hellman_t private_botan_ec_diffie_hellman_t;
37
38 /**
39 * Private data of a botan_ec_diffie_hellman_t object.
40 */
41 struct private_botan_ec_diffie_hellman_t {
42
43 /**
44 * Public interface
45 */
46 botan_ec_diffie_hellman_t public;
47
48 /**
49 * Diffie Hellman group
50 */
51 diffie_hellman_group_t group;
52
53 /**
54 * EC curve name
55 */
56 const char* curve_name;
57
58 /**
59 * EC private key
60 */
61 botan_privkey_t key;
62
63 /**
64 * Shared secret
65 */
66 chunk_t shared_secret;
67 };
68
69 METHOD(diffie_hellman_t, set_other_public_value, bool,
70 private_botan_ec_diffie_hellman_t *this, chunk_t value)
71 {
72 botan_pk_op_ka_t ka;
73
74 if (!diffie_hellman_verify_value(this->group, value))
75 {
76 return FALSE;
77 }
78
79 if (botan_pk_op_key_agreement_create(&ka, this->key, "Raw", 0))
80 {
81 return FALSE;
82 }
83
84 chunk_clear(&this->shared_secret);
85
86 if (botan_pk_op_key_agreement_size(ka, &this->shared_secret.len))
87 {
88 botan_pk_op_key_agreement_destroy(ka);
89 return FALSE;
90 }
91
92 /* prepend 0x04 to indicate uncompressed point format */
93 value = chunk_cata("cc", chunk_from_chars(0x04), value);
94
95 this->shared_secret = chunk_alloc(this->shared_secret.len);
96 if (botan_pk_op_key_agreement(ka, this->shared_secret.ptr,
97 &this->shared_secret.len, value.ptr,
98 value.len, NULL, 0))
99 {
100 chunk_clear(&this->shared_secret);
101 botan_pk_op_key_agreement_destroy(ka);
102 return FALSE;
103 }
104 botan_pk_op_key_agreement_destroy(ka);
105 return TRUE;
106 }
107
108 METHOD(diffie_hellman_t, get_my_public_value, bool,
109 private_botan_ec_diffie_hellman_t *this, chunk_t *value)
110 {
111 chunk_t pkey = chunk_empty;
112
113 if (botan_pk_op_key_agreement_export_public(this->key, NULL, &pkey.len)
114 != BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
115 {
116 return FALSE;
117 }
118
119 pkey = chunk_alloca(pkey.len);
120 if (botan_pk_op_key_agreement_export_public(this->key, pkey.ptr, &pkey.len))
121 {
122 return FALSE;
123 }
124
125 /* skip 0x04 byte prepended by botan */
126 *value = chunk_clone(chunk_skip(pkey, 1));
127 return TRUE;
128 }
129
130 METHOD(diffie_hellman_t, set_private_value, bool,
131 private_botan_ec_diffie_hellman_t *this, chunk_t value)
132 {
133 botan_mp_t scalar;
134
135 chunk_clear(&this->shared_secret);
136
137 if (!chunk_to_botan_mp(value, &scalar))
138 {
139 return FALSE;
140 }
141
142 if (botan_privkey_destroy(this->key))
143 {
144 botan_mp_destroy(scalar);
145 return FALSE;
146 }
147
148 if (botan_privkey_load_ecdh(&this->key, scalar, this->curve_name))
149 {
150 botan_mp_destroy(scalar);
151 return FALSE;
152 }
153
154 botan_mp_destroy(scalar);
155 return TRUE;
156 }
157
158 METHOD(diffie_hellman_t, get_shared_secret, bool,
159 private_botan_ec_diffie_hellman_t *this, chunk_t *secret)
160 {
161 if (!this->shared_secret.len)
162 {
163 return FALSE;
164 }
165 *secret = chunk_clone(this->shared_secret);
166 return TRUE;
167 }
168
169 METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
170 private_botan_ec_diffie_hellman_t *this)
171 {
172 return this->group;
173 }
174
175 METHOD(diffie_hellman_t, destroy, void,
176 private_botan_ec_diffie_hellman_t *this)
177 {
178 botan_privkey_destroy(this->key);
179 chunk_clear(&this->shared_secret);
180 free(this);
181 }
182
183 /*
184 * Described in header.
185 */
186 botan_ec_diffie_hellman_t *botan_ec_diffie_hellman_create(
187 diffie_hellman_group_t group)
188 {
189 private_botan_ec_diffie_hellman_t *this;
190 botan_rng_t rng;
191
192 INIT(this,
193 .public = {
194 .dh = {
195 .get_shared_secret = _get_shared_secret,
196 .set_other_public_value = _set_other_public_value,
197 .get_my_public_value = _get_my_public_value,
198 .set_private_value = _set_private_value,
199 .get_dh_group = _get_dh_group,
200 .destroy = _destroy,
201 },
202 },
203 .group = group,
204 );
205
206 switch (group)
207 {
208 case ECP_256_BIT:
209 this->curve_name = "secp256r1";
210 break;
211 case ECP_384_BIT:
212 this->curve_name = "secp384r1";
213 break;
214 case ECP_521_BIT:
215 this->curve_name = "secp521r1";
216 break;
217 case ECP_256_BP:
218 this->curve_name = "brainpool256r1";
219 break;
220 case ECP_384_BP:
221 this->curve_name = "brainpool384r1";
222 break;
223 case ECP_512_BP:
224 this->curve_name = "brainpool512r1";
225 break;
226 default:
227 free(this);
228 return NULL;
229 }
230
231 if (botan_rng_init(&rng, "user"))
232 {
233 free(this);
234 return NULL;
235 }
236
237 if (botan_privkey_create_ecdh(&this->key, rng, this->curve_name))
238 {
239 DBG1(DBG_LIB, "ECDH private key generation failed");
240 botan_rng_destroy(rng);
241 free(this);
242 return NULL;
243 }
244
245 botan_rng_destroy(rng);
246 return &this->public;
247 }
248
249 #endif