]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / libstrongswan / plugins / openssl / openssl_x_diffie_hellman.c
1 /*
2 * Copyright (C) 2018 Tobias Brunner
3 *
4 * Copyright (C) secunet Security Networks AG
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/evp.h>
18
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)
22
23 #include "openssl_x_diffie_hellman.h"
24 #include "openssl_util.h"
25
26 #include <utils/debug.h>
27
28 typedef struct private_diffie_hellman_t private_diffie_hellman_t;
29
30 /**
31 * Private data
32 */
33 struct private_diffie_hellman_t {
34 /**
35 * Public interface.
36 */
37 diffie_hellman_t public;
38
39 /**
40 * Diffie Hellman group number.
41 */
42 diffie_hellman_group_t group;
43
44 /**
45 * Private (public) key
46 */
47 EVP_PKEY *key;
48
49 /**
50 * Public key provided by peer
51 */
52 EVP_PKEY *pub;
53
54 /**
55 * Shared secret
56 */
57 chunk_t shared_secret;
58 };
59
60 /**
61 * Map a DH group to a key type
62 */
63 static int map_key_type(diffie_hellman_group_t group)
64 {
65 switch (group)
66 {
67 case CURVE_25519:
68 return EVP_PKEY_X25519;
69 case CURVE_448:
70 return EVP_PKEY_X448;
71 default:
72 return 0;
73 }
74 }
75
76 METHOD(diffie_hellman_t, set_other_public_value, bool,
77 private_diffie_hellman_t *this, chunk_t value)
78 {
79 if (!diffie_hellman_verify_value(this->group, value))
80 {
81 return FALSE;
82 }
83
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);
87 if (!this->pub)
88 {
89 DBG1(DBG_LIB, "%N public value is malformed",
90 diffie_hellman_group_names, this->group);
91 return FALSE;
92 }
93 chunk_clear(&this->shared_secret);
94 return TRUE;
95 }
96
97 METHOD(diffie_hellman_t, get_my_public_value, bool,
98 private_diffie_hellman_t *this, chunk_t *value)
99 {
100 size_t len;
101
102 if (!EVP_PKEY_get_raw_public_key(this->key, NULL, &len))
103 {
104 return FALSE;
105 }
106
107 *value = chunk_alloc(len);
108
109 if (!EVP_PKEY_get_raw_public_key(this->key, value->ptr, &value->len))
110 {
111 chunk_free(value);
112 return FALSE;
113 }
114 return TRUE;
115 }
116
117 METHOD(diffie_hellman_t, set_private_value, bool,
118 private_diffie_hellman_t *this, chunk_t value)
119 {
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);
123 if (!this->key)
124 {
125 return FALSE;
126 }
127 return TRUE;
128 }
129
130 METHOD(diffie_hellman_t, get_shared_secret, bool,
131 private_diffie_hellman_t *this, chunk_t *secret)
132 {
133 if (!this->shared_secret.len &&
134 !openssl_compute_shared_key(this->key, this->pub, &this->shared_secret))
135 {
136 DBG1(DBG_LIB, "%N shared secret computation failed",
137 diffie_hellman_group_names, this->group);
138 return FALSE;
139 }
140 *secret = chunk_clone(this->shared_secret);
141 return TRUE;
142 }
143
144 METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
145 private_diffie_hellman_t *this)
146 {
147 return this->group;
148 }
149
150 METHOD(diffie_hellman_t, destroy, void,
151 private_diffie_hellman_t *this)
152 {
153 EVP_PKEY_free(this->key);
154 EVP_PKEY_free(this->pub);
155 chunk_clear(&this->shared_secret);
156 free(this);
157 }
158
159 /*
160 * Described in header
161 */
162 diffie_hellman_t *openssl_x_diffie_hellman_create(diffie_hellman_group_t group)
163 {
164 private_diffie_hellman_t *this;
165 EVP_PKEY_CTX *ctx = NULL;
166 EVP_PKEY *key = NULL;
167
168 switch (group)
169 {
170 case CURVE_25519:
171 ctx = EVP_PKEY_CTX_new_id(NID_X25519, NULL);
172 break;
173 case CURVE_448:
174 ctx = EVP_PKEY_CTX_new_id(NID_X448, NULL);
175 break;
176 default:
177 break;
178 }
179
180 if (!ctx ||
181 EVP_PKEY_keygen_init(ctx) <= 0 ||
182 EVP_PKEY_keygen(ctx, &key) <= 0)
183 {
184 DBG1(DBG_LIB, "generating key for %N failed",
185 diffie_hellman_group_names, group);
186 EVP_PKEY_CTX_free(ctx);
187 return NULL;
188 }
189 EVP_PKEY_CTX_free(ctx);
190
191 INIT(this,
192 .public = {
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,
198 .destroy = _destroy,
199 },
200 .group = group,
201 .key = key,
202 );
203 return &this->public;
204 }
205
206 #endif /* OPENSSL_NO_ECDH */