refining changeset 4483 by introducing charon.dh_exponent_ansi_x9_42 key
[strongswan.git] / src / libstrongswan / plugins / openssl / openssl_diffie_hellman.c
1 /*
2 * Copyright (C) 2008 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #include <openssl/dh.h>
19
20 #include "openssl_diffie_hellman.h"
21
22 #include <debug.h>
23
24 typedef struct modulus_entry_t modulus_entry_t;
25
26 /**
27 * Entry of the modulus list.
28 */
29 struct modulus_entry_t {
30 /**
31 * Group number as it is defined in file transform_substructure.h.
32 */
33 diffie_hellman_group_t group;
34
35 /**
36 * Pointer to the function to get the modulus.
37 */
38 BIGNUM *(*get_prime)(BIGNUM *bn);
39
40 /*
41 * Optimum length of exponent in bits.
42 */
43 long opt_exponent_len;
44
45 /*
46 * Generator value.
47 */
48 u_int16_t generator;
49 };
50
51 /**
52 * All supported modulus values - optimum exponent size according to RFC 3526.
53 */
54 static modulus_entry_t modulus_entries[] = {
55 {MODP_768_BIT, get_rfc2409_prime_768, 256, 2},
56 {MODP_1024_BIT, get_rfc2409_prime_1024, 256, 2},
57 {MODP_1536_BIT, get_rfc3526_prime_1536, 256, 2},
58 {MODP_2048_BIT, get_rfc3526_prime_2048, 384, 2},
59 {MODP_3072_BIT, get_rfc3526_prime_3072, 384, 2},
60 {MODP_4096_BIT, get_rfc3526_prime_4096, 512, 2},
61 {MODP_6144_BIT, get_rfc3526_prime_6144, 512, 2},
62 {MODP_8192_BIT, get_rfc3526_prime_8192, 512, 2},
63 };
64
65 typedef struct private_openssl_diffie_hellman_t private_openssl_diffie_hellman_t;
66
67 /**
68 * Private data of an openssl_diffie_hellman_t object.
69 */
70 struct private_openssl_diffie_hellman_t {
71 /**
72 * Public openssl_diffie_hellman_t interface.
73 */
74 openssl_diffie_hellman_t public;
75
76 /**
77 * Diffie Hellman group number.
78 */
79 u_int16_t group;
80
81 /**
82 * Diffie Hellman object
83 */
84 DH *dh;
85
86 /**
87 * Other public value
88 */
89 BIGNUM *pub_key;
90
91 /*
92 * Optimum length of exponent in bits.
93 */
94 long opt_exponent_len;
95
96 /**
97 * Shared secret
98 */
99 chunk_t shared_secret;
100
101 /**
102 * True if shared secret is computed
103 */
104 bool computed;
105 };
106
107 /**
108 * Convert a BIGNUM to a chunk
109 */
110 static void bn2chunk(BIGNUM *bn, chunk_t *chunk)
111 {
112 chunk->len = BN_num_bytes(bn);
113 chunk->ptr = malloc(chunk->len);
114 BN_bn2bin(bn, chunk->ptr);
115 }
116
117 /**
118 * Implementation of openssl_diffie_hellman_t.set_other_public_value.
119 */
120 static void set_other_public_value(private_openssl_diffie_hellman_t *this, chunk_t value)
121 {
122 int len;
123 BN_bin2bn(value.ptr, value.len, this->pub_key);
124
125 len = DH_size(this->dh);
126 chunk_free(&this->shared_secret);
127 this->shared_secret = chunk_alloc(len);
128
129 if (DH_compute_key(this->shared_secret.ptr, this->pub_key, this->dh) < 0) {
130 DBG1("DH shared secret computation failed");
131 return;
132 }
133
134 this->computed = TRUE;
135 }
136
137 /**
138 * Implementation of openssl_diffie_hellman_t.get_other_public_value.
139 */
140 static status_t get_other_public_value(private_openssl_diffie_hellman_t *this,
141 chunk_t *value)
142 {
143 if (!this->computed)
144 {
145 return FAILED;
146 }
147 bn2chunk(this->pub_key, value);
148 return SUCCESS;
149 }
150
151 /**
152 * Implementation of openssl_diffie_hellman_t.get_my_public_value.
153 */
154 static void get_my_public_value(private_openssl_diffie_hellman_t *this,chunk_t *value)
155 {
156 bn2chunk(this->dh->pub_key, value);
157 }
158
159 /**
160 * Implementation of openssl_diffie_hellman_t.get_shared_secret.
161 */
162 static status_t get_shared_secret(private_openssl_diffie_hellman_t *this, chunk_t *secret)
163 {
164 if (!this->computed)
165 {
166 return FAILED;
167 }
168 *secret = chunk_clone(this->shared_secret);
169 return SUCCESS;
170 }
171
172 /**
173 * Implementation of openssl_diffie_hellman_t.get_dh_group.
174 */
175 static diffie_hellman_group_t get_dh_group(private_openssl_diffie_hellman_t *this)
176 {
177 return this->group;
178 }
179
180 /**
181 * Lookup the modulus in modulo table
182 */
183 static status_t set_modulus(private_openssl_diffie_hellman_t *this)
184 {
185 int i;
186 for (i = 0; i < (sizeof(modulus_entries) / sizeof(modulus_entry_t)); i++)
187 {
188 if (modulus_entries[i].group == this->group)
189 {
190 this->dh->p = modulus_entries[i].get_prime(NULL);
191 this->dh->g = BN_new();
192 BN_set_word(this->dh->g, modulus_entries[i].generator);
193 this->opt_exponent_len = modulus_entries[i].opt_exponent_len;
194 return SUCCESS;
195 }
196 }
197 return NOT_FOUND;
198 }
199
200 /**
201 * Implementation of openssl_diffie_hellman_t.destroy.
202 */
203 static void destroy(private_openssl_diffie_hellman_t *this)
204 {
205 BN_clear_free(this->pub_key);
206 DH_free(this->dh);
207 chunk_free(&this->shared_secret);
208 free(this);
209 }
210
211 /*
212 * Described in header.
213 */
214 openssl_diffie_hellman_t *openssl_diffie_hellman_create(diffie_hellman_group_t group)
215 {
216 bool ansi_x9_42;
217 private_openssl_diffie_hellman_t *this = malloc_thing(private_openssl_diffie_hellman_t);
218
219 this->public.dh.get_shared_secret = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_shared_secret;
220 this->public.dh.set_other_public_value = (void (*)(diffie_hellman_t *, chunk_t )) set_other_public_value;
221 this->public.dh.get_other_public_value = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_other_public_value;
222 this->public.dh.get_my_public_value = (void (*)(diffie_hellman_t *, chunk_t *)) get_my_public_value;
223 this->public.dh.get_dh_group = (diffie_hellman_group_t (*)(diffie_hellman_t *)) get_dh_group;
224 this->public.dh.destroy = (void (*)(diffie_hellman_t *)) destroy;
225
226 this->dh = DH_new();
227 if (!this->dh)
228 {
229 free(this);
230 return NULL;
231 }
232
233 this->group = group;
234 this->computed = FALSE;
235
236 this->pub_key = BN_new();
237 this->shared_secret = chunk_empty;
238
239 /* find a modulus according to group */
240 if (set_modulus(this) != SUCCESS)
241 {
242 destroy(this);
243 return NULL;
244 }
245
246 ansi_x9_42 = lib->settings->get_bool(lib->settings,
247 "charon.dh_exponent_ansi_x9_42", TRUE);
248 this->dh->length = (ansi_x9_42) ? 0 : this->opt_exponent_len;
249
250 /* generate my public and private values */
251 if (!DH_generate_key(this->dh))
252 {
253 destroy(this);
254 return NULL;
255 }
256 DBG2("size of DH secret exponent: %d bits", BN_num_bits(this->dh->priv_key));
257
258 return &this->public;
259 }