0
0
mirror of https://github.com/OpenVPN/openvpn3.git synced 2024-09-20 04:02:15 +02:00

[OSSL 3.0] Implement using a library context for OpenSSL 3.0

This allows use to load non default providers while also not touching
the default library context. THis is necessary to have profile with and
without legacy library for example

Signed-off-by: Arne Schwabe <arne@openvpn.net>
This commit is contained in:
Arne Schwabe 2021-10-11 14:55:59 +02:00 committed by David Sommerseth
parent 9e02183743
commit 708be87c72
No known key found for this signature in database
GPG Key ID: 86CF944C9671FDF2
19 changed files with 249 additions and 130 deletions

View File

@ -753,14 +753,14 @@ namespace openvpn {
// client ProtoContext config
Client::ProtoConfig::Ptr cp(new Client::ProtoConfig());
cp->relay_mode = relay_mode;
cp->dc.set_factory(new CryptoDCSelect<SSLLib::CryptoAPI>(frame, cli_stats, prng));
cp->ssl_factory = cc->new_factory();
cp->relay_mode = relay_mode;
cp->dc.set_factory(new CryptoDCSelect<SSLLib::CryptoAPI>(cp->ssl_factory->libctx(), frame, cli_stats, prng));
cp->dc_deferred = true; // defer data channel setup until after options pull
cp->tls_auth_factory.reset(new CryptoOvpnHMACFactory<SSLLib::CryptoAPI>());
cp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<SSLLib::CryptoAPI>());
cp->tls_crypt_metadata_factory.reset(new CryptoTLSCryptMetadataFactory());
cp->tlsprf_factory.reset(new CryptoTLSPRFFactory<SSLLib::CryptoAPI>());
cp->ssl_factory = cc->new_factory();
cp->load(opt, *proto_context_options, config.default_key_direction, false);
cp->set_xmit_creds(!autologin || pcc.hasEmbeddedPassword() || autologin_sessions);
cp->extra_peer_info = build_peer_info(config, pcc, autologin_sessions);

View File

@ -30,6 +30,7 @@
#include <openvpn/common/exception.hpp>
#include <openvpn/crypto/static_key.hpp>
#include <openvpn/crypto/cryptoalgs.hpp>
#include <openvpn/crypto/definitions.hpp>
namespace openvpn {
template <typename CRYPTO_API>
@ -71,7 +72,7 @@ namespace openvpn {
return in_size + ctx.block_size();
}
void init(const CryptoAlgs::Type cipher, const StaticKey& key, const int mode)
void init(SSLLib::Ctx libctx, const CryptoAlgs::Type cipher, const StaticKey& key, const int mode)
{
const CryptoAlgs::Alg& alg = CryptoAlgs::get(cipher);
@ -84,7 +85,7 @@ namespace openvpn {
throw cipher_internal_error();
// initialize cipher context with cipher type, key, and encrypt/decrypt mode
ctx.init(cipher, key.data(), mode);
ctx.init(libctx, cipher, key.data(), mode);
// save mode in object
mode_ = mode;

View File

@ -51,9 +51,9 @@ namespace openvpn {
* crypto library
*/
template <typename CRYPTO_API>
static inline bool is_algorithm_supported(const CryptoAlgs::Type cipher)
static inline bool is_algorithm_supported(SSLLib::Ctx libctx, const CryptoAlgs::Type cipher)
{
return CRYPTO_API::CipherContextAEAD::is_supported(cipher);
return CRYPTO_API::CipherContextAEAD::is_supported(libctx, cipher);
}
template <typename CRYPTO_API>
@ -161,19 +161,21 @@ namespace openvpn {
public:
typedef CryptoDCInstance Base;
Crypto(const CryptoAlgs::Type cipher_arg,
Crypto(SSLLib::Ctx libctx_arg,
const CryptoAlgs::Type cipher_arg,
const Frame::Ptr& frame_arg,
const SessionStats::Ptr& stats_arg)
: cipher(cipher_arg),
frame(frame_arg),
stats(stats_arg)
stats(stats_arg),
libctx(libctx_arg)
{
}
// Encrypt/Decrypt
// returns true if packet ID is close to wrapping
virtual bool encrypt(BufferAllocated& buf, const PacketID::time_t now, const unsigned char *op32)
bool encrypt(BufferAllocated& buf, const PacketID::time_t now, const unsigned char *op32) override
{
// only process non-null packets
if (buf.size())
@ -216,7 +218,7 @@ namespace openvpn {
return e.pid_send.wrap_warning();
}
virtual Error::Type decrypt(BufferAllocated& buf, const PacketID::time_t now, const unsigned char *op32)
Error::Type decrypt(BufferAllocated& buf, const PacketID::time_t now, const unsigned char *op32) override
{
// only process non-null packets
if (buf.size())
@ -256,26 +258,25 @@ namespace openvpn {
// Initialization
virtual void init_cipher(StaticKey&& encrypt_key,
StaticKey&& decrypt_key)
void init_cipher(StaticKey&& encrypt_key, StaticKey&& decrypt_key) override
{
e.impl.init(cipher, encrypt_key.data(), encrypt_key.size(), CRYPTO_API::CipherContextAEAD::ENCRYPT);
d.impl.init(cipher, decrypt_key.data(), decrypt_key.size(), CRYPTO_API::CipherContextAEAD::DECRYPT);
e.impl.init(libctx, cipher, encrypt_key.data(), encrypt_key.size(), CRYPTO_API::CipherContextAEAD::ENCRYPT);
d.impl.init(libctx, cipher, decrypt_key.data(), decrypt_key.size(), CRYPTO_API::CipherContextAEAD::DECRYPT);
}
virtual void init_hmac(StaticKey&& encrypt_key,
StaticKey&& decrypt_key)
void init_hmac(StaticKey&& encrypt_key,
StaticKey&& decrypt_key) override
{
e.nonce.set_tail(encrypt_key);
d.nonce.set_tail(decrypt_key);
}
virtual void init_pid(const int send_form,
void init_pid(const int send_form,
const int recv_mode,
const int recv_form,
const char *recv_name,
const int recv_unit,
const SessionStats::Ptr& recv_stats_arg)
const SessionStats::Ptr& recv_stats_arg) override
{
e.pid_send.init(send_form);
d.pid_recv.init(recv_mode, recv_form, recv_name, recv_unit, recv_stats_arg);
@ -283,7 +284,7 @@ namespace openvpn {
// Indicate whether or not cipher/digest is defined
virtual unsigned int defined() const
unsigned int defined() const override
{
unsigned int ret = CRYPTO_DEFINED;
@ -294,14 +295,14 @@ namespace openvpn {
return ret;
}
virtual bool consider_compression(const CompressContext& comp_ctx)
bool consider_compression(const CompressContext& comp_ctx) override
{
return true;
}
// Rekeying
virtual void rekey(const typename Base::RekeyType type)
void rekey(const typename Base::RekeyType type) override
{
}
@ -309,6 +310,7 @@ namespace openvpn {
CryptoAlgs::Type cipher;
Frame::Ptr frame;
SessionStats::Ptr stats;
SSLLib::Ctx libctx;
Encrypt e;
Decrypt d;
};
@ -319,24 +321,26 @@ namespace openvpn {
public:
typedef RCPtr<CryptoContext> Ptr;
CryptoContext(const CryptoAlgs::Type cipher_arg,
CryptoContext(SSLLib::Ctx libctx_arg,
const CryptoAlgs::Type cipher_arg,
const CryptoAlgs::KeyDerivation key_method,
const Frame::Ptr& frame_arg,
const SessionStats::Ptr& stats_arg)
: CryptoDCContext(key_method),
cipher(CryptoAlgs::legal_dc_cipher(cipher_arg)),
frame(frame_arg),
stats(stats_arg)
stats(stats_arg),
libctx(libctx_arg)
{
}
virtual CryptoDCInstance::Ptr new_obj(const unsigned int key_id)
CryptoDCInstance::Ptr new_obj(const unsigned int key_id) override
{
return new Crypto<CRYPTO_API>(cipher, frame, stats);
return new Crypto<CRYPTO_API>(libctx, cipher, frame, stats);
}
// cipher/HMAC/key info
virtual Info crypto_info()
Info crypto_info() override
{
Info ret;
ret.cipher_alg = cipher;
@ -347,7 +351,7 @@ namespace openvpn {
// Info for ProtoContext::link_mtu_adjust
virtual size_t encap_overhead() const
size_t encap_overhead() const override
{
return CRYPTO_API::CipherContextAEAD::AUTH_TAG_LEN;
}
@ -356,6 +360,7 @@ namespace openvpn {
CryptoAlgs::Type cipher;
Frame::Ptr frame;
SessionStats::Ptr stats;
SSLLib::Ctx libctx;
};
}
}

View File

@ -28,6 +28,7 @@
#include <openvpn/crypto/decrypt_chm.hpp>
#include <openvpn/crypto/cryptodc.hpp>
#include <openvpn/random/randapi.hpp>
#include <openvpn/ssl/sslapi.hpp>
namespace openvpn {
@ -37,7 +38,9 @@ namespace openvpn {
public:
typedef CryptoDCInstance Base;
CryptoCHM(const CryptoAlgs::Type cipher_arg,
CryptoCHM(
SSLLib::Ctx libctx_arg,
const CryptoAlgs::Type cipher_arg,
const CryptoAlgs::Type digest_arg,
const Frame::Ptr& frame_arg,
const SessionStats::Ptr& stats_arg,
@ -46,7 +49,8 @@ namespace openvpn {
digest(digest_arg),
frame(frame_arg),
stats(stats_arg),
prng(prng_arg)
prng(prng_arg),
libctx(libctx_arg)
{
encrypt_.frame = frame;
decrypt_.frame = frame;
@ -56,52 +60,52 @@ namespace openvpn {
// Encrypt/Decrypt
/* returns true if packet ID is close to wrapping */
virtual bool encrypt(BufferAllocated& buf, const PacketID::time_t now, const unsigned char *op32)
bool encrypt(BufferAllocated& buf, const PacketID::time_t now, const unsigned char *op32) override
{
encrypt_.encrypt(buf, now);
return encrypt_.pid_send.wrap_warning();
}
virtual Error::Type decrypt(BufferAllocated& buf, const PacketID::time_t now, const unsigned char *op32)
Error::Type decrypt(BufferAllocated& buf, const PacketID::time_t now, const unsigned char *op32) override
{
return decrypt_.decrypt(buf, now);
}
// Initialization
virtual void init_cipher(StaticKey&& encrypt_key,
StaticKey&& decrypt_key)
void init_cipher(StaticKey&& encrypt_key,
StaticKey&& decrypt_key) override
{
encrypt_.cipher.init(cipher, encrypt_key, CRYPTO_API::CipherContext::ENCRYPT);
decrypt_.cipher.init(cipher, decrypt_key, CRYPTO_API::CipherContext::DECRYPT);
encrypt_.cipher.init(libctx, cipher, encrypt_key, CRYPTO_API::CipherContext::ENCRYPT);
decrypt_.cipher.init(libctx, cipher, decrypt_key, CRYPTO_API::CipherContext::DECRYPT);
}
virtual void init_hmac(StaticKey&& encrypt_key,
StaticKey&& decrypt_key)
void init_hmac(StaticKey&& encrypt_key,
StaticKey&& decrypt_key) override
{
encrypt_.hmac.init(digest, encrypt_key);
decrypt_.hmac.init(digest, decrypt_key);
}
virtual void init_pid(const int send_form,
void init_pid(const int send_form,
const int recv_mode,
const int recv_form,
const char *recv_name,
const int recv_unit,
const SessionStats::Ptr& recv_stats_arg)
const SessionStats::Ptr& recv_stats_arg) override
{
encrypt_.pid_send.init(send_form);
decrypt_.pid_recv.init(recv_mode, recv_form, recv_name, recv_unit, recv_stats_arg);
}
virtual bool consider_compression(const CompressContext& comp_ctx)
bool consider_compression(const CompressContext& comp_ctx) override
{
return true;
}
// Indicate whether or not cipher/digest is defined
virtual unsigned int defined() const
unsigned int defined() const override
{
unsigned int ret = CRYPTO_DEFINED;
if (CryptoAlgs::defined(cipher))
@ -113,7 +117,7 @@ namespace openvpn {
// Rekeying
virtual void rekey(const typename Base::RekeyType type)
void rekey(const typename Base::RekeyType type) override
{
}
@ -123,8 +127,9 @@ namespace openvpn {
Frame::Ptr frame;
SessionStats::Ptr stats;
RandomAPI::Ptr prng;
SSLLib::Ctx libctx;
EncryptCHM<CRYPTO_API> encrypt_;
EncryptCHM<CRYPTO_API> encrypt_;
DecryptCHM<CRYPTO_API> decrypt_;
};
@ -134,7 +139,9 @@ namespace openvpn {
public:
typedef RCPtr<CryptoContextCHM> Ptr;
CryptoContextCHM(const CryptoAlgs::Type cipher_arg,
CryptoContextCHM(
SSLLib::Ctx libctx_arg,
const CryptoAlgs::Type cipher_arg,
const CryptoAlgs::Type digest_arg,
const CryptoAlgs::KeyDerivation key_method,
const Frame::Ptr& frame_arg,
@ -145,13 +152,14 @@ namespace openvpn {
digest(CryptoAlgs::legal_dc_digest(digest_arg)),
frame(frame_arg),
stats(stats_arg),
prng(prng_arg)
prng(prng_arg),
libctx(libctx_arg)
{
}
virtual CryptoDCInstance::Ptr new_obj(const unsigned int key_id)
{
return new CryptoCHM<CRYPTO_API>(cipher, digest, frame, stats, prng);
return new CryptoCHM<CRYPTO_API>(libctx, cipher, digest, frame, stats, prng);
}
// cipher/HMAC/key info
@ -179,6 +187,7 @@ namespace openvpn {
Frame::Ptr frame;
SessionStats::Ptr stats;
RandomAPI::Ptr prng;
SSLLib::Ctx libctx;
};
}

View File

@ -40,12 +40,14 @@ namespace openvpn {
public:
typedef RCPtr<CryptoDCSelect> Ptr;
CryptoDCSelect(const Frame::Ptr& frame_arg,
CryptoDCSelect(SSLLib::Ctx libctx_arg,
const Frame::Ptr& frame_arg,
const SessionStats::Ptr& stats_arg,
const RandomAPI::Ptr& prng_arg)
: frame(frame_arg),
stats(stats_arg),
prng(prng_arg)
prng(prng_arg),
libctx(libctx_arg)
{
}
@ -55,9 +57,9 @@ namespace openvpn {
{
const CryptoAlgs::Alg& alg = CryptoAlgs::get(cipher);
if (alg.flags() & CryptoAlgs::CBC_HMAC)
return new CryptoContextCHM<CRYPTO_API>(cipher, digest, method, frame, stats, prng);
return new CryptoContextCHM<CRYPTO_API>(libctx, cipher, digest, method, frame, stats, prng);
else if (alg.flags() & CryptoAlgs::AEAD)
return new AEAD::CryptoContext<CRYPTO_API>(cipher, method, frame, stats);
return new AEAD::CryptoContext<CRYPTO_API>(libctx, cipher, method, frame, stats);
else
OPENVPN_THROW(crypto_dc_select, alg.name() << ": only CBC/HMAC and AEAD cipher modes supported");
}
@ -66,6 +68,7 @@ namespace openvpn {
Frame::Ptr frame;
SessionStats::Ptr stats;
RandomAPI::Ptr prng;
SSLLib::Ctx libctx;
};
}

View File

@ -0,0 +1,41 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2021 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#pragma once
#if USE_OPENSSL
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
#endif
/* We need to define this very early and in its own small header file so we
* can ensure that these definition are always available */
namespace openvpn {
namespace SSLLib {
#if defined(USE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x30000000L
using Ctx = OSSL_LIB_CTX *;
#else
using Ctx = void*;
#endif
}
}

View File

@ -52,11 +52,11 @@ namespace openvpn {
TLSCrypt() : mode(CRYPTO_API::CipherContext::MODE_UNDEF) {}
TLSCrypt(const CryptoAlgs::Type digest, const StaticKey& key_hmac,
TLSCrypt(SSLLib::Ctx libctx, const CryptoAlgs::Type digest, const StaticKey& key_hmac,
const CryptoAlgs::Type cipher, const StaticKey& key_crypt,
const int mode)
{
init(digest, key_hmac, cipher, key_crypt, mode);
init(libctx, digest, key_hmac, cipher, key_crypt, mode);
}
bool defined() const { return ctx_hmac.is_initialized() && ctx_crypt.is_initialized(); }
@ -67,9 +67,10 @@ namespace openvpn {
return ctx_hmac.size();
}
void init(const CryptoAlgs::Type digest, const StaticKey& key_hmac,
const CryptoAlgs::Type cipher, const StaticKey& key_crypt,
const int mode_arg)
void init(SSLLib::Ctx libctx, const CryptoAlgs::Type digest,
const StaticKey& key_hmac,
const CryptoAlgs::Type cipher, const StaticKey& key_crypt,
const int mode_arg)
{
const CryptoAlgs::Alg& alg_hmac = CryptoAlgs::get(digest);
@ -81,7 +82,7 @@ namespace openvpn {
ctx_hmac.init(digest, key_hmac.data(), alg_hmac.size());
// initialize Cipher context with cipher, key and mode
ctx_crypt.init(cipher, key_crypt.data(), mode_arg);
ctx_crypt.init(libctx, cipher, key_crypt.data(), mode_arg);
mode = mode_arg;
}
@ -162,7 +163,7 @@ namespace openvpn {
public:
typedef RCPtr<TLSCryptInstance> Ptr;
virtual void init(const StaticKey& key_hmac, const StaticKey& key_crypt) = 0;
virtual void init(SSLLib::Ctx libctx, const StaticKey& key_hmac, const StaticKey& key_crypt) = 0;
virtual size_t output_hmac_size() const = 0;
@ -209,7 +210,7 @@ namespace openvpn {
public:
typedef RCPtr<TLSCryptFactory> Ptr;
virtual TLSCryptContext::Ptr new_obj(const CryptoAlgs::Type digest_type,
virtual TLSCryptContext::Ptr new_obj(SSLLib::Ctx libctx, const CryptoAlgs::Type digest_type,
const CryptoAlgs::Type cipher_type) = 0;
};
@ -219,18 +220,20 @@ namespace openvpn {
class CryptoTLSCryptInstance : public TLSCryptInstance
{
public:
CryptoTLSCryptInstance(const CryptoAlgs::Type digest_arg,
CryptoTLSCryptInstance(SSLLib::Ctx libctx_arg,
const CryptoAlgs::Type digest_arg,
const CryptoAlgs::Type cipher_arg,
int mode_arg)
: digest(digest_arg),
cipher(cipher_arg),
mode(mode_arg)
mode(mode_arg),
libctx(libctx_arg)
{
}
void init(const StaticKey& key_hmac, const StaticKey& key_crypt)
void init(SSLLib::Ctx libctx, const StaticKey& key_hmac, const StaticKey& key_crypt)
{
tls_crypt.init(digest, key_hmac, cipher, key_crypt, mode);
tls_crypt.init(libctx, digest, key_hmac, cipher, key_crypt, mode);
}
size_t output_hmac_size() const
@ -268,16 +271,18 @@ namespace openvpn {
typename CryptoAlgs::Type cipher;
int mode;
TLSCrypt<CRYPTO_API> tls_crypt;
SSLLib::Ctx libctx;
};
template <typename CRYPTO_API>
class CryptoTLSCryptContext : public TLSCryptContext
{
public:
CryptoTLSCryptContext(const CryptoAlgs::Type digest_type,
CryptoTLSCryptContext(SSLLib::Ctx libctx_arg, const CryptoAlgs::Type digest_type,
const CryptoAlgs::Type cipher_type)
: digest(digest_type),
cipher(cipher_type)
cipher(cipher_type),
libctx(libctx_arg)
{
}
@ -293,29 +298,30 @@ namespace openvpn {
virtual TLSCryptInstance::Ptr new_obj_send()
{
return new CryptoTLSCryptInstance<CRYPTO_API>(digest, cipher,
return new CryptoTLSCryptInstance<CRYPTO_API>(libctx, digest, cipher,
CRYPTO_API::CipherContext::ENCRYPT);
}
virtual TLSCryptInstance::Ptr new_obj_recv()
{
return new CryptoTLSCryptInstance<CRYPTO_API>(digest, cipher,
return new CryptoTLSCryptInstance<CRYPTO_API>(libctx, digest, cipher,
CRYPTO_API::CipherContext::DECRYPT);
}
private:
CryptoAlgs::Type digest;
CryptoAlgs::Type cipher;
SSLLib::Ctx libctx;
};
template <typename CRYPTO_API>
class CryptoTLSCryptFactory : public TLSCryptFactory
{
public:
virtual TLSCryptContext::Ptr new_obj(const CryptoAlgs::Type digest_type,
const CryptoAlgs::Type cipher_type)
TLSCryptContext::Ptr new_obj(SSLLib::Ctx libctx, const CryptoAlgs::Type digest_type,
const CryptoAlgs::Type cipher_type) override
{
return new CryptoTLSCryptContext<CRYPTO_API>(digest_type, cipher_type);
return new CryptoTLSCryptContext<CRYPTO_API>(libctx, digest_type, cipher_type);
}
};
}

View File

@ -33,6 +33,7 @@
#include <openvpn/common/exception.hpp>
#include <openvpn/crypto/static_key.hpp>
#include <openvpn/crypto/cryptoalgs.hpp>
#include <openvpn/ssl/sslapi.hpp>
namespace openvpn {
namespace MbedTLSCrypto {
@ -106,7 +107,7 @@ namespace openvpn {
return (cipher_type(alg) != nullptr);
}
void init(const CryptoAlgs::Type alg, const unsigned char *key, const int mode)
void init(SSLLib::Ctx libctx, const CryptoAlgs::Type alg, const unsigned char *key, const int mode)
{
erase();

View File

@ -64,7 +64,7 @@ namespace openvpn {
~CipherContextAEAD() { erase() ; }
void init(const CryptoAlgs::Type alg,
void init(SSLLib::Ctx libctx, const CryptoAlgs::Type alg,
const unsigned char *key,
const unsigned int keysize,
const int mode)
@ -129,7 +129,7 @@ namespace openvpn {
bool is_initialized() const { return initialized; }
static bool is_supported(const CryptoAlgs::Type alg)
static bool is_supported(void *libctx, const CryptoAlgs::Type alg)
{
unsigned int keysize;
return (cipher_type(alg, keysize) != MBEDTLS_CIPHER_NONE);

View File

@ -1131,6 +1131,12 @@ namespace openvpn {
return SSL::Ptr(new SSL(this, nullptr));
}
// Get the library context. This currently does not exist for mbed TLS
virtual SSLLib::Ctx libctx()
{
return nullptr;
}
// like ssl() above but verify hostname against cert CommonName and/or SubjectAltName
virtual SSLAPI::Ptr ssl(const std::string* hostname, const std::string* cache_key)
{

View File

@ -426,5 +426,10 @@ EVP_CIPHER_free(const EVP_CIPHER * cipher)
* a noop */
}
static inline SSL_CTX *
SSL_CTX_new_ex(void *libctx, const char *propq, const SSL_METHOD *meth)
{
return SSL_CTX_new(meth);
}
#define EVP_PKEY_get_bits EVP_PKEY_bits
#endif

View File

@ -77,7 +77,7 @@ namespace openvpn {
~CipherContext() { free_cipher_context() ; }
void init(const CryptoAlgs::Type alg, const unsigned char *key, const int mode)
void init(SSLLib::Ctx libctx, const CryptoAlgs::Type alg, const unsigned char *key, const int mode)
{
// check that mode is valid
if (!(mode == ENCRYPT || mode == DECRYPT))
@ -85,7 +85,8 @@ namespace openvpn {
free_cipher_context();
ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_reset (ctx);
CIPHER_unique_ptr cipher(cipher_type(alg), EVP_CIPHER_free);
CIPHER_unique_ptr cipher(cipher_type(libctx, alg), EVP_CIPHER_free);
if (!cipher)
OPENVPN_THROW(openssl_cipher_error, CryptoAlgs::name(alg) << ": not usable");
@ -163,24 +164,24 @@ namespace openvpn {
}
private:
static evp_cipher_type *cipher_type(const CryptoAlgs::Type alg)
static evp_cipher_type *cipher_type(SSLLib::Ctx libctx, const CryptoAlgs::Type alg)
{
switch (alg)
{
case CryptoAlgs::AES_128_CBC:
return EVP_CIPHER_fetch(nullptr, "AES-128-CBC", nullptr);
return EVP_CIPHER_fetch(libctx, "AES-128-CBC", nullptr);
case CryptoAlgs::AES_192_CBC:
return EVP_CIPHER_fetch(nullptr, "AES-192-CBC", nullptr);
return EVP_CIPHER_fetch(libctx, "AES-192-CBC", nullptr);
case CryptoAlgs::AES_256_CBC:
return EVP_CIPHER_fetch(nullptr, "AES-256-CBC", nullptr);
return EVP_CIPHER_fetch(libctx, "AES-256-CBC", nullptr);
case CryptoAlgs::AES_256_CTR:
return EVP_CIPHER_fetch(nullptr, "AES-256-CTR", nullptr);
return EVP_CIPHER_fetch(libctx, "AES-256-CTR", nullptr);
case CryptoAlgs::DES_CBC:
return EVP_CIPHER_fetch(nullptr, "DES-CBC", nullptr);
return EVP_CIPHER_fetch(libctx, "DES-CBC", nullptr);
case CryptoAlgs::DES_EDE3_CBC:
return EVP_CIPHER_fetch(nullptr, "DES-EDE-CBC", nullptr);
return EVP_CIPHER_fetch(libctx, "DES-EDE-CBC", nullptr);
case CryptoAlgs::BF_CBC:
return EVP_CIPHER_fetch(nullptr, "BF-CBC", nullptr);
return EVP_CIPHER_fetch(libctx, "BF-CBC", nullptr);
default:
return nullptr;
}

View File

@ -73,15 +73,15 @@ namespace openvpn {
~CipherContextAEAD() { free_cipher_context(); }
void init(const CryptoAlgs::Type alg,
void init(SSLLib::Ctx libctx,
const CryptoAlgs::Type alg,
const unsigned char *key,
const unsigned int keysize,
const int mode)
{
free_cipher_context();
unsigned int ckeysz = 0;
CIPHER_unique_ptr ciph(cipher_type(alg, ckeysz), EVP_CIPHER_free);
CIPHER_unique_ptr ciph(cipher_type(libctx, alg, ckeysz), EVP_CIPHER_free);
if (!ciph)
OPENVPN_THROW(openssl_gcm_error, CryptoAlgs::name(alg) << ": not usable");
@ -212,32 +212,32 @@ namespace openvpn {
bool is_initialized() const { return ctx != nullptr; }
static bool is_supported(const CryptoAlgs::Type alg)
static bool is_supported(SSLLib::Ctx libctx, const CryptoAlgs::Type alg)
{
unsigned int keysize = 0;
CIPHER_unique_ptr cipher(cipher_type(alg, keysize), EVP_CIPHER_free);
CIPHER_unique_ptr cipher(cipher_type(libctx, alg, keysize), EVP_CIPHER_free);
return (bool)cipher;
}
private:
static evp_cipher_type *cipher_type(const CryptoAlgs::Type alg,
static evp_cipher_type *cipher_type(SSLLib::Ctx libctx, const CryptoAlgs::Type alg,
unsigned int& keysize)
{
switch (alg)
{
case CryptoAlgs::AES_128_GCM:
keysize = 16;
return EVP_CIPHER_fetch(nullptr, "AES-128-GCM", nullptr);
return EVP_CIPHER_fetch(libctx, "AES-128-GCM", nullptr);
case CryptoAlgs::AES_192_GCM:
keysize = 24;
return EVP_CIPHER_fetch(nullptr, "AES-192-GCM", nullptr);
return EVP_CIPHER_fetch(libctx, "AES-192-GCM", nullptr);
case CryptoAlgs::AES_256_GCM:
keysize = 32;
return EVP_CIPHER_fetch(nullptr, "AES-256-GCM", nullptr);
return EVP_CIPHER_fetch(libctx, "AES-256-GCM", nullptr);
case CryptoAlgs::CHACHA20_POLY1305:
keysize = 32;
return EVP_CIPHER_fetch(nullptr, "CHACHA20-POLY1305", nullptr);
return EVP_CIPHER_fetch(libctx, "CHACHA20-POLY1305", nullptr);
default:
keysize = 0;
return nullptr;

View File

@ -31,6 +31,7 @@
#include <sstream>
#include <utility>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/x509v3.h>
#include <openssl/rsa.h>
@ -988,17 +989,14 @@ namespace openvpn {
if (ct_out)
BIO_free(ct_out);
}
if (ssl_bio)
BIO_free_all(ssl_bio);
if (ssl)
BIO_free_all(ssl_bio);
if (sess_cache_key)
{
if (sess_cache_key)
{
SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
sess_cache_key->commit(SSL_get1_session(ssl));
}
SSL_free(ssl);
SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
sess_cache_key->commit(SSL_get1_session(ssl));
}
SSL_free(ssl);
openssl_clear_error_stack();
ssl_clear();
}
@ -1115,17 +1113,29 @@ namespace openvpn {
#endif
}
void initalise_lib_context()
{
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
lib_ctx = OSSL_LIB_CTX_new();
if (!lib_ctx) {
throw OpenSSLException("OpenSSLContext: OSSL_LIB_CTX_new failed");
}
#endif
}
OpenSSLContext(Config* config_arg)
: config(config_arg)
{
try
{
// Initialise our library context for OpenSSL 3.0
initalise_lib_context();
// Create new SSL_CTX for server or client mode
if (config->mode.is_server())
{
ctx = SSL_CTX_new(SSL::tls_method_server());
ctx = SSL_CTX_new_ex(lib_ctx, nullptr, SSL::tls_method_server());
if (ctx == nullptr)
throw OpenSSLException("OpenSSLContext: SSL_CTX_new failed for server method");
throw OpenSSLException("OpenSSLContext: SSL_CTX_new_ex failed for server method");
// Set DH object
if (!config->dh.defined())
@ -1153,9 +1163,9 @@ namespace openvpn {
}
else if (config->mode.is_client())
{
ctx = SSL_CTX_new(SSL::tls_method_client());
ctx = SSL_CTX_new_ex(lib_ctx, nullptr, SSL::tls_method_client());
if (ctx == nullptr)
throw OpenSSLException("OpenSSLContext: SSL_CTX_new failed for client method");
throw OpenSSLException("OpenSSLContext: SSL_CTX_new_ex failed for client method");
}
else
OPENVPN_THROW(ssl_context_error, "OpenSSLContext: unknown config->mode");
@ -1394,7 +1404,18 @@ namespace openvpn {
return SSL::Ptr(new SSL(*this, hostname, cache_key));
}
void update_trust(const CertCRLList& cc)
virtual SSLLib::Ctx libctx()
{
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
if (!lib_ctx)
throw OpenSSLException("OpenSSLContext: library context is not initialised");
#endif
return lib_ctx;
}
void update_trust(const CertCRLList& cc)
{
OpenSSLPKI::X509Store store(cc);
SSL_CTX_set_cert_store(ctx, store.release());
@ -2184,14 +2205,19 @@ namespace openvpn {
delete epki;
epki = nullptr;
}
if (ctx)
{
SSL_CTX_free(ctx);
ctx = nullptr;
}
SSL_CTX_free(ctx);
ctx = nullptr;
#if OPENSSL_VERSION_NUMBER > 0x30000000L
OSSL_LIB_CTX_free(lib_ctx);
#endif
lib_ctx = nullptr;
}
Config::Ptr config;
/* OpenSSL library context, used to load non-default providers etc */
SSLLib::Ctx lib_ctx;
SSL_CTX* ctx = nullptr;
ExternalPKIImpl* epki = nullptr;
OpenSSLSessionCache::Ptr sess_cache; // client-side only

View File

@ -51,7 +51,7 @@ namespace openvpn {
init_error("OpenSSL");
}
explicit OpenSSLException(const std::string& error_text)
explicit OpenSSLException(const std::string& error_text) noexcept
{
ssl_err = -1;
init_error(error_text.c_str());

View File

@ -765,7 +765,10 @@ namespace openvpn {
void set_tls_crypt_algs(const CryptoAlgs::Type digest,
const CryptoAlgs::Type cipher)
{
tls_crypt_context = tls_crypt_factory->new_obj(digest, cipher);
/* TODO: we currently use the default SSL library context here as the
* library context is not available this early. This should not matter
* for the algorithms used by tls_crypt */
tls_crypt_context = tls_crypt_factory->new_obj(nullptr, digest, cipher);
}
void set_xmit_creds(const bool xmit_creds_arg)
@ -874,11 +877,12 @@ namespace openvpn {
*
*/
out << "IV_CIPHERS=";
CryptoAlgs::for_each([&out](CryptoAlgs::Type type, const CryptoAlgs::Alg& alg) -> bool {
auto libctx=ssl_factory->libctx();
CryptoAlgs::for_each([&out,libctx](CryptoAlgs::Type type, const CryptoAlgs::Alg& alg) -> bool {
if (!CryptoAlgs::defined(type) || !alg.dc_cipher())
return false;
if (type == CryptoAlgs::CHACHA20_POLY1305 &&
!AEAD::is_algorithm_supported<SSLLib::CryptoAPI>(CryptoAlgs::CHACHA20_POLY1305))
!AEAD::is_algorithm_supported<SSLLib::CryptoAPI>(libctx, CryptoAlgs::CHACHA20_POLY1305))
return false;
out << alg.name() << ':';
return true;
@ -1835,7 +1839,8 @@ namespace openvpn {
crypto_flags = crypto->defined();
if (crypto_flags & CryptoDCInstance::CIPHER_DEFINED)
crypto->init_cipher(key.slice(OpenVPNStaticKey::CIPHER | OpenVPNStaticKey::ENCRYPT | key_dir),
crypto->init_cipher(
key.slice(OpenVPNStaticKey::CIPHER | OpenVPNStaticKey::ENCRYPT | key_dir),
key.slice(OpenVPNStaticKey::CIPHER | OpenVPNStaticKey::DECRYPT | key_dir));
if (crypto_flags & CryptoDCInstance::HMAC_DEFINED)
@ -3057,8 +3062,9 @@ namespace openvpn {
// static direction assignment - not user configurable
const unsigned int key_dir = server ? OpenVPNStaticKey::NORMAL : OpenVPNStaticKey::INVERSE;
tls_crypt_recv->init(c.tls_key.slice(OpenVPNStaticKey::HMAC | OpenVPNStaticKey::DECRYPT | key_dir),
c.tls_key.slice(OpenVPNStaticKey::CIPHER | OpenVPNStaticKey::DECRYPT | key_dir));
tls_crypt_recv->init(c.ssl_factory->libctx(),
c.tls_key.slice(OpenVPNStaticKey::HMAC | OpenVPNStaticKey::DECRYPT | key_dir),
c.tls_key.slice(OpenVPNStaticKey::CIPHER | OpenVPNStaticKey::DECRYPT | key_dir));
// needed to create the decrypt buffer during validation
frame = c.frame;
@ -3193,14 +3199,16 @@ namespace openvpn {
OpenVPNStaticKey::NORMAL :
OpenVPNStaticKey::INVERSE;
tls_crypt_send->init(key.slice(OpenVPNStaticKey::HMAC |
OpenVPNStaticKey::ENCRYPT | key_dir),
key.slice(OpenVPNStaticKey::CIPHER |
OpenVPNStaticKey::ENCRYPT | key_dir));
tls_crypt_recv->init(key.slice(OpenVPNStaticKey::HMAC |
OpenVPNStaticKey::DECRYPT | key_dir),
key.slice(OpenVPNStaticKey::CIPHER |
OpenVPNStaticKey::DECRYPT | key_dir));
tls_crypt_send->init(c.ssl_factory->libctx(),
key.slice(OpenVPNStaticKey::HMAC |
OpenVPNStaticKey::ENCRYPT | key_dir),
key.slice(OpenVPNStaticKey::CIPHER |
OpenVPNStaticKey::ENCRYPT | key_dir));
tls_crypt_recv->init(c.ssl_factory->libctx(),
key.slice(OpenVPNStaticKey::HMAC |
OpenVPNStaticKey::DECRYPT | key_dir),
key.slice(OpenVPNStaticKey::CIPHER |
OpenVPNStaticKey::DECRYPT | key_dir));
}
void reset_tls_crypt_server(const Config& c)
@ -3214,7 +3222,8 @@ namespace openvpn {
//the server key is composed by one key set only, therefore direction and
//mode should not be specified when slicing
tls_crypt_server->init(c.tls_key.slice(OpenVPNStaticKey::HMAC),
tls_crypt_server->init(c.ssl_factory->libctx(),
c.tls_key.slice(OpenVPNStaticKey::HMAC),
c.tls_key.slice(OpenVPNStaticKey::CIPHER));
tls_crypt_metadata = c.tls_crypt_metadata_factory->new_obj();

View File

@ -36,6 +36,7 @@
#include <openvpn/buffer/buffer.hpp>
#include <openvpn/frame/frame.hpp>
#include <openvpn/auth/authcert.hpp>
#include <openvpn/crypto/definitions.hpp>
#include <openvpn/pki/epkibase.hpp>
#include <openvpn/pki/pktype.hpp>
#include <openvpn/ssl/kuparse.hpp>
@ -98,6 +99,9 @@ namespace openvpn {
// create a new SSLAPI instance
virtual SSLAPI::Ptr ssl() = 0;
// get the library context that is used with this SSLAPI instance
virtual SSLLib::Ctx libctx() = 0;
// like ssl() above but optionally verify hostname against cert CommonName and/or
// SubjectAltName, and optionally set/lookup a cache key for this session.
virtual SSLAPI::Ptr ssl(const std::string* hostname, const std::string* cache_key) = 0;

View File

@ -22,6 +22,8 @@
#ifndef OPENVPN_SSL_SSLCHOOSE_H
#define OPENVPN_SSL_SSLCHOOSE_H
#include <openvpn/crypto/definitions.hpp>
#ifdef USE_OPENSSL
#include <openvpn/openssl/crypto/api.hpp>
#include <openvpn/openssl/ssl/sslctx.hpp>

View File

@ -893,7 +893,7 @@ int test(const int thread_num)
typedef ProtoContext ClientProtoContext;
ClientProtoContext::Config::Ptr cp(new ClientProtoContext::Config);
cp->ssl_factory = cc->new_factory();
cp->dc.set_factory(new CryptoDCSelect<ClientCryptoAPI>(frame, cli_stats, prng_cli));
cp->dc.set_factory(new CryptoDCSelect<ClientCryptoAPI>(cp->ssl_factory->libctx(), frame, cli_stats, prng_cli));
cp->tlsprf_factory.reset(new CryptoTLSPRFFactory<ClientCryptoAPI>());
cp->frame = frame;
cp->now = &time;
@ -980,7 +980,7 @@ int test(const int thread_num)
typedef ProtoContext ServerProtoContext;
ServerProtoContext::Config::Ptr sp(new ServerProtoContext::Config);
sp->ssl_factory = sc->new_factory();
sp->dc.set_factory(new CryptoDCSelect<ServerCryptoAPI>(frame, serv_stats, prng_serv));
sp->dc.set_factory(new CryptoDCSelect<ServerCryptoAPI>(sp->ssl_factory->libctx(), frame, serv_stats, prng_serv));
sp->tlsprf_factory.reset(new CryptoTLSPRFFactory<ServerCryptoAPI>());
sp->frame = frame;
sp->now = &time;