openssl: Explicitly include openssl/bn.h
[strongswan.git] / src / libstrongswan / plugins / openssl / openssl_diffie_hellman.c
1 /*
2 * Copyright (C) 2008-2010 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include <openssl/opensslconf.h>
18
19 #ifndef OPENSSL_NO_DH
20
21 #include <openssl/bn.h>
22 #include <openssl/dh.h>
23
24 #include "openssl_diffie_hellman.h"
25
26 #include <utils/debug.h>
27
28 typedef struct private_openssl_diffie_hellman_t private_openssl_diffie_hellman_t;
29
30 /**
31 * Private data of an openssl_diffie_hellman_t object.
32 */
33 struct private_openssl_diffie_hellman_t {
34 /**
35 * Public openssl_diffie_hellman_t interface.
36 */
37 openssl_diffie_hellman_t public;
38
39 /**
40 * Diffie Hellman group number.
41 */
42 diffie_hellman_group_t group;
43
44 /**
45 * Diffie Hellman object
46 */
47 DH *dh;
48
49 /**
50 * Other public value
51 */
52 BIGNUM *pub_key;
53
54 /**
55 * Shared secret
56 */
57 chunk_t shared_secret;
58
59 /**
60 * True if shared secret is computed
61 */
62 bool computed;
63 };
64
65 METHOD(diffie_hellman_t, get_my_public_value, bool,
66 private_openssl_diffie_hellman_t *this, chunk_t *value)
67 {
68 *value = chunk_alloc(DH_size(this->dh));
69 memset(value->ptr, 0, value->len);
70 BN_bn2bin(this->dh->pub_key,
71 value->ptr + value->len - BN_num_bytes(this->dh->pub_key));
72 return TRUE;
73 }
74
75 METHOD(diffie_hellman_t, get_shared_secret, bool,
76 private_openssl_diffie_hellman_t *this, chunk_t *secret)
77 {
78 if (!this->computed)
79 {
80 return FALSE;
81 }
82 /* shared secret should requires a len according the DH group */
83 *secret = chunk_alloc(DH_size(this->dh));
84 memset(secret->ptr, 0, secret->len);
85 memcpy(secret->ptr + secret->len - this->shared_secret.len,
86 this->shared_secret.ptr, this->shared_secret.len);
87 return TRUE;
88 }
89
90
91 METHOD(diffie_hellman_t, set_other_public_value, bool,
92 private_openssl_diffie_hellman_t *this, chunk_t value)
93 {
94 int len;
95
96 if (!diffie_hellman_verify_value(this->group, value))
97 {
98 return FALSE;
99 }
100
101 BN_bin2bn(value.ptr, value.len, this->pub_key);
102 chunk_clear(&this->shared_secret);
103 this->shared_secret.ptr = malloc(DH_size(this->dh));
104 memset(this->shared_secret.ptr, 0xFF, this->shared_secret.len);
105 len = DH_compute_key(this->shared_secret.ptr, this->pub_key, this->dh);
106 if (len < 0)
107 {
108 DBG1(DBG_LIB, "DH shared secret computation failed");
109 return FALSE;
110 }
111 this->shared_secret.len = len;
112 this->computed = TRUE;
113 return TRUE;
114 }
115
116 METHOD(diffie_hellman_t, set_private_value, bool,
117 private_openssl_diffie_hellman_t *this, chunk_t value)
118 {
119 if (BN_bin2bn(value.ptr, value.len, this->dh->priv_key))
120 {
121 chunk_clear(&this->shared_secret);
122 this->computed = FALSE;
123 return DH_generate_key(this->dh);
124 }
125 return FALSE;
126 }
127
128 METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
129 private_openssl_diffie_hellman_t *this)
130 {
131 return this->group;
132 }
133
134 /**
135 * Lookup the modulus in modulo table
136 */
137 static status_t set_modulus(private_openssl_diffie_hellman_t *this)
138 {
139 diffie_hellman_params_t *params = diffie_hellman_get_params(this->group);
140 if (!params)
141 {
142 return NOT_FOUND;
143 }
144 this->dh->p = BN_bin2bn(params->prime.ptr, params->prime.len, NULL);
145 this->dh->g = BN_bin2bn(params->generator.ptr, params->generator.len, NULL);
146 if (params->exp_len != params->prime.len)
147 {
148 this->dh->length = params->exp_len * 8;
149 }
150 return SUCCESS;
151 }
152
153 METHOD(diffie_hellman_t, destroy, void,
154 private_openssl_diffie_hellman_t *this)
155 {
156 BN_clear_free(this->pub_key);
157 DH_free(this->dh);
158 chunk_clear(&this->shared_secret);
159 free(this);
160 }
161
162 /*
163 * Described in header.
164 */
165 openssl_diffie_hellman_t *openssl_diffie_hellman_create(
166 diffie_hellman_group_t group, chunk_t g, chunk_t p)
167 {
168 private_openssl_diffie_hellman_t *this;
169
170 INIT(this,
171 .public = {
172 .dh = {
173 .get_shared_secret = _get_shared_secret,
174 .set_other_public_value = _set_other_public_value,
175 .get_my_public_value = _get_my_public_value,
176 .set_private_value = _set_private_value,
177 .get_dh_group = _get_dh_group,
178 .destroy = _destroy,
179 },
180 },
181 );
182
183 this->dh = DH_new();
184 if (!this->dh)
185 {
186 free(this);
187 return NULL;
188 }
189
190 this->group = group;
191 this->computed = FALSE;
192 this->pub_key = BN_new();
193 this->shared_secret = chunk_empty;
194
195 if (group == MODP_CUSTOM)
196 {
197 this->dh->p = BN_bin2bn(p.ptr, p.len, NULL);
198 this->dh->g = BN_bin2bn(g.ptr, g.len, NULL);
199 }
200 else
201 {
202 /* find a modulus according to group */
203 if (set_modulus(this) != SUCCESS)
204 {
205 destroy(this);
206 return NULL;
207 }
208 }
209
210 /* generate my public and private values */
211 if (!DH_generate_key(this->dh))
212 {
213 destroy(this);
214 return NULL;
215 }
216 DBG2(DBG_LIB, "size of DH secret exponent: %d bits",
217 BN_num_bits(this->dh->priv_key));
218
219 return &this->public;
220 }
221
222 #endif /* OPENSSL_NO_DH */