aboutsummaryrefslogtreecommitdiff
path: root/src/server/bnetserver
diff options
context:
space:
mode:
authorfunjoker <funjoker109@gmail.com>2024-03-28 20:18:59 +0100
committerfunjoker <funjoker109@gmail.com>2024-03-28 20:20:04 +0100
commite769af1044f524ee9ef469a3d1bfb728ee5ef4d0 (patch)
tree8da8700300f27e6070a12356e97f459a7841b081 /src/server/bnetserver
parentcdaf8ffc068ef00a3427af2b95a46e360d63e1fc (diff)
Core: port sneaky fixes from "Core: Updated to 10.2.6.53840"
Diffstat (limited to 'src/server/bnetserver')
-rw-r--r--src/server/bnetserver/REST/LoginHttpSession.cpp62
-rw-r--r--src/server/bnetserver/REST/LoginHttpSession.h49
-rw-r--r--src/server/bnetserver/REST/LoginRESTService.cpp28
-rw-r--r--src/server/bnetserver/REST/LoginRESTService.h14
-rw-r--r--src/server/bnetserver/Server/Session.cpp3
-rw-r--r--src/server/bnetserver/Server/SslContext.cpp33
-rw-r--r--src/server/bnetserver/Server/SslContext.h5
7 files changed, 148 insertions, 46 deletions
diff --git a/src/server/bnetserver/REST/LoginHttpSession.cpp b/src/server/bnetserver/REST/LoginHttpSession.cpp
index 95112cb8836..aff579de7f9 100644
--- a/src/server/bnetserver/REST/LoginHttpSession.cpp
+++ b/src/server/bnetserver/REST/LoginHttpSession.cpp
@@ -23,17 +23,20 @@
namespace Battlenet
{
-LoginHttpSession::LoginHttpSession(boost::asio::ip::tcp::socket&& socket)
- : SslSocket(std::move(socket), SslContext::instance())
+template<template<typename> typename SocketImpl>
+LoginHttpSession<SocketImpl>::LoginHttpSession(boost::asio::ip::tcp::socket&& socket, LoginHttpSessionWrapper& owner)
+ : BaseSocket(std::move(socket), SslContext::instance()), _owner(owner)
{
}
-LoginHttpSession::~LoginHttpSession() = default;
+template<template<typename> typename SocketImpl>
+LoginHttpSession<SocketImpl>::~LoginHttpSession() = default;
-void LoginHttpSession::Start()
+template<template<typename> typename SocketImpl>
+void LoginHttpSession<SocketImpl>::Start()
{
- std::string ip_address = GetRemoteIpAddress().to_string();
- TC_LOG_TRACE("server.http.session", "{} Accepted connection", GetClientInfo());
+ std::string ip_address = this->GetRemoteIpAddress().to_string();
+ TC_LOG_TRACE("server.http.session", "{} Accepted connection", this->GetClientInfo());
// Verify that this IP is not in the ip_banned table
LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS));
@@ -41,11 +44,12 @@ void LoginHttpSession::Start()
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO);
stmt->setString(0, ip_address);
- _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt)
- .WithPreparedCallback([sess = shared_from_this()](PreparedQueryResult result) { sess->CheckIpCallback(std::move(result)); }));
+ this->_queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt)
+ .WithPreparedCallback([sess = this->shared_from_this()](PreparedQueryResult result) { sess->CheckIpCallback(std::move(result)); }));
}
-void LoginHttpSession::CheckIpCallback(PreparedQueryResult result)
+template<template<typename> typename SocketImpl>
+void LoginHttpSession<SocketImpl>::CheckIpCallback(PreparedQueryResult result)
{
if (result)
{
@@ -60,21 +64,30 @@ void LoginHttpSession::CheckIpCallback(PreparedQueryResult result)
if (banned)
{
- TC_LOG_DEBUG("server.http.session", "{} tries to log in using banned IP!", GetClientInfo());
- CloseSocket();
+ TC_LOG_DEBUG("server.http.session", "{} tries to log in using banned IP!", this->GetClientInfo());
+ this->CloseSocket();
return;
}
}
- AsyncHandshake();
+ if constexpr (std::is_same_v<BaseSocket, Trinity::Net::Http::SslSocket<LoginHttpSession<Trinity::Net::Http::SslSocket>>>)
+ {
+ this->AsyncHandshake();
+ }
+ else
+ {
+ this->ResetHttpParser();
+ this->AsyncRead();
+ }
}
-Trinity::Net::Http::RequestHandlerResult LoginHttpSession::RequestHandler(Trinity::Net::Http::RequestContext& context)
+template<template<typename> typename SocketImpl>
+Trinity::Net::Http::RequestHandlerResult LoginHttpSession<SocketImpl>::RequestHandler(Trinity::Net::Http::RequestContext& context)
{
- return sLoginService.HandleRequest(shared_from_this(), context);
+ return sLoginService.HandleRequest(_owner.shared_from_this(), context);
}
-std::shared_ptr<Trinity::Net::Http::SessionState> LoginHttpSession::ObtainSessionState(Trinity::Net::Http::RequestContext& context) const
+std::shared_ptr<Trinity::Net::Http::SessionState> ObtainSessionState(Trinity::Net::Http::RequestContext& context, boost::asio::ip::address const& remoteAddress)
{
using namespace std::string_literals;
@@ -92,27 +105,38 @@ std::shared_ptr<Trinity::Net::Http::SessionState> LoginHttpSession::ObtainSessio
if (eq != std::string_view::npos)
name = cookie.substr(0, eq);
- return name == SESSION_ID_COOKIE;
+ return name == LoginHttpSessionWrapper::SESSION_ID_COOKIE;
});
if (sessionIdItr != cookies.end())
{
std::string_view value = sessionIdItr->substr(eq + 1);
- state = sLoginService.FindAndRefreshSessionState(value, GetRemoteIpAddress());
+ state = sLoginService.FindAndRefreshSessionState(value, remoteAddress);
}
}
if (!state)
{
- state = sLoginService.CreateNewSessionState(GetRemoteIpAddress());
+ state = sLoginService.CreateNewSessionState(remoteAddress);
std::string_view host = Trinity::Net::Http::ToStdStringView(context.request[boost::beast::http::field::host]);
if (std::size_t port = host.find(':'); port != std::string_view::npos)
host.remove_suffix(host.length() - port);
context.response.insert(boost::beast::http::field::set_cookie, Trinity::StringFormat("{}={}; Path=/bnetserver; Domain={}; Secure; HttpOnly; SameSite=None",
- SESSION_ID_COOKIE, boost::uuids::to_string(state->Id), host));
+ LoginHttpSessionWrapper::SESSION_ID_COOKIE, boost::uuids::to_string(state->Id), host));
}
return state;
}
+
+template class LoginHttpSession<Trinity::Net::Http::SslSocket>;
+template class LoginHttpSession<Trinity::Net::Http::Socket>;
+
+LoginHttpSessionWrapper::LoginHttpSessionWrapper(boost::asio::ip::tcp::socket&& socket)
+{
+ if (!SslContext::UsesDevWildcardCertificate())
+ _socket = std::make_shared<LoginHttpSession<Trinity::Net::Http::SslSocket>>(std::move(socket), *this);
+ else
+ _socket = std::make_shared<LoginHttpSession<Trinity::Net::Http::Socket>>(std::move(socket), *this);
+}
}
diff --git a/src/server/bnetserver/REST/LoginHttpSession.h b/src/server/bnetserver/REST/LoginHttpSession.h
index 2ee70d5afa5..6bd1ec113d0 100644
--- a/src/server/bnetserver/REST/LoginHttpSession.h
+++ b/src/server/bnetserver/REST/LoginHttpSession.h
@@ -18,8 +18,10 @@
#ifndef TRINITYCORE_LOGIN_HTTP_SESSION_H
#define TRINITYCORE_LOGIN_HTTP_SESSION_H
+#include "HttpSocket.h"
#include "HttpSslSocket.h"
#include "SRP6.h"
+#include <variant>
namespace Battlenet
{
@@ -28,12 +30,16 @@ struct LoginSessionState : public Trinity::Net::Http::SessionState
std::unique_ptr<Trinity::Crypto::SRP::BnetSRP6Base> Srp;
};
-class LoginHttpSession : public Trinity::Net::Http::SslSocket<LoginHttpSession>
+class LoginHttpSessionWrapper;
+std::shared_ptr<Trinity::Net::Http::SessionState> ObtainSessionState(Trinity::Net::Http::RequestContext& context, boost::asio::ip::address const& remoteAddress);
+
+template<template<typename> typename SocketImpl>
+class LoginHttpSession : public SocketImpl<LoginHttpSession<SocketImpl>>
{
-public:
- static constexpr std::string_view SESSION_ID_COOKIE = "JSESSIONID";
+ using BaseSocket = SocketImpl<LoginHttpSession<SocketImpl>>;
- explicit LoginHttpSession(boost::asio::ip::tcp::socket&& socket);
+public:
+ explicit LoginHttpSession(boost::asio::ip::tcp::socket&& socket, LoginHttpSessionWrapper& owner);
~LoginHttpSession();
void Start() override;
@@ -42,10 +48,41 @@ public:
Trinity::Net::Http::RequestHandlerResult RequestHandler(Trinity::Net::Http::RequestContext& context) override;
- LoginSessionState* GetSessionState() const { return static_cast<LoginSessionState*>(_state.get()); }
+ LoginSessionState* GetSessionState() const { return static_cast<LoginSessionState*>(this->_state.get()); }
protected:
- std::shared_ptr<Trinity::Net::Http::SessionState> ObtainSessionState(Trinity::Net::Http::RequestContext& context) const override;
+ std::shared_ptr<Trinity::Net::Http::SessionState> ObtainSessionState(Trinity::Net::Http::RequestContext& context) const override
+ {
+ return Battlenet::ObtainSessionState(context, this->GetRemoteIpAddress());
+ }
+
+ LoginHttpSessionWrapper& _owner;
+};
+
+class LoginHttpSessionWrapper : public Trinity::Net::Http::AbstractSocket, public std::enable_shared_from_this<LoginHttpSessionWrapper>
+{
+public:
+ static constexpr std::string_view SESSION_ID_COOKIE = "JSESSIONID";
+
+ explicit LoginHttpSessionWrapper(boost::asio::ip::tcp::socket&& socket);
+
+ void Start() { return std::visit([&](auto&& socket) { return socket->Start(); }, _socket); }
+ bool Update() { return std::visit([&](auto&& socket) { return socket->Update(); }, _socket); }
+ boost::asio::ip::address GetRemoteIpAddress() const { return std::visit([&](auto&& socket) { return socket->GetRemoteIpAddress(); }, _socket); }
+ bool IsOpen() const { return std::visit([&](auto&& socket) { return socket->IsOpen(); }, _socket); }
+ void CloseSocket() { return std::visit([&](auto&& socket) { return socket->CloseSocket(); }, _socket); }
+
+ void SendResponse(Trinity::Net::Http::RequestContext& context) override { return std::visit([&](auto&& socket) { return socket->SendResponse(context); }, _socket); }
+ void QueueQuery(QueryCallback&& queryCallback) override { return std::visit([&](auto&& socket) { return socket->QueueQuery(std::move(queryCallback)); }, _socket); }
+ std::string GetClientInfo() const override { return std::visit([&](auto&& socket) { return socket->GetClientInfo(); }, _socket); }
+ Optional<boost::uuids::uuid> GetSessionId() const override { return std::visit([&](auto&& socket) { return socket->GetSessionId(); }, _socket); }
+ LoginSessionState* GetSessionState() const { return std::visit([&](auto&& socket) { return socket->GetSessionState(); }, _socket); }
+
+private:
+ std::variant<
+ std::shared_ptr<LoginHttpSession<Trinity::Net::Http::SslSocket>>,
+ std::shared_ptr<LoginHttpSession<Trinity::Net::Http::Socket>>
+ > _socket;
};
}
#endif // TRINITYCORE_LOGIN_HTTP_SESSION_H
diff --git a/src/server/bnetserver/REST/LoginRESTService.cpp b/src/server/bnetserver/REST/LoginRESTService.cpp
index 7587510bafc..c9aabb248a3 100644
--- a/src/server/bnetserver/REST/LoginRESTService.cpp
+++ b/src/server/bnetserver/REST/LoginRESTService.cpp
@@ -25,6 +25,7 @@
#include "IteratorPair.h"
#include "ProtobufJSON.h"
#include "Resolver.h"
+#include "SslContext.h"
#include "Timer.h"
#include "Util.h"
@@ -43,32 +44,32 @@ bool LoginRESTService::StartNetwork(Trinity::Asio::IoContext& ioContext, std::st
using Trinity::Net::Http::RequestHandlerFlag;
- RegisterHandler(boost::beast::http::verb::get, "/bnetserver/login/", [this](std::shared_ptr<LoginHttpSession> session, HttpRequestContext& context)
+ RegisterHandler(boost::beast::http::verb::get, "/bnetserver/login/", [this](std::shared_ptr<LoginHttpSessionWrapper> session, HttpRequestContext& context)
{
return HandleGetForm(std::move(session), context);
});
- RegisterHandler(boost::beast::http::verb::get, "/bnetserver/gameAccounts/", [](std::shared_ptr<LoginHttpSession> session, HttpRequestContext& context)
+ RegisterHandler(boost::beast::http::verb::get, "/bnetserver/gameAccounts/", [](std::shared_ptr<LoginHttpSessionWrapper> session, HttpRequestContext& context)
{
return HandleGetGameAccounts(std::move(session), context);
});
- RegisterHandler(boost::beast::http::verb::get, "/bnetserver/portal/", [this](std::shared_ptr<LoginHttpSession> session, HttpRequestContext& context)
+ RegisterHandler(boost::beast::http::verb::get, "/bnetserver/portal/", [this](std::shared_ptr<LoginHttpSessionWrapper> session, HttpRequestContext& context)
{
return HandleGetPortal(std::move(session), context);
});
- RegisterHandler(boost::beast::http::verb::post, "/bnetserver/login/", [this](std::shared_ptr<LoginHttpSession> session, HttpRequestContext& context)
+ RegisterHandler(boost::beast::http::verb::post, "/bnetserver/login/", [this](std::shared_ptr<LoginHttpSessionWrapper> session, HttpRequestContext& context)
{
return HandlePostLogin(std::move(session), context);
}, RequestHandlerFlag::DoNotLogRequestContent);
- RegisterHandler(boost::beast::http::verb::post, "/bnetserver/login/srp/", [](std::shared_ptr<LoginHttpSession> session, HttpRequestContext& context)
+ RegisterHandler(boost::beast::http::verb::post, "/bnetserver/login/srp/", [](std::shared_ptr<LoginHttpSessionWrapper> session, HttpRequestContext& context)
{
return HandlePostLoginSrpChallenge(std::move(session), context);
});
- RegisterHandler(boost::beast::http::verb::post, "/bnetserver/refreshLoginTicket/", [this](std::shared_ptr<LoginHttpSession> session, HttpRequestContext& context)
+ RegisterHandler(boost::beast::http::verb::post, "/bnetserver/refreshLoginTicket/", [this](std::shared_ptr<LoginHttpSessionWrapper> session, HttpRequestContext& context)
{
return HandlePostRefreshLoginTicket(std::move(session), context);
});
@@ -165,17 +166,18 @@ std::string LoginRESTService::ExtractAuthorization(HttpRequest const& request)
return ticket;
}
-LoginRESTService::RequestHandlerResult LoginRESTService::HandleGetForm(std::shared_ptr<LoginHttpSession> session, HttpRequestContext& context) const
+LoginRESTService::RequestHandlerResult LoginRESTService::HandleGetForm(std::shared_ptr<LoginHttpSessionWrapper> session, HttpRequestContext& context) const
{
JSON::Login::FormInputs form = _formInputs;
- form.set_srp_url(Trinity::StringFormat("https://{}:{}/bnetserver/login/srp/", GetHostnameForClient(session->GetRemoteIpAddress()), _port));
+ form.set_srp_url(Trinity::StringFormat("http{}://{}:{}/bnetserver/login/srp/", !SslContext::UsesDevWildcardCertificate() ? "s" : "",
+ GetHostnameForClient(session->GetRemoteIpAddress()), _port));
context.response.set(boost::beast::http::field::content_type, "application/json;charset=utf-8");
context.response.body() = ::JSON::Serialize(form);
return RequestHandlerResult::Handled;
}
-LoginRESTService::RequestHandlerResult LoginRESTService::HandleGetGameAccounts(std::shared_ptr<LoginHttpSession> session, HttpRequestContext& context)
+LoginRESTService::RequestHandlerResult LoginRESTService::HandleGetGameAccounts(std::shared_ptr<LoginHttpSessionWrapper> session, HttpRequestContext& context)
{
std::string ticket = ExtractAuthorization(context.request);
if (ticket.empty())
@@ -224,14 +226,14 @@ LoginRESTService::RequestHandlerResult LoginRESTService::HandleGetGameAccounts(s
return RequestHandlerResult::Async;
}
-LoginRESTService::RequestHandlerResult LoginRESTService::HandleGetPortal(std::shared_ptr<LoginHttpSession> session, HttpRequestContext& context) const
+LoginRESTService::RequestHandlerResult LoginRESTService::HandleGetPortal(std::shared_ptr<LoginHttpSessionWrapper> session, HttpRequestContext& context) const
{
context.response.set(boost::beast::http::field::content_type, "text/plain");
context.response.body() = Trinity::StringFormat("{}:{}", GetHostnameForClient(session->GetRemoteIpAddress()), sConfigMgr->GetIntDefault("BattlenetPort", 1119));
return RequestHandlerResult::Handled;
}
-LoginRESTService::RequestHandlerResult LoginRESTService::HandlePostLogin(std::shared_ptr<LoginHttpSession> session, HttpRequestContext& context) const
+LoginRESTService::RequestHandlerResult LoginRESTService::HandlePostLogin(std::shared_ptr<LoginHttpSessionWrapper> session, HttpRequestContext& context) const
{
std::shared_ptr<JSON::Login::LoginForm> loginForm = std::make_shared<JSON::Login::LoginForm>();
if (!::JSON::Deserialize(context.request.body(), loginForm.get()))
@@ -395,7 +397,7 @@ LoginRESTService::RequestHandlerResult LoginRESTService::HandlePostLogin(std::sh
return RequestHandlerResult::Async;
}
-LoginRESTService::RequestHandlerResult LoginRESTService::HandlePostLoginSrpChallenge(std::shared_ptr<LoginHttpSession> session, HttpRequestContext& context)
+LoginRESTService::RequestHandlerResult LoginRESTService::HandlePostLoginSrpChallenge(std::shared_ptr<LoginHttpSessionWrapper> session, HttpRequestContext& context)
{
JSON::Login::LoginForm loginForm;
if (!::JSON::Deserialize(context.request.body(), &loginForm))
@@ -482,7 +484,7 @@ LoginRESTService::RequestHandlerResult LoginRESTService::HandlePostLoginSrpChall
return RequestHandlerResult::Async;
}
-LoginRESTService::RequestHandlerResult LoginRESTService::HandlePostRefreshLoginTicket(std::shared_ptr<LoginHttpSession> session, HttpRequestContext& context) const
+LoginRESTService::RequestHandlerResult LoginRESTService::HandlePostRefreshLoginTicket(std::shared_ptr<LoginHttpSessionWrapper> session, HttpRequestContext& context) const
{
std::string ticket = ExtractAuthorization(context.request);
if (ticket.empty())
diff --git a/src/server/bnetserver/REST/LoginRESTService.h b/src/server/bnetserver/REST/LoginRESTService.h
index 5683c262590..bcc99808505 100644
--- a/src/server/bnetserver/REST/LoginRESTService.h
+++ b/src/server/bnetserver/REST/LoginRESTService.h
@@ -42,7 +42,7 @@ enum class BanMode
BAN_ACCOUNT = 1
};
-class LoginRESTService : public Trinity::Net::Http::HttpService<LoginHttpSession>
+class LoginRESTService : public Trinity::Net::Http::HttpService<LoginHttpSessionWrapper>
{
public:
using RequestHandlerResult = Trinity::Net::Http::RequestHandlerResult;
@@ -67,13 +67,13 @@ private:
static std::string ExtractAuthorization(HttpRequest const& request);
- RequestHandlerResult HandleGetForm(std::shared_ptr<LoginHttpSession> session, HttpRequestContext& context) const;
- static RequestHandlerResult HandleGetGameAccounts(std::shared_ptr<LoginHttpSession> session, HttpRequestContext& context);
- RequestHandlerResult HandleGetPortal(std::shared_ptr<LoginHttpSession> session, HttpRequestContext& context) const;
+ RequestHandlerResult HandleGetForm(std::shared_ptr<LoginHttpSessionWrapper> session, HttpRequestContext& context) const;
+ static RequestHandlerResult HandleGetGameAccounts(std::shared_ptr<LoginHttpSessionWrapper> session, HttpRequestContext& context);
+ RequestHandlerResult HandleGetPortal(std::shared_ptr<LoginHttpSessionWrapper> session, HttpRequestContext& context) const;
- RequestHandlerResult HandlePostLogin(std::shared_ptr<LoginHttpSession> session, HttpRequestContext& context) const;
- static RequestHandlerResult HandlePostLoginSrpChallenge(std::shared_ptr<LoginHttpSession> session, HttpRequestContext& context);
- RequestHandlerResult HandlePostRefreshLoginTicket(std::shared_ptr<LoginHttpSession> session, HttpRequestContext& context) const;
+ RequestHandlerResult HandlePostLogin(std::shared_ptr<LoginHttpSessionWrapper> session, HttpRequestContext& context) const;
+ static RequestHandlerResult HandlePostLoginSrpChallenge(std::shared_ptr<LoginHttpSessionWrapper> session, HttpRequestContext& context);
+ RequestHandlerResult HandlePostRefreshLoginTicket(std::shared_ptr<LoginHttpSessionWrapper> session, HttpRequestContext& context) const;
static std::unique_ptr<Trinity::Crypto::SRP::BnetSRP6Base> CreateSrpImplementation(SrpVersion version, SrpHashFunction hashFunction,
std::string const& username, Trinity::Crypto::SRP::Salt const& salt, Trinity::Crypto::SRP::Verifier const& verifier);
diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp
index b450df14e1d..c94ee6e3e56 100644
--- a/src/server/bnetserver/Server/Session.cpp
+++ b/src/server/bnetserver/Server/Session.cpp
@@ -260,7 +260,8 @@ uint32 Battlenet::Session::HandleLogon(authentication::v1::LogonRequest const* l
challenge::v1::ChallengeExternalRequest externalChallenge;
externalChallenge.set_payload_type("web_auth_url");
- externalChallenge.set_payload(Trinity::StringFormat("https://{}:{}/bnetserver/login/", sLoginService.GetHostnameForClient(GetRemoteIpAddress()), sLoginService.GetPort()));
+ externalChallenge.set_payload(Trinity::StringFormat("http{}://{}:{}/bnetserver/login/", !SslContext::UsesDevWildcardCertificate() ? "s" : "",
+ sLoginService.GetHostnameForClient(GetRemoteIpAddress()), sLoginService.GetPort()));
Service<challenge::v1::ChallengeListener>(this).OnExternalChallenge(&externalChallenge);
return ERROR_OK;
}
diff --git a/src/server/bnetserver/Server/SslContext.cpp b/src/server/bnetserver/Server/SslContext.cpp
index 92d95f24cc5..52daff1645d 100644
--- a/src/server/bnetserver/Server/SslContext.cpp
+++ b/src/server/bnetserver/Server/SslContext.cpp
@@ -24,6 +24,8 @@
#include <openssl/store.h>
#include <openssl/ui.h>
+bool Battlenet::SslContext::_usesDevWildcardCertificate = false;
+
namespace
{
auto CreatePasswordUiMethodFromPemCallback(::pem_password_cb* callback)
@@ -114,6 +116,37 @@ bool Battlenet::SslContext::Initialize()
if (sk_X509_num(certs) > 0)
{
X509* cert = sk_X509_shift(certs);
+
+ _usesDevWildcardCertificate = [&]
+ {
+ X509_NAME const* nm = X509_get_subject_name(cert);
+ int32 lastpos = -1;
+ while (true)
+ {
+ lastpos = X509_NAME_get_index_by_NID(nm, NID_commonName, lastpos);
+ if (lastpos == -1)
+ break;
+
+ X509_NAME_ENTRY* e = X509_NAME_get_entry(nm, lastpos);
+ if (!e)
+ continue;
+
+ ASN1_STRING* text = X509_NAME_ENTRY_get_data(e);
+ if (!text)
+ continue;
+
+ unsigned char* utf8TextRaw = nullptr;
+ if (int utf8Length = ASN1_STRING_to_UTF8(&utf8TextRaw, text); utf8Length >= 0)
+ {
+ auto utf8Text = Trinity::make_unique_ptr_with_deleter(utf8TextRaw, [](unsigned char* ptr) { ::OPENSSL_free(ptr); });
+ if (std::string_view(reinterpret_cast<char const*>(utf8Text.get()), utf8Length) == "*.*")
+ return true;
+ }
+ }
+
+ return false;
+ }();
+
SSL_CTX_use_cert_and_key(nativeContext, cert, key, certs, 1);
}
diff --git a/src/server/bnetserver/Server/SslContext.h b/src/server/bnetserver/Server/SslContext.h
index 470deffd97e..330c0db221b 100644
--- a/src/server/bnetserver/Server/SslContext.h
+++ b/src/server/bnetserver/Server/SslContext.h
@@ -28,6 +28,11 @@ namespace Battlenet
static bool Initialize();
static boost::asio::ssl::context& instance();
+
+ static bool UsesDevWildcardCertificate() { return _usesDevWildcardCertificate; }
+
+ private:
+ static bool _usesDevWildcardCertificate;
};
}