2 * Copyright (C) 2008 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
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>.
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
18 #include <openssl/dh.h>
20 #include "openssl_diffie_hellman.h"
24 typedef struct modulus_entry_t modulus_entry_t
;
27 * Entry of the modulus list.
29 struct modulus_entry_t
{
31 * Group number as it is defined in file transform_substructure.h.
33 diffie_hellman_group_t group
;
36 * Pointer to the function to get the modulus.
38 BIGNUM
*(*get_prime
)(BIGNUM
*bn
);
41 * Optimum length of exponent in bits.
43 long opt_exponent_len
;
52 * All supported modulus values - optimum exponent size according to RFC 3526.
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},
65 typedef struct private_openssl_diffie_hellman_t private_openssl_diffie_hellman_t
;
68 * Private data of an openssl_diffie_hellman_t object.
70 struct private_openssl_diffie_hellman_t
{
72 * Public openssl_diffie_hellman_t interface.
74 openssl_diffie_hellman_t
public;
77 * Diffie Hellman group number.
82 * Diffie Hellman object
92 * Optimum length of exponent in bits.
94 long opt_exponent_len
;
99 chunk_t shared_secret
;
102 * True if shared secret is computed
108 * Convert a BIGNUM to a chunk
110 static void bn2chunk(BIGNUM
*bn
, chunk_t
*chunk
)
112 chunk
->len
= BN_num_bytes(bn
);
113 chunk
->ptr
= malloc(chunk
->len
);
114 BN_bn2bin(bn
, chunk
->ptr
);
118 * Implementation of openssl_diffie_hellman_t.set_other_public_value.
120 static void set_other_public_value(private_openssl_diffie_hellman_t
*this, chunk_t value
)
123 BN_bin2bn(value
.ptr
, value
.len
, this->pub_key
);
125 len
= DH_size(this->dh
);
126 chunk_free(&this->shared_secret
);
127 this->shared_secret
= chunk_alloc(len
);
129 if (DH_compute_key(this->shared_secret
.ptr
, this->pub_key
, this->dh
) < 0) {
130 DBG1("DH shared secret computation failed");
134 this->computed
= TRUE
;
138 * Implementation of openssl_diffie_hellman_t.get_other_public_value.
140 static status_t
get_other_public_value(private_openssl_diffie_hellman_t
*this,
147 bn2chunk(this->pub_key
, value
);
152 * Implementation of openssl_diffie_hellman_t.get_my_public_value.
154 static void get_my_public_value(private_openssl_diffie_hellman_t
*this,chunk_t
*value
)
156 bn2chunk(this->dh
->pub_key
, value
);
160 * Implementation of openssl_diffie_hellman_t.get_shared_secret.
162 static status_t
get_shared_secret(private_openssl_diffie_hellman_t
*this, chunk_t
*secret
)
168 *secret
= chunk_clone(this->shared_secret
);
173 * Implementation of openssl_diffie_hellman_t.get_dh_group.
175 static diffie_hellman_group_t
get_dh_group(private_openssl_diffie_hellman_t
*this)
181 * Lookup the modulus in modulo table
183 static status_t
set_modulus(private_openssl_diffie_hellman_t
*this)
186 for (i
= 0; i
< (sizeof(modulus_entries
) / sizeof(modulus_entry_t
)); i
++)
188 if (modulus_entries
[i
].group
== this->group
)
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
;
201 * Implementation of openssl_diffie_hellman_t.destroy.
203 static void destroy(private_openssl_diffie_hellman_t
*this)
205 BN_clear_free(this->pub_key
);
207 chunk_free(&this->shared_secret
);
212 * Described in header.
214 openssl_diffie_hellman_t
*openssl_diffie_hellman_create(diffie_hellman_group_t group
)
217 private_openssl_diffie_hellman_t
*this = malloc_thing(private_openssl_diffie_hellman_t
);
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
;
234 this->computed
= FALSE
;
236 this->pub_key
= BN_new();
237 this->shared_secret
= chunk_empty
;
239 /* find a modulus according to group */
240 if (set_modulus(this) != SUCCESS
)
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
;
250 /* generate my public and private values */
251 if (!DH_generate_key(this->dh
))
256 DBG2("size of DH secret exponent: %d bits", BN_num_bits(this->dh
->priv_key
));
258 return &this->public;