adding diffie hellman with OpenSSL
[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 * Generator value.
42 */
43 u_int16_t generator;
44 };
45
46 /**
47 * All supported modulus values.
48 */
49 static modulus_entry_t modulus_entries[] = {
50 {MODP_768_BIT, get_rfc2409_prime_768, 2},
51 {MODP_1024_BIT, get_rfc2409_prime_1024, 2},
52 {MODP_1536_BIT, get_rfc3526_prime_1536, 2},
53 {MODP_2048_BIT, get_rfc3526_prime_2048, 2},
54 {MODP_3072_BIT, get_rfc3526_prime_3072, 2},
55 {MODP_4096_BIT, get_rfc3526_prime_4096, 2},
56 {MODP_6144_BIT, get_rfc3526_prime_6144, 2},
57 {MODP_8192_BIT, get_rfc3526_prime_8192, 2},
58 };
59
60 typedef struct private_openssl_diffie_hellman_t private_openssl_diffie_hellman_t;
61
62 /**
63 * Private data of an openssl_diffie_hellman_t object.
64 */
65 struct private_openssl_diffie_hellman_t {
66 /**
67 * Public openssl_diffie_hellman_t interface.
68 */
69 openssl_diffie_hellman_t public;
70
71 /**
72 * Diffie Hellman group number.
73 */
74 u_int16_t group;
75
76 /**
77 * Diffie Hellman object
78 */
79 DH *dh;
80
81 /**
82 * Other public value
83 */
84 BIGNUM *pub_key;
85
86 /**
87 * Shared secret
88 */
89 chunk_t shared_secret;
90
91 /**
92 * True if shared secret is computed
93 */
94 bool computed;
95 };
96
97 /**
98 * Convert a BIGNUM to a chunk
99 */
100 static void bn2chunk(BIGNUM *bn, chunk_t *chunk)
101 {
102 chunk->len = BN_num_bytes(bn);
103 chunk->ptr = malloc(chunk->len);
104 BN_bn2bin(bn, chunk->ptr);
105 }
106
107 /**
108 * Implementation of openssl_diffie_hellman_t.set_other_public_value.
109 */
110 static void set_other_public_value(private_openssl_diffie_hellman_t *this, chunk_t value)
111 {
112 int len;
113 BN_bin2bn(value.ptr, value.len, this->pub_key);
114
115 len = DH_size(this->dh);
116 chunk_free(&this->shared_secret);
117 this->shared_secret = chunk_alloc(len);
118
119 if (DH_compute_key(this->shared_secret.ptr, this->pub_key, this->dh) < 0) {
120 DBG1("DH shared secret computation failed");
121 return;
122 }
123
124 this->computed = TRUE;
125 }
126
127 /**
128 * Implementation of openssl_diffie_hellman_t.get_other_public_value.
129 */
130 static status_t get_other_public_value(private_openssl_diffie_hellman_t *this,
131 chunk_t *value)
132 {
133 if (!this->computed)
134 {
135 return FAILED;
136 }
137 bn2chunk(this->pub_key, value);
138 return SUCCESS;
139 }
140
141 /**
142 * Implementation of openssl_diffie_hellman_t.get_my_public_value.
143 */
144 static void get_my_public_value(private_openssl_diffie_hellman_t *this,chunk_t *value)
145 {
146 bn2chunk(this->dh->pub_key, value);
147 }
148
149 /**
150 * Implementation of openssl_diffie_hellman_t.get_shared_secret.
151 */
152 static status_t get_shared_secret(private_openssl_diffie_hellman_t *this, chunk_t *secret)
153 {
154 if (!this->computed)
155 {
156 return FAILED;
157 }
158 *secret = chunk_clone(this->shared_secret);
159 return SUCCESS;
160 }
161
162 /**
163 * Implementation of openssl_diffie_hellman_t.get_dh_group.
164 */
165 static diffie_hellman_group_t get_dh_group(private_openssl_diffie_hellman_t *this)
166 {
167 return this->group;
168 }
169
170 /**
171 * Lookup the modulus in modulo table
172 */
173 static status_t set_modulus(private_openssl_diffie_hellman_t *this)
174 {
175 int i;
176 for (i = 0; i < (sizeof(modulus_entries) / sizeof(modulus_entry_t)); i++)
177 {
178 if (modulus_entries[i].group == this->group)
179 {
180 this->dh->p = modulus_entries[i].get_prime(NULL);
181 this->dh->g = BN_new();
182 BN_set_word(this->dh->g, modulus_entries[i].generator);
183 return SUCCESS;
184 }
185 }
186 return NOT_FOUND;
187 }
188
189 /**
190 * Implementation of openssl_diffie_hellman_t.destroy.
191 */
192 static void destroy(private_openssl_diffie_hellman_t *this)
193 {
194 BN_clear_free(this->pub_key);
195 DH_free(this->dh);
196 chunk_free(&this->shared_secret);
197 free(this);
198 }
199
200 /*
201 * Described in header.
202 */
203 openssl_diffie_hellman_t *openssl_diffie_hellman_create(diffie_hellman_group_t group)
204 {
205 private_openssl_diffie_hellman_t *this = malloc_thing(private_openssl_diffie_hellman_t);
206
207 this->public.dh.get_shared_secret = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_shared_secret;
208 this->public.dh.set_other_public_value = (void (*)(diffie_hellman_t *, chunk_t )) set_other_public_value;
209 this->public.dh.get_other_public_value = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_other_public_value;
210 this->public.dh.get_my_public_value = (void (*)(diffie_hellman_t *, chunk_t *)) get_my_public_value;
211 this->public.dh.get_dh_group = (diffie_hellman_group_t (*)(diffie_hellman_t *)) get_dh_group;
212 this->public.dh.destroy = (void (*)(diffie_hellman_t *)) destroy;
213
214 this->dh = DH_new();
215 if (!this->dh)
216 {
217 free(this);
218 return NULL;
219 }
220
221 this->group = group;
222 this->computed = FALSE;
223
224 this->pub_key = BN_new();
225 this->shared_secret = chunk_empty;
226
227 /* find a modulus according to group */
228 if (set_modulus(this) != SUCCESS)
229 {
230 destroy(this);
231 return NULL;
232 }
233
234 /* generate my public and private values */
235 if (!DH_generate_key(this->dh))
236 {
237 destroy(this);
238 return NULL;
239 }
240
241 return &this->public;
242 }