OpenVPN 3 Core Library
Loading...
Searching...
No Matches
extpki.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12#pragma once
13
14#include <openssl/rsa.h>
15#include <openssl/evp.h>
16
17#include <openssl/ec.h>
18#include <openssl/ecdsa.h>
19
22
24
25namespace openvpn {
26using ssl_external_pki = SSLFactoryAPI::ssl_external_pki;
27
29{
30 public:
31 ExternalPKIRsaImpl(SSL_CTX *ssl_ctx, ::X509 *cert, ExternalPKIBase *external_pki_arg, const std::string &alias)
32 : external_pki(external_pki_arg), alias(alias), n_errors(0)
33 {
34 RSA *rsa = nullptr;
35 const RSA *pub_rsa = nullptr;
36 RSA_METHOD *rsa_meth = nullptr;
37 const char *errtext = "";
38
39 /* allocate custom RSA method object */
40 rsa_meth = RSA_meth_new("OpenSSLContext::ExternalPKIRsaImpl private key RSA Method",
41 RSA_METHOD_FLAG_NO_CHECK);
42
43 RSA_meth_set_pub_enc(rsa_meth, rsa_pub_enc);
44 RSA_meth_set_pub_dec(rsa_meth, rsa_pub_dec);
45 RSA_meth_set_priv_enc(rsa_meth, rsa_priv_enc);
46 RSA_meth_set_priv_dec(rsa_meth, rsa_priv_dec);
47 RSA_meth_set_init(rsa_meth, nullptr);
48 RSA_meth_set_finish(rsa_meth, rsa_finish);
49 RSA_meth_set0_app_data(rsa_meth, this);
50
51
52 /* get the public key */
53 if (X509_get0_pubkey(cert) == nullptr) /* nullptr before SSL_CTX_use_certificate() is called */
54 {
55 errtext = "pkey is NULL";
56 goto err;
57 }
58
59 if (EVP_PKEY_id(X509_get0_pubkey(cert)) != EVP_PKEY_RSA)
60 {
61 errtext = "pkey is not RSA";
62 goto err;
63 }
64 pub_rsa = EVP_PKEY_get0_RSA(X509_get0_pubkey(cert));
65
66 /* allocate RSA object */
67 rsa = RSA_new();
68 if (rsa == nullptr)
69 {
70 SSLerr(SSL_F_SSL_USE_PRIVATEKEY, ERR_R_MALLOC_FAILURE);
71 errtext = "RSA_new";
72 goto err;
73 }
74
75 /* only set e and n as d (private key) is outside our control */
76 RSA_set0_key(rsa, BN_dup(RSA_get0_n(pub_rsa)), BN_dup(RSA_get0_e(pub_rsa)), nullptr);
77 RSA_set_flags(rsa, RSA_FLAG_EXT_PKEY);
78
79 if (!RSA_set_method(rsa, rsa_meth))
80 {
81 errtext = "RSA_set_method";
82 goto err;
83 }
84 /* rsa_meth will be freed when rsa is freed from this point,
85 * set pointer to nullptr so the err does not try to free it
86 */
87 rsa_meth = nullptr;
88
89 /* bind our custom RSA object to ssl_ctx */
90 if (!SSL_CTX_use_RSAPrivateKey(ssl_ctx, rsa))
91 {
92 errtext = "SSL_CTX_use_RSAPrivateKey";
93 goto err;
94 }
95
96 RSA_free(rsa); /* doesn't necessarily free, just decrements refcount */
97 return;
98
99 err:
100 RSA_free(rsa);
101 RSA_meth_free(rsa_meth);
102
103 OPENVPN_THROW(OpenSSLException, "OpenSSLContext::ExternalPKIRsaImpl: " << errtext);
104 }
105
106 ~ExternalPKIRsaImpl() override = default;
107
108 unsigned int get_n_errors() const
109 {
110 return n_errors;
111 }
112
113 private:
114 /* called at RSA_free */
115 static int rsa_finish(RSA *rsa)
116 {
117 RSA_meth_free(const_cast<RSA_METHOD *>(RSA_get_method(rsa)));
118 return 1;
119 }
120
121 /* sign arbitrary data */
122 static int
123 rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
124 {
125 ExternalPKIRsaImpl *self = (ExternalPKIRsaImpl *)(RSA_meth_get0_app_data(RSA_get_method(rsa)));
126
127 try
128 {
129 if (padding != RSA_PKCS1_PADDING && padding != RSA_NO_PADDING)
130 {
131 RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
132 throw ssl_external_pki("OpenSSL: bad padding type");
133 }
134 std::string padding_algo;
135 if (padding == RSA_PKCS1_PADDING)
136 {
137 padding_algo = "RSA_PKCS1_PADDING";
138 }
139 else if (padding == RSA_NO_PADDING)
140 {
141 padding_algo = "RSA_NO_PADDING";
142 }
143
144 /* convert 'from' to base64 */
145 ConstBuffer from_buf(from, flen, true);
146 const std::string from_b64 = base64->encode(from_buf);
147
148 /* get signature */
149 std::string sig_b64;
150 const bool status = self->external_pki->sign(self->alias, from_b64, sig_b64, padding_algo, "", "");
151 if (!status)
152 throw ssl_external_pki("OpenSSL: could not obtain signature");
153
154 /* decode base64 signature to binary */
155 const int len = RSA_size(rsa);
156 Buffer sig(to, len, false);
157 base64->decode(sig, sig_b64);
158
159 /* verify length */
160 if (sig.size() != static_cast<size_t>(len))
161 throw ssl_external_pki("OpenSSL: incorrect signature length");
162
163 /* return length of signature */
164 return len;
165 }
166 catch (const std::exception &e)
167 {
168 OPENVPN_LOG("OpenSSLContext::ExternalPKIRsaImpl::rsa_priv_enc exception: " << e.what());
169 ++self->n_errors;
170 return -1;
171 }
172 }
173
174 static void not_implemented(RSA *rsa)
175 {
176 ExternalPKIRsaImpl *self = (ExternalPKIRsaImpl *)(RSA_meth_get0_app_data(RSA_get_method(rsa)));
177 ++self->n_errors;
178 }
179
180 /* encrypt */
181 static int
182 rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
183 {
184 not_implemented(rsa);
185 return -1;
186 }
187
188 /* verify arbitrary data */
189 static int
190 rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
191 {
192 not_implemented(rsa);
193 return -1;
194 }
195
196 /* decrypt */
197 static int
198 rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
199 {
200 not_implemented(rsa);
201 return -1;
202 }
203
205 std::string alias;
206 unsigned int n_errors;
207};
208
209/* The OpenSSL EC_* methods we are using here are only available for OpenSSL 1.1.0 and later */
210#if !defined(OPENSSL_NO_EC)
212{
213
214 public:
215 ExternalPKIECImpl(SSL_CTX *ssl_ctx, ::X509 *cert, ExternalPKIBase *external_pki_arg, const std::string &alias)
216 : external_pki(external_pki_arg), alias(alias)
217 {
218
219 if (ec_self_data_index < 0)
220 throw ssl_external_pki("ExternalPKIECImpl::ec_self_data_index is uninitialized");
221
222 std::string errtext;
223
224 EVP_PKEY *privkey = nullptr;
225 EC_KEY *ec = nullptr;
226 EC_KEY_METHOD *ec_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
227
228 /* we only need to override a small number of methods */
229 EC_KEY_METHOD_set_init(ec_method, NULL, ec_finish, NULL, NULL, NULL, NULL);
230 EC_KEY_METHOD_set_sign(ec_method, ecdsa_sign, ecdsa_sign_setup, ecdsa_sign_sig);
231
232 /* get the public key */
233 EVP_PKEY *pubkey = X509_get0_pubkey(cert);
234
235 if (pubkey == nullptr) /* nullptr before SSL_CTX_use_certificate() is called */
236 {
237 errtext = "public key is NULL";
238 goto err;
239 }
240
241 if (EVP_PKEY_id(pubkey) != EVP_PKEY_EC)
242 {
243 errtext = "public key is not EC";
244 goto err;
245 }
246
247 ec = EVP_PKEY_get1_EC_KEY(pubkey);
248
249 if (!ec)
250 {
251 errtext = "cannot get public EC key";
252 goto err;
253 }
254
255 /* This will move responsibility to free ec_method to ec */
256 if (!EC_KEY_set_method(ec, ec_method))
257 {
258 errtext = "Could not set EC method";
259 EC_KEY_METHOD_free(ec_method);
260 goto err;
261 }
262
263 if (!EC_KEY_set_ex_data(ec, ec_self_data_index, this))
264 {
265 errtext = "Could not set EC Key ex data";
266 EC_KEY_METHOD_free(ec_method);
267 goto err;
268 }
269
270 privkey = EVP_PKEY_new();
271 if (!EVP_PKEY_assign_EC_KEY(privkey, ec))
272 {
273 errtext = "assigning EC key methods failed";
274 goto err;
275 }
276
277 if (!SSL_CTX_use_PrivateKey(ssl_ctx, privkey))
278 {
279 errtext = "assigning EC private key to SSL context failed";
280 goto err;
281 }
282
283 EVP_PKEY_free(privkey); /* release ref to privkey and ec */
284
285 return;
286
287 err:
288 if (privkey)
289 {
290 EVP_PKEY_free(privkey);
291 }
292 else
293 {
294 EC_KEY_free(ec);
295 }
296 OPENVPN_THROW(OpenSSLException, "OpenSSLContext::ExternalPKIECImpl: " << errtext);
297 }
298
299 ~ExternalPKIECImpl() override = default;
300
301 static void init_static()
302 {
303 ec_self_data_index = EC_KEY_get_ex_new_index(0, (char *)"ExternalPKIECImpl", nullptr, nullptr, nullptr);
304 }
305
306 private:
307 static void ec_finish(EC_KEY *ec)
308 {
309 EC_KEY_METHOD_free(const_cast<EC_KEY_METHOD *>(EC_KEY_get_method(ec)));
310 }
311
312 /* sign arbitrary data */
313 static int ecdsa_sign(int type,
314 const unsigned char *dgst,
315 int dlen,
316 unsigned char *sig,
317 unsigned int *siglen,
318 const BIGNUM *kinv,
319 const BIGNUM *r,
320 EC_KEY *eckey)
321 {
322 ExternalPKIECImpl *self = (ExternalPKIECImpl *)(EC_KEY_get_ex_data(eckey, ec_self_data_index));
323
324 try
325 {
326 *siglen = ECDSA_size(eckey);
327 self->do_sign(dgst, dlen, sig, *siglen);
328 /* No error */
329 return 1;
330 }
331 catch (const std::exception &e)
332 {
333 OPENVPN_LOG("OpenSSLContext::ExternalPKIECImpl::ecdsa_sign exception: " << e.what());
334 return 0;
335 }
336 }
337
338 static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp)
339 {
340 /* No precomputation, return success */
341 return 1;
342 }
343
344 static ECDSA_SIG *
345 ecdsa_sign_sig(const unsigned char *dgst, int dgstlen, const BIGNUM *kinvp, const BIGNUM *rp, EC_KEY *eckey)
346 {
347 ExternalPKIECImpl *self = (ExternalPKIECImpl *)(EC_KEY_get_ex_data(eckey, ec_self_data_index));
348
349 unsigned len = ECDSA_size(eckey);
350
351 auto sig = new unsigned char[len];
352
353 ECDSA_SIG *ecsig = nullptr;
354 try
355 {
356 unsigned int siglen = len;
357 self->do_sign(dgst, dgstlen, sig, siglen);
358
359 ecsig = d2i_ECDSA_SIG(NULL, (const unsigned char **)&sig, siglen);
360 }
361 catch (const std::exception &e)
362 {
363 OPENVPN_LOG("OpenSSLContext::ExternalPKIECImpl::ecdsa_sign_sig exception: " << e.what());
364 }
365
366 delete[] sig;
367 return ecsig;
368 }
369
379 void do_sign(const unsigned char *dgst, int dlen, unsigned char *sig, unsigned int &siglen)
380 {
381 /* convert 'dgst' to base64 */
382 ConstBuffer dgst_buf(dgst, dlen, true);
383 const std::string dgst_b64 = base64->encode(dgst_buf);
384
385 /* get signature */
386 std::string sig_b64;
387 const bool status = external_pki->sign(alias, dgst_b64, sig_b64, "ECDSA", "", "");
388 if (!status)
389 throw ssl_external_pki("OpenSSL: could not obtain signature");
390
391 /* decode base64 signature to binary */
392 Buffer sigout(sig, siglen, false);
393 base64->decode(sigout, sig_b64);
394
395 siglen = sigout.size();
396 }
397
399 std::string alias;
400 inline static int ec_self_data_index = -1;
401};
402#endif /* !defined(OPENSSL_NO_EC) */
403} // namespace openvpn
std::string encode(const V &data) const
Definition base64.hpp:139
size_t decode(void *data, size_t len, const std::string &str) const
Definition base64.hpp:186
size_t size() const
Returns the size of the buffer in T objects.
Definition buffer.hpp:1225
virtual bool sign(const std::string &alias, const std::string &data, std::string &sig, const std::string &algorithm, const std::string &hashalg, const std::string &saltlen)=0
static int ec_self_data_index
Definition extpki.hpp:400
ExternalPKIBase * external_pki
Definition extpki.hpp:398
static ECDSA_SIG * ecdsa_sign_sig(const unsigned char *dgst, int dgstlen, const BIGNUM *kinvp, const BIGNUM *rp, EC_KEY *eckey)
Definition extpki.hpp:345
static void ec_finish(EC_KEY *ec)
Definition extpki.hpp:307
static void init_static()
Definition extpki.hpp:301
static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp)
Definition extpki.hpp:338
void do_sign(const unsigned char *dgst, int dlen, unsigned char *sig, unsigned int &siglen)
Definition extpki.hpp:379
ExternalPKIECImpl(SSL_CTX *ssl_ctx, ::X509 *cert, ExternalPKIBase *external_pki_arg, const std::string &alias)
Definition extpki.hpp:215
static int ecdsa_sign(int type, const unsigned char *dgst, int dlen, unsigned char *sig, unsigned int *siglen, const BIGNUM *kinv, const BIGNUM *r, EC_KEY *eckey)
Definition extpki.hpp:313
~ExternalPKIECImpl() override=default
~ExternalPKIRsaImpl() override=default
static int rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
Definition extpki.hpp:198
unsigned int get_n_errors() const
Definition extpki.hpp:108
static int rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
Definition extpki.hpp:190
static void not_implemented(RSA *rsa)
Definition extpki.hpp:174
static int rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
Definition extpki.hpp:123
static int rsa_finish(RSA *rsa)
Definition extpki.hpp:115
ExternalPKIRsaImpl(SSL_CTX *ssl_ctx, ::X509 *cert, ExternalPKIBase *external_pki_arg, const std::string &alias)
Definition extpki.hpp:31
static int rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
Definition extpki.hpp:182
ExternalPKIBase * external_pki
Definition extpki.hpp:204
#define OPENVPN_THROW(exc, stuff)
#define OPENVPN_LOG(args)
Support deferred server-side state creation when client connects.
Definition ovpncli.cpp:95
const Base64 * base64
Definition base64.hpp:299
SSLFactoryAPI::ssl_external_pki ssl_external_pki
Definition extpki.hpp:26