botan: Simplify DH/ECDH key derivation
[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 if (!diffie_hellman_verify_value(this->group, value))
73 {
74 return FALSE;
75 }
76
77 chunk_clear(&this->shared_secret);
78
79 /* prepend 0x04 to indicate uncompressed point format */
80 value = chunk_cata("cc", chunk_from_chars(0x04), value);
81
82 return botan_dh_key_derivation(this->key, value, &this->shared_secret);
83 }
84
85 METHOD(diffie_hellman_t, get_my_public_value, bool,
86 private_botan_ec_diffie_hellman_t *this, chunk_t *value)
87 {
88 chunk_t pkey = chunk_empty;
89
90 if (botan_pk_op_key_agreement_export_public(this->key, NULL, &pkey.len)
91 != BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
92 {
93 return FALSE;
94 }
95
96 pkey = chunk_alloca(pkey.len);
97 if (botan_pk_op_key_agreement_export_public(this->key, pkey.ptr, &pkey.len))
98 {
99 return FALSE;
100 }
101
102 /* skip 0x04 byte prepended by botan */
103 *value = chunk_clone(chunk_skip(pkey, 1));
104 return TRUE;
105 }
106
107 METHOD(diffie_hellman_t, set_private_value, bool,
108 private_botan_ec_diffie_hellman_t *this, chunk_t value)
109 {
110 botan_mp_t scalar;
111
112 chunk_clear(&this->shared_secret);
113
114 if (!chunk_to_botan_mp(value, &scalar))
115 {
116 return FALSE;
117 }
118
119 if (botan_privkey_destroy(this->key))
120 {
121 botan_mp_destroy(scalar);
122 return FALSE;
123 }
124
125 if (botan_privkey_load_ecdh(&this->key, scalar, this->curve_name))
126 {
127 botan_mp_destroy(scalar);
128 return FALSE;
129 }
130
131 botan_mp_destroy(scalar);
132 return TRUE;
133 }
134
135 METHOD(diffie_hellman_t, get_shared_secret, bool,
136 private_botan_ec_diffie_hellman_t *this, chunk_t *secret)
137 {
138 if (!this->shared_secret.len)
139 {
140 return FALSE;
141 }
142 *secret = chunk_clone(this->shared_secret);
143 return TRUE;
144 }
145
146 METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
147 private_botan_ec_diffie_hellman_t *this)
148 {
149 return this->group;
150 }
151
152 METHOD(diffie_hellman_t, destroy, void,
153 private_botan_ec_diffie_hellman_t *this)
154 {
155 botan_privkey_destroy(this->key);
156 chunk_clear(&this->shared_secret);
157 free(this);
158 }
159
160 /*
161 * Described in header.
162 */
163 botan_ec_diffie_hellman_t *botan_ec_diffie_hellman_create(
164 diffie_hellman_group_t group)
165 {
166 private_botan_ec_diffie_hellman_t *this;
167 botan_rng_t rng;
168
169 INIT(this,
170 .public = {
171 .dh = {
172 .get_shared_secret = _get_shared_secret,
173 .set_other_public_value = _set_other_public_value,
174 .get_my_public_value = _get_my_public_value,
175 .set_private_value = _set_private_value,
176 .get_dh_group = _get_dh_group,
177 .destroy = _destroy,
178 },
179 },
180 .group = group,
181 );
182
183 switch (group)
184 {
185 case ECP_256_BIT:
186 this->curve_name = "secp256r1";
187 break;
188 case ECP_384_BIT:
189 this->curve_name = "secp384r1";
190 break;
191 case ECP_521_BIT:
192 this->curve_name = "secp521r1";
193 break;
194 case ECP_256_BP:
195 this->curve_name = "brainpool256r1";
196 break;
197 case ECP_384_BP:
198 this->curve_name = "brainpool384r1";
199 break;
200 case ECP_512_BP:
201 this->curve_name = "brainpool512r1";
202 break;
203 default:
204 free(this);
205 return NULL;
206 }
207
208 if (botan_rng_init(&rng, "user"))
209 {
210 free(this);
211 return NULL;
212 }
213
214 if (botan_privkey_create_ecdh(&this->key, rng, this->curve_name))
215 {
216 DBG1(DBG_LIB, "ECDH private key generation failed");
217 botan_rng_destroy(rng);
218 free(this);
219 return NULL;
220 }
221
222 botan_rng_destroy(rng);
223 return &this->public;
224 }
225
226 #endif