summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorx12xx12x <44411062+12xx12@users.noreply.github.com>2023-03-26 14:48:06 +0200
committerMattes D <github@xoft.cz>2023-05-19 16:25:12 +0200
commit800f1c0bc5bd4632bd0f246c756283cc47d31a34 (patch)
tree9200f7d4bb2a4e3d91161468859c403f9933eae1
parentRemoved all Printf-family functions from StringUtils. (diff)
downloadcuberite-800f1c0bc5bd4632bd0f246c756283cc47d31a34.tar
cuberite-800f1c0bc5bd4632bd0f246c756283cc47d31a34.tar.gz
cuberite-800f1c0bc5bd4632bd0f246c756283cc47d31a34.tar.bz2
cuberite-800f1c0bc5bd4632bd0f246c756283cc47d31a34.tar.lz
cuberite-800f1c0bc5bd4632bd0f246c756283cc47d31a34.tar.xz
cuberite-800f1c0bc5bd4632bd0f246c756283cc47d31a34.tar.zst
cuberite-800f1c0bc5bd4632bd0f246c756283cc47d31a34.zip
-rw-r--r--src/Bindings/LuaTCPLink.cpp4
-rw-r--r--src/HTTP/UrlClient.cpp133
-rw-r--r--src/HTTP/UrlClient.h48
-rw-r--r--src/HTTP/UrlParser.cpp11
-rw-r--r--src/HTTP/UrlParser.h3
-rw-r--r--src/OSSupport/Network.h3
-rw-r--r--src/OSSupport/TCPLinkImpl.cpp5
-rw-r--r--src/OSSupport/TCPLinkImpl.h3
-rw-r--r--src/Protocol/Authenticator.cpp136
-rw-r--r--src/Protocol/Authenticator.h4
-rw-r--r--src/Protocol/MojangAPI.cpp276
-rw-r--r--src/Protocol/MojangAPI.h11
-rw-r--r--src/mbedTLS++/CMakeLists.txt1
-rw-r--r--src/mbedTLS++/RootCA.h97
-rw-r--r--src/mbedTLS++/SslConfig.cpp14
-rw-r--r--src/mbedTLS++/SslContext.cpp4
-rw-r--r--src/mbedTLS++/SslContext.h2
-rw-r--r--tests/HTTP/UrlClientTest.cpp4
18 files changed, 380 insertions, 379 deletions
diff --git a/src/Bindings/LuaTCPLink.cpp b/src/Bindings/LuaTCPLink.cpp
index 498691806..1e8f99410 100644
--- a/src/Bindings/LuaTCPLink.cpp
+++ b/src/Bindings/LuaTCPLink.cpp
@@ -192,7 +192,9 @@ AString cLuaTCPLink::StartTLSClient(
return fmt::format(FMT_STRING("Cannot parse client private key: -0x{:x}"), -res);
}
}
- return link->StartTLSClient(ownCert, ownPrivKey);
+
+ // TODO : Provide a way to pass SNI from Lua too.
+ return link->StartTLSClient(ownCert, ownPrivKey, "");
}
return "";
}
diff --git a/src/HTTP/UrlClient.cpp b/src/HTTP/UrlClient.cpp
index 13a882205..3985e0707 100644
--- a/src/HTTP/UrlClient.cpp
+++ b/src/HTTP/UrlClient.cpp
@@ -4,11 +4,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"
@@ -16,7 +17,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;
+ };
+}
@@ -261,7 +299,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
{
@@ -371,7 +409,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));
}
@@ -613,12 +651,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)
);
}
@@ -629,13 +667,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)
);
}
@@ -647,12 +685,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)
);
}
@@ -664,12 +702,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)
);
}
@@ -677,3 +715,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));
+}
+
+
+
+
+
diff --git a/src/HTTP/UrlClient.h b/src/HTTP/UrlClient.h
index 5f737b057..aaff60a87 100644
--- a/src/HTTP/UrlClient.h
+++ b/src/HTTP/UrlClient.h
@@ -86,7 +86,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. */
@@ -115,7 +115,7 @@ public:
const AString & a_URL,
cCallbacksPtr && a_Callbacks,
AStringMap && a_Headers,
- AString && a_Body,
+ const AString & a_Body,
AStringMap && a_Options
);
@@ -123,9 +123,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", ...) */
@@ -133,7 +133,7 @@ public:
const AString & a_URL,
cCallbacksPtr && a_Callbacks,
AStringMap && a_Headers,
- AString && a_Body,
+ const AString & a_Body,
AStringMap && a_Options
);
@@ -142,7 +142,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
);
};
diff --git a/src/HTTP/UrlParser.cpp b/src/HTTP/UrlParser.cpp
index 85b1cd216..f89aaad45 100644
--- a/src/HTTP/UrlParser.cpp
+++ b/src/HTTP/UrlParser.cpp
@@ -4,6 +4,7 @@
// Implements the cUrlParser class that parses string URL into individual parts
#include "Globals.h"
+
#include "UrlParser.h"
@@ -198,3 +199,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);
+}
+
+
+
+
diff --git a/src/HTTP/UrlParser.h b/src/HTTP/UrlParser.h
index 15a63e05d..76018460a 100644
--- a/src/HTTP/UrlParser.h
+++ b/src/HTTP/UrlParser.h
@@ -51,6 +51,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);
};
diff --git a/src/OSSupport/Network.h b/src/OSSupport/Network.h
index 32163b710..32c7ecdd0 100644
--- a/src/OSSupport/Network.h
+++ b/src/OSSupport/Network.h
@@ -113,7 +113,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.
diff --git a/src/OSSupport/TCPLinkImpl.cpp b/src/OSSupport/TCPLinkImpl.cpp
index c93a1879d..86fa24a63 100644
--- a/src/OSSupport/TCPLinkImpl.cpp
+++ b/src/OSSupport/TCPLinkImpl.cpp
@@ -237,7 +237,8 @@ void cTCPLinkImpl::Close(void)
AString cTCPLinkImpl::StartTLSClient(
cX509CertPtr a_OwnCert,
- cCryptoKeyPtr a_OwnPrivKey
+ cCryptoKeyPtr a_OwnPrivKey,
+ const std::string_view hostname
)
{
// Check preconditions:
@@ -263,6 +264,8 @@ AString cTCPLinkImpl::StartTLSClient(
m_TlsContext->Initialize(true);
}
+ m_TlsContext->SetExpectedPeerName(hostname);
+
m_TlsContext->SetSelf(cLinkTlsContextWPtr(m_TlsContext));
// Start the handshake:
diff --git a/src/OSSupport/TCPLinkImpl.h b/src/OSSupport/TCPLinkImpl.h
index 4b8c6f308..d26b1e358 100644
--- a/src/OSSupport/TCPLinkImpl.h
+++ b/src/OSSupport/TCPLinkImpl.h
@@ -68,7 +68,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,
diff --git a/src/Protocol/Authenticator.cpp b/src/Protocol/Authenticator.cpp
index b0669a354..00b09c30d 100644
--- a/src/Protocol/Authenticator.cpp
+++ b/src/Protocol/Authenticator.cpp
@@ -1,25 +1,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 "../IniFile.h"
-#include "../JsonUtils.h"
-#include "json/json.h"
+#include "Protocol/Authenticator.h"
-#include "../mbedTLS++/BlockingSslClientSocket.h"
+#include "ClientHandle.h"
+#include "HTTP/UrlClient.h"
+#include "HTTP/UrlParser.h"
+#include "IniFile.h"
+#include "JsonUtils.h"
+#include "json/json.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%";
@@ -51,6 +51,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;
+ }
+ }
}
@@ -143,7 +173,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());
@@ -152,39 +182,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())
{
@@ -193,14 +197,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;
}
@@ -212,9 +216,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%"
@@ -225,42 +229,12 @@ 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))
- {
- 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)
+ // Create and send the HTTP request
+ auto [IsSuccessfull, Response] = cUrlClient::BlockingGet(m_Server + ActualAddress);
+ if (!IsSuccessfull)
{
- 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())
@@ -279,7 +253,7 @@ bool cAuthenticator::GetPlayerProperties(const AString & a_UUID, Json::Value & a
a_Properties = root["properties"];
return true;
}
-*/
+#endif
diff --git a/src/Protocol/Authenticator.h b/src/Protocol/Authenticator.h
index 66dcf20b4..1987de8b3 100644
--- a/src/Protocol/Authenticator.h
+++ b/src/Protocol/Authenticator.h
@@ -66,7 +66,7 @@ private:
}
};
- typedef std::deque<cUser> cUserList;
+ using cUserList = std::deque<cUser>;
cCriticalSection m_CS;
cUserList m_Queue;
@@ -89,7 +89,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;
};
diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp
index 6cedf66d2..37c1b0911 100644
--- a/src/Protocol/MojangAPI.cpp
+++ b/src/Protocol/MojangAPI.cpp
@@ -5,17 +5,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"
-
@@ -30,122 +31,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";
@@ -188,8 +77,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;
}
@@ -432,61 +320,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
@@ -641,7 +474,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);
@@ -650,43 +484,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;
@@ -762,49 +566,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;
}
@@ -891,7 +669,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)
{
diff --git a/src/Protocol/MojangAPI.h b/src/Protocol/MojangAPI.h
index 4d1751f1c..f9267fefe 100644
--- a/src/Protocol/MojangAPI.h
+++ b/src/Protocol/MojangAPI.h
@@ -11,7 +11,7 @@
#include <time.h>
-#include "../UUID.h"
+#include "UUID.h"
@@ -42,11 +42,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.
@@ -131,8 +126,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". */
diff --git a/src/mbedTLS++/CMakeLists.txt b/src/mbedTLS++/CMakeLists.txt
index 42e0fc8b2..dcb5d23a0 100644
--- a/src/mbedTLS++/CMakeLists.txt
+++ b/src/mbedTLS++/CMakeLists.txt
@@ -25,6 +25,7 @@ target_sources(
EntropyContext.h
ErrorCodes.h
RsaPrivateKey.h
+ RootCA.h
SslConfig.h
SslContext.h
Sha1Checksum.h
diff --git a/src/mbedTLS++/RootCA.h b/src/mbedTLS++/RootCA.h
new file mode 100644
index 000000000..3e0d654bd
--- /dev/null
+++ b/src/mbedTLS++/RootCA.h
@@ -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;
+}
diff --git a/src/mbedTLS++/SslConfig.cpp b/src/mbedTLS++/SslConfig.cpp
index 8ea850c9f..054d63980 100644
--- a/src/mbedTLS++/SslConfig.cpp
+++ b/src/mbedTLS++/SslConfig.cpp
@@ -1,11 +1,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,
@@ -225,7 +225,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);
@@ -236,7 +235,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
diff --git a/src/mbedTLS++/SslContext.cpp b/src/mbedTLS++/SslContext.cpp
index 4847e9322..83bb1955e 100644
--- a/src/mbedTLS++/SslContext.cpp
+++ b/src/mbedTLS++/SslContext.cpp
@@ -82,10 +82,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());
}
diff --git a/src/mbedTLS++/SslContext.h b/src/mbedTLS++/SslContext.h
index 033749bf3..6343f7e43 100644
--- a/src/mbedTLS++/SslContext.h
+++ b/src/mbedTLS++/SslContext.h
@@ -54,7 +54,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.
diff --git a/tests/HTTP/UrlClientTest.cpp b/tests/HTTP/UrlClientTest.cpp
index 17f98ab70..41d61152e 100644
--- a/tests/HTTP/UrlClientTest.cpp
+++ b/tests/HTTP/UrlClientTest.cpp
@@ -117,7 +117,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();
@@ -163,7 +163,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();