Merge commit '800f1c0bc5bd4632bd0f246c756283cc47d31a34' into pullstream

This commit is contained in:
Rebekah 2024-02-14 06:10:31 -05:00
commit 11c57356a4
Signed by: oneechanhax
GPG Key ID: 183EB7902964DAE5
17 changed files with 376 additions and 377 deletions

View File

@ -20,11 +20,12 @@
// Implements the cUrlClient class for high-level URL interaction
#include "Globals.h"
#include "UrlClient.h"
#include "UrlParser.h"
#include "HTTPMessageParser.h"
#include "../mbedTLS++/X509Cert.h"
#include "../mbedTLS++/CryptoKey.h"
#include "HTTP/UrlClient.h"
#include "HTTP/UrlParser.h"
#include "HTTP/HTTPMessageParser.h"
#include "mbedTLS++/X509Cert.h"
#include "mbedTLS++/CryptoKey.h"
@ -32,7 +33,44 @@
// fwd:
class cSchemeHandler;
typedef std::shared_ptr<cSchemeHandler> cSchemeHandlerPtr;
using cSchemeHandlerPtr = std::shared_ptr<cSchemeHandler>;
/** This is a basic set of callbacks to enable quick implementation of HTTP request. */
namespace
{
class cSimpleHTTPCallbacks :
public cUrlClient::cCallbacks
{
public:
explicit cSimpleHTTPCallbacks(std::shared_ptr<cEvent> a_Event, AString & a_ResponseBody) :
m_Event(std::move(a_Event)), m_ResponseBody(a_ResponseBody)
{
}
void OnBodyFinished() override
{
m_Event->Set();
}
void OnError(const AString & a_ErrorMsg) override
{
LOGERROR("%s %d: HTTP Error: %s", __FILE__, __LINE__, a_ErrorMsg.c_str());
m_Event->Set();
}
void OnBodyData(const void * a_Data, size_t a_Size) override
{
m_ResponseBody.append(static_cast<const char *>(a_Data), a_Size);
}
std::shared_ptr<cEvent> m_Event;
/** The accumulator for the partial body data, so that OnBodyFinished() can send the entire thing at once. */
AString & m_ResponseBody;
};
}
@ -277,7 +315,7 @@ public:
m_Link = &a_Link;
if (m_IsTls)
{
m_Link->StartTLSClient(m_ParentRequest.GetOwnCert(), m_ParentRequest.GetOwnPrivKey());
m_Link->StartTLSClient(m_ParentRequest.GetOwnCert(), m_ParentRequest.GetOwnPrivKey(), m_ParentRequest.m_UrlHost);
}
else
{
@ -387,7 +425,7 @@ public:
return;
}
}
m_ParentRequest.GetCallbacks().OnStatusLine(a_FirstLine.substr(1, idxFirstSpace), resultCode, a_FirstLine.substr(idxSecondSpace + 1));
m_ParentRequest.GetCallbacks().OnStatusLine(a_FirstLine.substr(0, idxFirstSpace), resultCode, a_FirstLine.substr(idxSecondSpace + 1));
}
@ -629,12 +667,12 @@ std::pair<bool, AString> cUrlClient::Request(
const AString & a_URL,
cCallbacksPtr && a_Callbacks,
AStringMap && a_Headers,
AString && a_Body,
const AString & a_Body,
AStringMap && a_Options
)
{
return cUrlClientRequest::Request(
a_Method, a_URL, std::move(a_Callbacks), std::move(a_Headers), std::move(a_Body), std::move(a_Options)
a_Method, a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, std::move(a_Options)
);
}
@ -645,13 +683,13 @@ std::pair<bool, AString> cUrlClient::Request(
std::pair<bool, AString> cUrlClient::Get(
const AString & a_URL,
cCallbacksPtr && a_Callbacks,
AStringMap a_Headers,
AStringMap && a_Headers,
const AString & a_Body,
AStringMap a_Options
AStringMap && a_Options
)
{
return cUrlClientRequest::Request(
"GET", a_URL, std::move(a_Callbacks), std::move(a_Headers), std::move(a_Body), std::move(a_Options)
"GET", a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, std::move(a_Options)
);
}
@ -663,12 +701,12 @@ std::pair<bool, AString> cUrlClient::Post(
const AString & a_URL,
cCallbacksPtr && a_Callbacks,
AStringMap && a_Headers,
AString && a_Body,
const AString & a_Body,
AStringMap && a_Options
)
{
return cUrlClientRequest::Request(
"POST", a_URL, std::move(a_Callbacks), std::move(a_Headers), std::move(a_Body), std::move(a_Options)
"POST", a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, std::move(a_Options)
);
}
@ -680,12 +718,12 @@ std::pair<bool, AString> cUrlClient::Put(
const AString & a_URL,
cCallbacksPtr && a_Callbacks,
AStringMap && a_Headers,
AString && a_Body,
const AString & a_Body,
AStringMap && a_Options
)
{
return cUrlClientRequest::Request(
"PUT", a_URL, std::move(a_Callbacks), std::move(a_Headers), std::move(a_Body), std::move(a_Options)
"PUT", a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, std::move(a_Options)
);
}
@ -693,3 +731,64 @@ std::pair<bool, AString> cUrlClient::Put(
std::pair<bool, AString> cUrlClient::BlockingRequest(const AString & a_Method, const AString & a_URL, AStringMap && a_Headers, const AString & a_Body, AStringMap && a_Options)
{
auto EvtFinished = std::make_shared<cEvent>();
AString Response;
auto Callbacks = std::make_unique<cSimpleHTTPCallbacks>(EvtFinished, Response);
auto [Success, ErrorMessage] = cUrlClient::Request(a_Method, a_URL, std::move(Callbacks), std::move(a_Headers), a_Body, std::move(a_Options));
if (Success)
{
EvtFinished->Wait();
}
else
{
LOGWARNING("%s: HTTP error: %s", __FUNCTION__, ErrorMessage.c_str());
return std::make_pair(false, AString());
}
return std::make_pair(true, Response);
}
std::pair<bool, AString> cUrlClient::BlockingGet(
const AString & a_URL,
AStringMap a_Headers,
const AString & a_Body,
AStringMap a_Options)
{
return BlockingRequest("GET", a_URL, std::move(a_Headers), a_Body, std::move(a_Options));
}
std::pair<bool, AString> cUrlClient::BlockingPost(
const AString & a_URL,
AStringMap && a_Headers,
const AString & a_Body,
AStringMap && a_Options)
{
return BlockingRequest("POST", a_URL, std::move(a_Headers), a_Body, std::move(a_Options));
}
std::pair<bool, AString> cUrlClient::BlockingPut(
const AString & a_URL,
AStringMap && a_Headers,
const AString & a_Body,
AStringMap && a_Options)
{
return BlockingRequest("PUT", a_URL, std::move(a_Headers), a_Body, std::move(a_Options));
}

View File

@ -102,7 +102,7 @@ public:
for such a response; instead, the redirect is silently attempted. */
virtual void OnRedirecting(const AString & a_NewLocation) {}
};
typedef std::unique_ptr<cCallbacks> cCallbacksPtr;
using cCallbacksPtr = std::unique_ptr<cCallbacks>;
/** Used for HTTP status codes. */
@ -131,7 +131,7 @@ public:
const AString & a_URL,
cCallbacksPtr && a_Callbacks,
AStringMap && a_Headers,
AString && a_Body,
const AString & a_Body,
AStringMap && a_Options
);
@ -139,9 +139,9 @@ public:
static std::pair<bool, AString> Get(
const AString & a_URL,
cCallbacksPtr && a_Callbacks,
AStringMap a_Headers = AStringMap(),
AStringMap && a_Headers = AStringMap(),
const AString & a_Body = AString(),
AStringMap a_Options = AStringMap()
AStringMap && a_Options = AStringMap()
);
/** Alias for Request("POST", ...) */
@ -149,7 +149,7 @@ public:
const AString & a_URL,
cCallbacksPtr && a_Callbacks,
AStringMap && a_Headers,
AString && a_Body,
const AString & a_Body,
AStringMap && a_Options
);
@ -158,7 +158,43 @@ public:
const AString & a_URL,
cCallbacksPtr && a_Callbacks,
AStringMap && a_Headers,
AString && a_Body,
const AString & a_Body,
AStringMap && a_Options
);
/** The method will run a thread blocking HTTP request. Any error handling
is done inside the functions. Check the LOG or stdout for any occurring
errors. Other parameters are the same as for the regular request method.
The return value is if the request was successful and the response. */
static std::pair<bool, AString> BlockingRequest(
const AString & a_Method,
const AString & a_URL,
AStringMap && a_Headers = AStringMap(),
const AString & a_Body = AString(),
AStringMap && a_Options = AStringMap()
);
/** Alias for BlockingRequest("GET", ...) */
static std::pair<bool, AString> BlockingGet(
const AString & a_URL,
AStringMap a_Headers = AStringMap(),
const AString & a_Body = AString(),
AStringMap a_Options = AStringMap()
);
/** Alias for BlockingRequest("POST", ...) */
static std::pair<bool, AString> BlockingPost(
const AString & a_URL,
AStringMap && a_Headers,
const AString & a_Body,
AStringMap && a_Options
);
/** Alias for BlockingRequest("PUT", ...) */
static std::pair<bool, AString> BlockingPut(
const AString & a_URL,
AStringMap && a_Headers,
const AString & a_Body,
AStringMap && a_Options
);
};

View File

@ -20,6 +20,7 @@
// Implements the cUrlParser class that parses string URL into individual parts
#include "Globals.h"
#include "UrlParser.h"
@ -214,3 +215,13 @@ std::pair<bool, AString> cUrlParser::Parse(
std::pair<bool, AString> cUrlParser::Validate(const AString & a_Url)
{
AString UrlScheme, UrlUsername, UrlPassword, UrlHost, UrlPath, UrlQuery, UrlFragment;
UInt16 Port;
return Parse(a_Url, UrlScheme, UrlUsername, UrlPassword, UrlHost, Port, UrlPath, UrlQuery, UrlFragment);
}

View File

@ -67,6 +67,9 @@ public:
AString & a_Query,
AString & a_Fragment
);
/** Checks if the supplied URL is valid */
static std::pair<bool, AString> Validate(const AString & a_Url);
};

View File

@ -129,7 +129,8 @@ public:
Returns empty string on success, non-empty error description on failure. */
virtual AString StartTLSClient(
cX509CertPtr a_OwnCert,
cCryptoKeyPtr a_OwnPrivKey
cCryptoKeyPtr a_OwnPrivKey,
const std::string_view hostname
) = 0;
/** Starts a TLS handshake as a server connection.

View File

@ -253,7 +253,8 @@ void cTCPLinkImpl::Close(void)
AString cTCPLinkImpl::StartTLSClient(
cX509CertPtr a_OwnCert,
cCryptoKeyPtr a_OwnPrivKey
cCryptoKeyPtr a_OwnPrivKey,
const std::string_view hostname
)
{
// Check preconditions:
@ -279,6 +280,8 @@ AString cTCPLinkImpl::StartTLSClient(
m_TlsContext->Initialize(true);
}
m_TlsContext->SetExpectedPeerName(hostname);
m_TlsContext->SetSelf(cLinkTlsContextWPtr(m_TlsContext));
// Start the handshake:

View File

@ -84,7 +84,8 @@ public:
virtual void Close(void) override;
virtual AString StartTLSClient(
cX509CertPtr a_OwnCert,
cCryptoKeyPtr a_OwnPrivKey
cCryptoKeyPtr a_OwnPrivKey,
const std::string_view hostname
) override;
virtual AString StartTLSServer(
cX509CertPtr a_OwnCert,

View File

@ -17,25 +17,25 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Authenticator.h"
#include "MojangAPI.h"
#include "../Root.h"
#include "../Server.h"
#include "../ClientHandle.h"
#include "../UUID.h"
#include "Protocol/Authenticator.h"
#include "../IniFile.h"
#include "../JsonUtils.h"
#include "ClientHandle.h"
#include "HTTP/UrlClient.h"
#include "HTTP/UrlParser.h"
#include "IniFile.h"
#include "JsonUtils.h"
#include "json/json.h"
#include "../mbedTLS++/BlockingSslClientSocket.h"
#include "Protocol/MojangAPI.h"
#include "Root.h"
#include "Server.h"
#include "UUID.h"
#define DEFAULT_AUTH_SERVER "sessionserver.mojang.com"
#define DEFAULT_AUTH_ADDRESS "/session/minecraft/hasJoined?username=%USERNAME%&serverId=%SERVERID%"
constexpr char DEFAULT_AUTH_SERVER[] = "sessionserver.mojang.com";
constexpr char DEFAULT_AUTH_ADDRESS[] = "/session/minecraft/hasJoined?username=%USERNAME%&serverId=%SERVERID%";
@ -67,6 +67,36 @@ void cAuthenticator::ReadSettings(cSettingsRepositoryInterface & a_Settings)
m_Server = a_Settings.GetValueSet ("Authentication", "Server", DEFAULT_AUTH_SERVER);
m_Address = a_Settings.GetValueSet ("Authentication", "Address", DEFAULT_AUTH_ADDRESS);
m_ShouldAuthenticate = a_Settings.GetValueSetB("Authentication", "Authenticate", true);
// prepend https:// if missing
constexpr std::string_view HttpPrefix = "http://";
constexpr std::string_view HttpsPrefix = "https://";
if (
(std::string_view(m_Server).substr(0, HttpPrefix.size()) != HttpPrefix) &&
(std::string_view(m_Server).substr(0, HttpsPrefix.size()) != HttpsPrefix)
)
{
m_Server = "https://" + m_Server;
}
{
auto [IsSuccessfull, ErrorMessage] = cUrlParser::Validate(m_Server);
if (!IsSuccessfull)
{
LOGWARNING("%s %d: Supplied invalid URL for configuration value [Authentication: Server]: \"%s\", using default! Error: %s", __FUNCTION__, __LINE__, m_Server.c_str(), ErrorMessage.c_str());
m_Server = DEFAULT_AUTH_SERVER;
}
}
{
auto [IsSuccessfull, ErrorMessage] = cUrlParser::Validate(m_Server);
if (!IsSuccessfull)
{
LOGWARNING("%s %d: Supplied invalid URL for configuration value [Authentication: Address]: \"%s\", using default! Error: %s", __FUNCTION__, __LINE__, m_Address.c_str(), ErrorMessage.c_str());
m_Address = DEFAULT_AUTH_ADDRESS;
}
}
}
@ -159,7 +189,7 @@ void cAuthenticator::Execute(void)
bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, cUUID & a_UUID, Json::Value & a_Properties)
bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, cUUID & a_UUID, Json::Value & a_Properties) const
{
LOGD("Trying to authenticate user %s", a_UserName.c_str());
@ -168,39 +198,13 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
ReplaceURL(ActualAddress, "%USERNAME%", a_UserName);
ReplaceURL(ActualAddress, "%SERVERID%", a_ServerId);
AString Request;
Request += "GET " + ActualAddress + " HTTP/1.0\r\n";
Request += "Host: " + m_Server + "\r\n";
Request += "User-Agent: Cuberite\r\n";
Request += "Connection: close\r\n";
Request += "\r\n";
AString Response;
if (!cMojangAPI::SecureRequest(m_Server, Request, Response))
// Create and send the HTTP request
auto [IsSuccessfull, Response] = cUrlClient::BlockingGet(m_Server + ActualAddress);
if (!IsSuccessfull)
{
return false;
}
// Check the HTTP status line:
const AString Prefix("HTTP/1.1 200 OK");
AString HexDump;
if (Response.compare(0, Prefix.size(), Prefix))
{
LOGINFO("User %s failed to auth, bad HTTP status line received", a_UserName.c_str());
LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
return false;
}
// Erase the HTTP headers from the response:
size_t idxHeadersEnd = Response.find("\r\n\r\n");
if (idxHeadersEnd == AString::npos)
{
LOGINFO("User %s failed to authenticate, bad HTTP response header received", a_UserName.c_str());
LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
return false;
}
Response.erase(0, idxHeadersEnd + 4);
// Parse the Json response:
if (Response.empty())
{
@ -209,14 +213,14 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
Json::Value root;
if (!JsonUtils::ParseString(Response, root))
{
LOGWARNING("cAuthenticator: Cannot parse received data (authentication) to JSON!");
LOGWARNING("%s: Cannot parse received data (authentication) to JSON!", __FUNCTION__);
return false;
}
a_UserName = root.get("name", "Unknown").asString();
a_Properties = root["properties"];
if (!a_UUID.FromString(root.get("id", "").asString()))
{
LOGWARNING("cAuthenticator: Recieved invalid UUID format");
LOGWARNING("%s: Received invalid UUID format", __FUNCTION__);
return false;
}
@ -228,9 +232,9 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
#ifdef ENABLE_PROPERTIES
/* In case we want to export this function to the plugin API later - don't forget to add the relevant INI configuration lines for DEFAULT_PROPERTIES_ADDRESS
/* In case we want to export this function to the plugin API later - don't forget to add the relevant INI configuration lines for DEFAULT_PROPERTIES_ADDRESS */
#define DEFAULT_PROPERTIES_ADDRESS "/session/minecraft/profile/%UUID%"
@ -241,43 +245,13 @@ bool cAuthenticator::GetPlayerProperties(const AString & a_UUID, Json::Value & a
{
LOGD("Trying to get properties for user %s", a_UUID.c_str());
// Create the GET request:
AString ActualAddress = m_PropertiesAddress;
ReplaceString(ActualAddress, "%UUID%", a_UUID);
AString Request;
Request += "GET " + ActualAddress + " HTTP/1.0\r\n";
Request += "Host: " + m_Server + "\r\n";
Request += "User-Agent: Cuberite\r\n";
Request += "Connection: close\r\n";
Request += "\r\n";
AString Response;
if (!ConnectSecurelyToAddress(StarfieldCACert(), m_Server, Request, Response))
// Create and send the HTTP request
auto [IsSuccessfull, Response] = cUrlClient::BlockingGet(m_Server + ActualAddress);
if (!IsSuccessfull)
{
return false;
}
// Check the HTTP status line:
const AString Prefix("HTTP/1.1 200 OK");
AString HexDump;
if (Response.compare(0, Prefix.size(), Prefix))
{
LOGINFO("Failed to get properties for user %s, bad HTTP status line received", a_UUID.c_str());
LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
return false;
}
// Erase the HTTP headers from the response:
size_t idxHeadersEnd = Response.find("\r\n\r\n");
if (idxHeadersEnd == AString::npos)
{
LOGINFO("Failed to get properties for user %s, bad HTTP response header received", a_UUID.c_str());
LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
return false;
}
Response.erase(0, idxHeadersEnd + 4);
// Parse the Json response:
if (Response.empty())
{
@ -295,7 +269,7 @@ bool cAuthenticator::GetPlayerProperties(const AString & a_UUID, Json::Value & a
a_Properties = root["properties"];
return true;
}
*/
#endif

View File

@ -82,7 +82,7 @@ private:
}
};
typedef std::deque<cUser> cUserList;
using cUserList = std::deque<cUser>;
cCriticalSection m_CS;
cUserList m_Queue;
@ -105,7 +105,7 @@ private:
/** Returns true if the user authenticated okay, false on error
Returns the case-corrected username, UUID, and properties (eg. skin). */
bool AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, cUUID & a_UUID, Json::Value & a_Properties);
bool AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, cUUID & a_UUID, Json::Value & a_Properties) const;
};

View File

@ -21,17 +21,18 @@
#include "Globals.h"
#include "MojangAPI.h"
#include "HTTP/UrlClient.h"
#include "IniFile.h"
#include "JsonUtils.h"
#include "json/json.h"
#include "mbedTLS++/BlockingSslClientSocket.h"
#include "mbedTLS++/SslConfig.h"
#include "OSSupport/IsThread.h"
#include "RankManager.h"
#include "Root.h"
#include "SQLiteCpp/Database.h"
#include "SQLiteCpp/Statement.h"
#include "../IniFile.h"
#include "../JsonUtils.h"
#include "json/json.h"
#include "../mbedTLS++/BlockingSslClientSocket.h"
#include "../mbedTLS++/SslConfig.h"
#include "../RankManager.h"
#include "../OSSupport/IsThread.h"
#include "../Root.h"
@ -46,122 +47,10 @@ const int MAX_PER_QUERY = 100;
#define DEFAULT_NAME_TO_UUID_SERVER "api.mojang.com"
#define DEFAULT_NAME_TO_UUID_ADDRESS "/profiles/minecraft"
#define DEFAULT_UUID_TO_PROFILE_SERVER "sessionserver.mojang.com"
#define DEFAULT_UUID_TO_PROFILE_ADDRESS "/session/minecraft/profile/%UUID%?unsigned=false"
/** Returns the CA certificates that should be trusted for Mojang-related connections. */
static cX509CertPtr GetCACerts(void)
{
static const char CertString[] =
// DigiCert Global Root CA (sessionserver.mojang.com)
// Downloaded from https://www.digicert.com/kb/digicert-root-certificates.htm
"-----BEGIN CERTIFICATE-----\n"
"MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n"
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n"
"QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n"
"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n"
"b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n"
"9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n"
"CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n"
"nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n"
"43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n"
"T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n"
"gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n"
"BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n"
"TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n"
"DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n"
"hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n"
"06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n"
"PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n"
"YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n"
"CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n"
"-----END CERTIFICATE-----\n"
// Amazon Root CA 1 (api.mojang.com)
// Downloaded from https://www.amazontrust.com/repository/
"-----BEGIN CERTIFICATE-----\n"
"MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\n"
"ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n"
"b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL\n"
"MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\n"
"b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj\n"
"ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM\n"
"9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw\n"
"IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6\n"
"VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L\n"
"93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm\n"
"jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n"
"AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA\n"
"A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI\n"
"U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs\n"
"N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv\n"
"o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU\n"
"5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy\n"
"rqXRfboQnoZsG4q5WTP468SQvvG5\n"
"-----END CERTIFICATE-----\n"
// AAA Certificate Services (authserver.ely.by GH#4832)
// Downloaded from https://www.tbs-certificates.co.uk/FAQ/en/Comodo_AAA_Certificate_Services.html
"-----BEGIN CERTIFICATE-----\n"
"MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb\n"
"MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow\n"
"GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj\n"
"YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL\n"
"MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE\n"
"BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM\n"
"GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP\n"
"ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua\n"
"BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe\n"
"3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4\n"
"YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR\n"
"rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm\n"
"ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU\n"
"oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF\n"
"MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v\n"
"QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t\n"
"b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF\n"
"AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q\n"
"GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz\n"
"Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2\n"
"G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi\n"
"l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3\n"
"smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==\n"
"-----END CERTIFICATE-----\n"
;
static auto X509Cert = [&]()
{
auto Cert = std::make_shared<cX509Cert>();
VERIFY(0 == Cert->Parse(CertString, sizeof(CertString)));
return Cert;
}();
return X509Cert;
}
/** Returns the config to be used for secure requests. */
static std::shared_ptr<const cSslConfig> GetSslConfig()
{
static const std::shared_ptr<const cSslConfig> Config = []()
{
auto Conf = cSslConfig::MakeDefaultConfig(true);
Conf->SetCACerts(GetCACerts());
Conf->SetAuthMode(eSslAuthMode::Required);
return Conf;
}();
return Config;
}
constexpr char DEFAULT_NAME_TO_UUID_SERVER[] = "api.mojang.com";
constexpr char DEFAULT_NAME_TO_UUID_ADDRESS[] = "/profiles/minecraft";
constexpr char DEFAULT_UUID_TO_PROFILE_SERVER[] = "sessionserver.mojang.com";
constexpr char DEFAULT_UUID_TO_PROFILE_ADDRESS[] = "/session/minecraft/profile/%UUID%?unsigned=false";
@ -204,8 +93,7 @@ cMojangAPI::sProfile::sProfile(
for (Json::UInt i = 0; i < Size; i++)
{
const Json::Value & Prop = a_Properties[i];
AString PropName = Prop.get("name", "").asString();
if (PropName != "textures")
if (Prop.get("name", "").asString() != "textures")
{
continue;
}
@ -448,61 +336,6 @@ void cMojangAPI::AddPlayerProfile(const AString & a_PlayerName, const cUUID & a_
bool cMojangAPI::SecureRequest(const AString & a_ServerName, const AString & a_Request, AString & a_Response)
{
// Connect the socket:
cBlockingSslClientSocket Socket;
Socket.SetSslConfig(GetSslConfig());
Socket.SetExpectedPeerName(a_ServerName);
if (!Socket.Connect(a_ServerName, 443))
{
LOGWARNING("%s: Can't connect to %s: %s", __FUNCTION__, a_ServerName.c_str(), Socket.GetLastErrorText().c_str());
return false;
}
if (!Socket.Send(a_Request.c_str(), a_Request.size()))
{
LOGWARNING("%s: Writing SSL data failed: %s", __FUNCTION__, Socket.GetLastErrorText().c_str());
return false;
}
// Read the HTTP response:
unsigned char buf[1024];
for (;;)
{
int ret = Socket.Receive(buf, sizeof(buf));
if ((ret == MBEDTLS_ERR_SSL_WANT_READ) || (ret == MBEDTLS_ERR_SSL_WANT_WRITE))
{
// This value should never be returned, it is handled internally by cBlockingSslClientSocket
LOGWARNING("%s: SSL reading failed internally", __FUNCTION__);
return false;
}
if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
{
break;
}
if (ret < 0)
{
LOGWARNING("%s: SSL reading failed: -0x%x", __FUNCTION__, -ret);
return false;
}
if (ret == 0)
{
break;
}
a_Response.append(reinterpret_cast<const char *>(buf), static_cast<size_t>(ret));
}
return true;
}
void cMojangAPI::LoadCachesFromDisk(void)
{
try
@ -657,7 +490,8 @@ void cMojangAPI::QueryNamesToUUIDs(AStringVector & a_NamesToQuery)
// Create the request body - a JSON containing up to MAX_PER_QUERY playernames:
Json::Value root;
int Count = 0;
AStringVector::iterator itr = a_NamesToQuery.begin(), end = a_NamesToQuery.end();
auto itr = a_NamesToQuery.begin();
auto end = a_NamesToQuery.end();
for (; (itr != end) && (Count < MAX_PER_QUERY); ++itr, ++Count)
{
Json::Value req(*itr);
@ -666,43 +500,13 @@ void cMojangAPI::QueryNamesToUUIDs(AStringVector & a_NamesToQuery)
a_NamesToQuery.erase(a_NamesToQuery.begin(), itr);
auto RequestBody = JsonUtils::WriteFastString(root);
// Create the HTTP request:
AString Request;
Request += "POST " + m_NameToUUIDAddress + " HTTP/1.0\r\n"; // We need to use HTTP 1.0 because we don't handle Chunked transfer encoding
Request += "Host: " + m_NameToUUIDServer + "\r\n";
Request += "User-Agent: Cuberite\r\n";
Request += "Connection: close\r\n";
Request += "Content-Type: application/json\r\n";
Request += fmt::format(FMT_STRING("Content-Length: {}\r\n"), RequestBody.length());
Request += "\r\n";
Request += RequestBody;
// Get the response from the server:
AString Response;
if (!SecureRequest(m_NameToUUIDServer, Request, Response))
// Create and send the HTTP request
auto [IsSuccessfull, Response] = cUrlClient::BlockingPost(m_NameToUUIDAddress, AStringMap(), std::move(RequestBody), AStringMap());
if (!IsSuccessfull)
{
continue;
}
// Check the HTTP status line:
const AString Prefix("HTTP/1.1 200 OK");
AString HexDump;
if (Response.compare(0, Prefix.size(), Prefix))
{
LOGINFO("%s failed: bad HTTP status line received", __FUNCTION__);
LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
continue;
}
// Erase the HTTP headers from the response:
size_t idxHeadersEnd = Response.find("\r\n\r\n");
if (idxHeadersEnd == AString::npos)
{
LOGINFO("%s failed: bad HTTP response header received", __FUNCTION__);
LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
continue;
}
Response.erase(0, idxHeadersEnd + 4);
// Parse the returned string into Json:
AString ParseError;
@ -778,49 +582,23 @@ void cMojangAPI::QueryUUIDToProfile(const cUUID & a_UUID)
AString Address = m_UUIDToProfileAddress;
ReplaceURL(Address, "%UUID%", a_UUID.ToShortString());
// Create the HTTP request:
AString Request;
Request += "GET " + Address + " HTTP/1.0\r\n"; // We need to use HTTP 1.0 because we don't handle Chunked transfer encoding
Request += "Host: " + m_UUIDToProfileServer + "\r\n";
Request += "User-Agent: Cuberite\r\n";
Request += "Connection: close\r\n";
Request += "Content-Length: 0\r\n";
Request += "\r\n";
// Get the response from the server:
AString Response;
if (!SecureRequest(m_UUIDToProfileServer, Request, Response))
// Create and send the HTTP request
auto [IsSuccessfull, Response] = cUrlClient::BlockingGet(Address);
if (!IsSuccessfull)
{
return;
}
// Check the HTTP status line:
const AString Prefix("HTTP/1.1 200 OK");
AString HexDump;
if (Response.compare(0, Prefix.size(), Prefix))
{
LOGINFO("%s failed: bad HTTP status line received", __FUNCTION__);
LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
return;
}
// Erase the HTTP headers from the response:
size_t idxHeadersEnd = Response.find("\r\n\r\n");
if (idxHeadersEnd == AString::npos)
{
LOGINFO("%s failed: bad HTTP response header received", __FUNCTION__);
LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
return;
}
Response.erase(0, idxHeadersEnd + 4);
// Parse the returned string into Json:
Json::Value root;
AString ParseError;
if (!JsonUtils::ParseString(Response, root, &ParseError) || !root.isObject())
{
LOGWARNING("%s failed: Cannot parse received data (NameToUUID) to JSON: \"%s\"", __FUNCTION__, ParseError);
#ifdef NDEBUG
AString HexDump;
LOGD("Response body:\n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
#endif
return;
}
@ -907,7 +685,7 @@ void cMojangAPI::Update(void)
std::vector<cUUID> ProfileUUIDs;
{
cCSLock Lock(m_CSUUIDToProfile);
for (auto & UUIDToProfile : m_UUIDToProfile)
for (const auto & UUIDToProfile : m_UUIDToProfile)
{
if (UUIDToProfile.second.m_DateTime < LimitDateTime)
{

View File

@ -27,7 +27,7 @@
#include <time.h>
#include "../UUID.h"
#include "UUID.h"
@ -58,11 +58,6 @@ public:
Loads cached results from disk. */
void Start(cSettingsRepositoryInterface & a_Settings, bool a_ShouldAuth);
/** Connects to the specified server using SSL, sends the given request and receives the response.
Checks Mojang certificates using the hard-coded Starfield root CA certificate.
Returns true if all was successful, false on failure. */
static bool SecureRequest(const AString & a_ServerName, const AString & a_Request, AString & a_Response);
/** Converts a player name into a UUID.
The UUID will be nil on error.
If a_UseOnlyCached is true, the function only consults the cached values.
@ -147,8 +142,8 @@ protected:
Int64 a_DateTime
);
};
typedef std::map<AString, sProfile> cProfileMap;
typedef std::map<cUUID, sProfile> cUUIDProfileMap;
using cProfileMap = std::map<AString, sProfile>;
using cUUIDProfileMap = std::map<cUUID, sProfile>;
/** The server to connect to when converting player names to UUIDs. For example "api.mojang.com". */

View File

@ -25,6 +25,7 @@ target_sources(
EntropyContext.h
ErrorCodes.h
RsaPrivateKey.h
RootCA.h
SslConfig.h
SslContext.h
Sha1Checksum.h

97
src/mbedTLS++/RootCA.h Normal file
View File

@ -0,0 +1,97 @@
// This file contains the public keys for different root CAs
#include "Globals.h"
#include "mbedTLS++/X509Cert.h"
static cX509CertPtr GetCACerts(void)
{
static const char CertString[] =
// DigiCert Global Root CA (sessionserver.mojang.com)
// Downloaded from https://www.digicert.com/kb/digicert-root-certificates.htm
// DigiCert Global Root CA
"-----BEGIN CERTIFICATE-----\n"
"MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n"
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n"
"QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n"
"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n"
"b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n"
"9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n"
"CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n"
"nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n"
"43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n"
"T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n"
"gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n"
"BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n"
"TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n"
"DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n"
"hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n"
"06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n"
"PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n"
"YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n"
"CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n"
"-----END CERTIFICATE-----\n"
// Amazon Root CA 1 (api.mojang.com)
// Downloaded from https://www.amazontrust.com/repository/
"-----BEGIN CERTIFICATE-----\n"
"MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\n"
"ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n"
"b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL\n"
"MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\n"
"b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj\n"
"ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM\n"
"9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw\n"
"IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6\n"
"VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L\n"
"93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm\n"
"jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n"
"AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA\n"
"A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI\n"
"U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs\n"
"N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv\n"
"o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU\n"
"5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy\n"
"rqXRfboQnoZsG4q5WTP468SQvvG5\n"
"-----END CERTIFICATE-----\n"
// AAA Certificate Services (authserver.ely.by GH#4832)
// Downloaded from https://www.tbs-certificates.co.uk/FAQ/en/Comodo_AAA_Certificate_Services.html
"-----BEGIN CERTIFICATE-----\n"
"MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb\n"
"MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow\n"
"GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj\n"
"YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL\n"
"MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE\n"
"BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM\n"
"GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP\n"
"ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua\n"
"BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe\n"
"3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4\n"
"YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR\n"
"rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm\n"
"ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU\n"
"oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF\n"
"MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v\n"
"QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t\n"
"b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF\n"
"AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q\n"
"GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz\n"
"Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2\n"
"G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi\n"
"l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3\n"
"smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==\n"
"-----END CERTIFICATE-----\n"
;
static auto X509Cert = [&]()
{
auto Cert = std::make_shared<cX509Cert>();
VERIFY(0 == Cert->Parse(CertString, sizeof(CertString)));
return Cert;
}();
return X509Cert;
}

View File

@ -17,11 +17,11 @@
#include "Globals.h"
#include "SslConfig.h"
#include "EntropyContext.h"
#include "CtrDrbgContext.h"
#include "CryptoKey.h"
#include "X509Cert.h"
#include "mbedTLS++/SslConfig.h"
#include "mbedTLS++/CryptoKey.h"
#include "mbedTLS++/EntropyContext.h"
#include "mbedTLS++/RootCA.h"
// This allows us to debug SSL and certificate problems, but produce way too much output,
@ -241,7 +241,6 @@ void cSslConfig::SetCACerts(cX509CertPtr a_CACert)
std::shared_ptr<cSslConfig> cSslConfig::MakeDefaultConfig(bool a_IsClient)
{
// TODO: Default CA chain and SetAuthMode(eSslAuthMode::Required)
auto Ret = std::make_shared<cSslConfig>();
Ret->InitDefaults(a_IsClient);
@ -252,7 +251,8 @@ std::shared_ptr<cSslConfig> cSslConfig::MakeDefaultConfig(bool a_IsClient)
Ret->SetRng(std::move(CtrDrbg));
}
Ret->SetAuthMode(eSslAuthMode::None); // We cannot verify because we don't have a CA chain
Ret->SetAuthMode(eSslAuthMode::Required);
Ret->SetCACerts(GetCACerts());
#ifndef NDEBUG
#ifdef ENABLE_SSL_DEBUG_MSG

View File

@ -98,10 +98,10 @@ int cSslContext::Initialize(bool a_IsClient)
void cSslContext::SetExpectedPeerName(const AString & a_ExpectedPeerName)
void cSslContext::SetExpectedPeerName(const std::string_view a_ExpectedPeerName)
{
ASSERT(m_IsValid); // Call Initialize() first
mbedtls_ssl_set_hostname(&m_Ssl, a_ExpectedPeerName.c_str());
mbedtls_ssl_set_hostname(&m_Ssl, a_ExpectedPeerName.data());
}

View File

@ -70,7 +70,7 @@ public:
/** Sets the SSL peer name expected for this context. Must be called after Initialize().
\param a_ExpectedPeerName CommonName that we expect the SSL peer to have in its cert,
if it is different, the verification will fail. An empty string will disable the CN check. */
void SetExpectedPeerName(const AString & a_ExpectedPeerName);
void SetExpectedPeerName(const std::string_view a_ExpectedPeerName);
/** Writes data to be encrypted and sent to the SSL peer. Will perform SSL handshake, if needed.
Returns the number of bytes actually written, or mbedTLS error code.

View File

@ -133,7 +133,7 @@ int TestRequest1()
auto callbacks = std::make_unique<cCallbacks>(evtFinished);
AStringMap options;
options["MaxRedirects"] = "0";
auto res = cUrlClient::Get("http://github.com", std::move(callbacks), AStringMap(), AString(), options);
auto res = cUrlClient::Get("http://github.com", std::move(callbacks), AStringMap(), AString(), std::move(options));
if (res.first)
{
evtFinished->Wait();
@ -179,7 +179,7 @@ int TestRequest3()
auto callbacks = std::make_unique<cCallbacks>(evtFinished);
AStringMap options;
options["MaxRedirects"] = "0";
auto res = cUrlClient::Get("https://github.com", std::move(callbacks), AStringMap(), AString(), options);
auto res = cUrlClient::Get("https://github.com", std::move(callbacks), AStringMap(), AString(), std::move(options));
if (res.first)
{
evtFinished->Wait();