mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
Core/SSL: Support more certificate formats
This commit is contained in:
@@ -21,7 +21,6 @@
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
#include <openssl/provider.h>
|
||||
OSSL_PROVIDER* LegacyProvider;
|
||||
OSSL_PROVIDER* DefaultProvider;
|
||||
#endif
|
||||
|
||||
void OpenSSLCrypto::threadsSetup([[maybe_unused]] boost::filesystem::path const& providerModulePath)
|
||||
@@ -34,8 +33,7 @@ void OpenSSLCrypto::threadsSetup([[maybe_unused]] boost::filesystem::path const&
|
||||
#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
|
||||
OSSL_PROVIDER_set_default_search_path(nullptr, providerModulePath.string().c_str());
|
||||
#endif
|
||||
LegacyProvider = OSSL_PROVIDER_load(nullptr, "legacy");
|
||||
DefaultProvider = OSSL_PROVIDER_load(nullptr, "default");
|
||||
LegacyProvider = OSSL_PROVIDER_try_load(nullptr, "legacy", 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -43,7 +41,6 @@ void OpenSSLCrypto::threadsCleanup()
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
OSSL_PROVIDER_unload(LegacyProvider);
|
||||
OSSL_PROVIDER_unload(DefaultProvider);
|
||||
OSSL_PROVIDER_set_default_search_path(nullptr, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -140,8 +140,7 @@ private:
|
||||
{
|
||||
_lib = OSSL_LIB_CTX_new();
|
||||
OSSL_PROVIDER_add_builtin(_lib, "trinity-rsa-hmac-sha256", &InitProvider);
|
||||
_handle = OSSL_PROVIDER_load(_lib, "trinity-rsa-hmac-sha256");
|
||||
OSSL_PROVIDER_load(_lib, "default");
|
||||
_handle = OSSL_PROVIDER_try_load(_lib, "trinity-rsa-hmac-sha256", 1);
|
||||
}
|
||||
|
||||
~HMAC_SHA256_MD()
|
||||
|
||||
@@ -18,11 +18,47 @@
|
||||
#include "SslContext.h"
|
||||
#include "Config.h"
|
||||
#include "Log.h"
|
||||
#include "Memory.h"
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <openssl/store.h>
|
||||
#include <openssl/ui.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
auto CreatePasswordUiMethodFromPemCallback(::pem_password_cb* callback)
|
||||
{
|
||||
return Trinity::make_unique_ptr_with_deleter(UI_UTIL_wrap_read_pem_callback(callback, 0), ::UI_destroy_method);
|
||||
}
|
||||
|
||||
auto OpenOpenSSLStore(boost::filesystem::path const& storePath, UI_METHOD const* passwordCallback, void* passwordCallbackData)
|
||||
{
|
||||
std::string uri;
|
||||
uri.reserve(6 + storePath.size());
|
||||
|
||||
uri += "file:";
|
||||
std::string genericPath = storePath.generic_string();
|
||||
if (!genericPath.empty() && !genericPath.starts_with('/'))
|
||||
uri += '/'; // ensure the path starts with / (windows special case, unix absolute paths already do)
|
||||
|
||||
uri += genericPath;
|
||||
|
||||
return Trinity::make_unique_ptr_with_deleter(OSSL_STORE_open(uri.c_str(), passwordCallback, passwordCallbackData, nullptr, nullptr), ::OSSL_STORE_close);
|
||||
}
|
||||
|
||||
boost::system::error_code GetLastOpenSSLError()
|
||||
{
|
||||
auto ossl_error = ::ERR_get_error();
|
||||
if (ERR_SYSTEM_ERROR(ossl_error))
|
||||
return boost::system::error_code(static_cast<int>(::ERR_GET_REASON(ossl_error)), boost::asio::error::get_system_category());
|
||||
|
||||
return boost::system::error_code(static_cast<int>(ossl_error), boost::asio::error::get_ssl_category());
|
||||
}
|
||||
}
|
||||
|
||||
bool Battlenet::SslContext::Initialize()
|
||||
{
|
||||
boost::system::error_code err;
|
||||
|
||||
#define LOAD_CHECK(fn) do { fn; \
|
||||
if (err) \
|
||||
{ \
|
||||
@@ -31,7 +67,6 @@ bool Battlenet::SslContext::Initialize()
|
||||
} } while (0)
|
||||
|
||||
std::string certificateChainFile = sConfigMgr->GetStringDefault("CertificatesFile", "./bnetserver.cert.pem");
|
||||
std::string privateKeyFile = sConfigMgr->GetStringDefault("PrivateKeyFile", "./bnetserver.key.pem");
|
||||
|
||||
auto passwordCallback = [](std::size_t /*max_length*/, boost::asio::ssl::context::password_purpose /*purpose*/) -> std::string
|
||||
{
|
||||
@@ -39,8 +74,54 @@ bool Battlenet::SslContext::Initialize()
|
||||
};
|
||||
|
||||
LOAD_CHECK(instance().set_password_callback(passwordCallback, err));
|
||||
LOAD_CHECK(instance().use_certificate_chain_file(certificateChainFile, err));
|
||||
LOAD_CHECK(instance().use_private_key_file(privateKeyFile, boost::asio::ssl::context::pem, err));
|
||||
|
||||
SSL_CTX* nativeContext = instance().native_handle();
|
||||
auto password_ui_method = CreatePasswordUiMethodFromPemCallback(SSL_CTX_get_default_passwd_cb(nativeContext));
|
||||
|
||||
auto store = OpenOpenSSLStore(boost::filesystem::absolute(certificateChainFile),
|
||||
password_ui_method.get(), SSL_CTX_get_default_passwd_cb_userdata(nativeContext));
|
||||
|
||||
if (!store)
|
||||
{
|
||||
err = GetLastOpenSSLError();
|
||||
TC_LOG_ERROR("server.ssl", "OSSL_STORE_open failed: {}", err.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
EVP_PKEY* key = nullptr;
|
||||
STACK_OF(X509)* certs = sk_X509_new_null();
|
||||
while (!OSSL_STORE_eof(store.get()))
|
||||
{
|
||||
OSSL_STORE_INFO* info = OSSL_STORE_load(store.get());
|
||||
if (!info)
|
||||
continue;
|
||||
|
||||
switch (OSSL_STORE_INFO_get_type(info))
|
||||
{
|
||||
case OSSL_STORE_INFO_PKEY:
|
||||
key = OSSL_STORE_INFO_get1_PKEY(info);
|
||||
break;
|
||||
case OSSL_STORE_INFO_CERT:
|
||||
sk_X509_push(certs, OSSL_STORE_INFO_get1_CERT(info));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sk_X509_num(certs) > 0)
|
||||
{
|
||||
X509* cert = sk_X509_shift(certs);
|
||||
SSL_CTX_use_cert_and_key(nativeContext, cert, key, certs, 1);
|
||||
}
|
||||
|
||||
sk_X509_free(certs);
|
||||
|
||||
if (!key)
|
||||
{
|
||||
std::string privateKeyFile = sConfigMgr->GetStringDefault("PrivateKeyFile", "./bnetserver.key.pem");
|
||||
LOAD_CHECK(instance().use_private_key_file(privateKeyFile, boost::asio::ssl::context::pem, err));
|
||||
}
|
||||
|
||||
#undef LOAD_CHECK
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ PidFile = ""
|
||||
|
||||
#
|
||||
# CertificatesFile
|
||||
# Description: Certificates file.
|
||||
# Description: Certificates file. Both PEM (.crt) and PKCS#12 (.pfx) formats are supported
|
||||
# Example: "/etc/ssl/certs/bnetserver.cert.pem"
|
||||
# Default: "./bnetserver.cert.pem"
|
||||
|
||||
@@ -107,6 +107,7 @@ CertificatesFile = "./bnetserver.cert.pem"
|
||||
# PrivateKeyFile
|
||||
# Description: Private key file.
|
||||
# Example: "/etc/ssl/private/bnetserver.key.pem"
|
||||
# Leave empty if you have a certificate in PKCS#12 format
|
||||
# Default: "./bnetserver.key.pem"
|
||||
|
||||
PrivateKeyFile = "./bnetserver.key.pem"
|
||||
|
||||
Reference in New Issue
Block a user