2 * Copyright (C) 2018 Tobias Brunner
4 * Copyright (C) secunet Security Networks AG
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>.
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
17 #include <openssl/evp.h>
19 /* basic support for X25519 was added with 1.1.0a, but we require features (e.g.
20 * to load the keys) that were only added with 1.1.1 */
21 #if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(OPENSSL_NO_ECDH)
23 #include "openssl_x_diffie_hellman.h"
24 #include "openssl_util.h"
26 #include <utils/debug.h>
28 typedef struct private_diffie_hellman_t private_diffie_hellman_t
;
33 struct private_diffie_hellman_t
{
37 diffie_hellman_t
public;
40 * Diffie Hellman group number.
42 diffie_hellman_group_t group
;
45 * Private (public) key
50 * Public key provided by peer
57 chunk_t shared_secret
;
61 * Map a DH group to a key type
63 static int map_key_type(diffie_hellman_group_t group
)
68 return EVP_PKEY_X25519
;
76 METHOD(diffie_hellman_t
, set_other_public_value
, bool,
77 private_diffie_hellman_t
*this, chunk_t value
)
79 if (!diffie_hellman_verify_value(this->group
, value
))
84 EVP_PKEY_free(this->pub
);
85 this->pub
= EVP_PKEY_new_raw_public_key(map_key_type(this->group
), NULL
,
86 value
.ptr
, value
.len
);
89 DBG1(DBG_LIB
, "%N public value is malformed",
90 diffie_hellman_group_names
, this->group
);
93 chunk_clear(&this->shared_secret
);
97 METHOD(diffie_hellman_t
, get_my_public_value
, bool,
98 private_diffie_hellman_t
*this, chunk_t
*value
)
102 if (!EVP_PKEY_get_raw_public_key(this->key
, NULL
, &len
))
107 *value
= chunk_alloc(len
);
109 if (!EVP_PKEY_get_raw_public_key(this->key
, value
->ptr
, &value
->len
))
117 METHOD(diffie_hellman_t
, set_private_value
, bool,
118 private_diffie_hellman_t
*this, chunk_t value
)
120 EVP_PKEY_free(this->key
);
121 this->key
= EVP_PKEY_new_raw_private_key(map_key_type(this->group
), NULL
,
122 value
.ptr
, value
.len
);
130 METHOD(diffie_hellman_t
, get_shared_secret
, bool,
131 private_diffie_hellman_t
*this, chunk_t
*secret
)
133 if (!this->shared_secret
.len
&&
134 !openssl_compute_shared_key(this->key
, this->pub
, &this->shared_secret
))
136 DBG1(DBG_LIB
, "%N shared secret computation failed",
137 diffie_hellman_group_names
, this->group
);
140 *secret
= chunk_clone(this->shared_secret
);
144 METHOD(diffie_hellman_t
, get_dh_group
, diffie_hellman_group_t
,
145 private_diffie_hellman_t
*this)
150 METHOD(diffie_hellman_t
, destroy
, void,
151 private_diffie_hellman_t
*this)
153 EVP_PKEY_free(this->key
);
154 EVP_PKEY_free(this->pub
);
155 chunk_clear(&this->shared_secret
);
160 * Described in header
162 diffie_hellman_t
*openssl_x_diffie_hellman_create(diffie_hellman_group_t group
)
164 private_diffie_hellman_t
*this;
165 EVP_PKEY_CTX
*ctx
= NULL
;
166 EVP_PKEY
*key
= NULL
;
171 ctx
= EVP_PKEY_CTX_new_id(NID_X25519
, NULL
);
174 ctx
= EVP_PKEY_CTX_new_id(NID_X448
, NULL
);
181 EVP_PKEY_keygen_init(ctx
) <= 0 ||
182 EVP_PKEY_keygen(ctx
, &key
) <= 0)
184 DBG1(DBG_LIB
, "generating key for %N failed",
185 diffie_hellman_group_names
, group
);
186 EVP_PKEY_CTX_free(ctx
);
189 EVP_PKEY_CTX_free(ctx
);
193 .get_shared_secret
= _get_shared_secret
,
194 .set_other_public_value
= _set_other_public_value
,
195 .get_my_public_value
= _get_my_public_value
,
196 .set_private_value
= _set_private_value
,
197 .get_dh_group
= _get_dh_group
,
203 return &this->public;
206 #endif /* OPENSSL_NO_ECDH */