cTCPLink and cUrlClient accept list of trusted root CAs for TLS.
This commit is contained in:
parent
c2e0344110
commit
97c49c6f29
@ -528,6 +528,10 @@ g_Server = nil
|
|||||||
Name = "OwnPrivateKeyPassword",
|
Name = "OwnPrivateKeyPassword",
|
||||||
Type = "string",
|
Type = "string",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name = "TrustedRootCAs",
|
||||||
|
Type = "string",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Returns =
|
Returns =
|
||||||
{
|
{
|
||||||
@ -541,7 +545,7 @@ g_Server = nil
|
|||||||
IsOptional = true,
|
IsOptional = true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Notes = "Starts a TLS handshake on the link, as a client side of the TLS. The Own___ parameters specify the client certificate and its corresponding private key and password; all three parameters are optional and no client certificate is presented to the remote peer if they are not used or all empty. Once the TLS handshake is started by this call, all incoming data is first decrypted before being sent to the OnReceivedData callback, and all outgoing data is queued until the TLS handshake completes, and then sent encrypted over the link. Returns true on success, nil and optional error message on immediate failure.<br/><b>NOTE:</b> The TLS support in the API is currently experimental and shouldn't be considered safe - there's no peer certificate verification and the error reporting is only basic.",
|
Notes = "Starts a TLS handshake on the link, as a client side of the TLS. The Own___ parameters specify the client certificate and its corresponding private key and password; all three parameters are optional and no client certificate is presented to the remote peer if they are not used or all empty. Once the TLS handshake is started by this call, all incoming data is first decrypted before being sent to the OnReceivedData callback, and all outgoing data is queued until the TLS handshake completes, and then sent encrypted over the link. Returns true on success, nil and optional error message on immediate failure.<br/>The TrustedRootCAs is a string containing all certificates that should be trusted, in PEM format, concatenated and separated by a newline.<b>NOTE:</b> If TrustedRootCAs is empty or nil, the server's certificate will NOT be verified, which is UNSAFE!",
|
||||||
},
|
},
|
||||||
StartTLSServer =
|
StartTLSServer =
|
||||||
{
|
{
|
||||||
@ -1123,6 +1127,7 @@ end
|
|||||||
<tr><td>OwnCert</td><td>The client certificate to use, if requested by the server. A string containing a PEM- or DER-encoded cert is expected.</td></tr>
|
<tr><td>OwnCert</td><td>The client certificate to use, if requested by the server. A string containing a PEM- or DER-encoded cert is expected.</td></tr>
|
||||||
<tr><td>OwnPrivKey</td><td>The private key appropriate for OwnCert. A string containing a PEM- or DER-encoded private key is expected.</td></tr>
|
<tr><td>OwnPrivKey</td><td>The private key appropriate for OwnCert. A string containing a PEM- or DER-encoded private key is expected.</td></tr>
|
||||||
<tr><td>OwnPrivKeyPassword</td><td>The password for OwnPrivKey. If not present or empty, no password is assumed.</td></tr>
|
<tr><td>OwnPrivKeyPassword</td><td>The password for OwnPrivKey. If not present or empty, no password is assumed.</td></tr>
|
||||||
|
<tr><td>TrustedRootCAs</td><td>The certificates of the Root CAs that are to be trusted, encoded in PEM format. Multiple certificates can be used by concatenating the certificates, separating them by newlines. If this option is not present or empty, the request will NOT check the server's certificate, which is UNSAFE!</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<p>
|
<p>
|
||||||
Redirection:
|
Redirection:
|
||||||
|
@ -166,7 +166,8 @@ void cLuaTCPLink::Close(void)
|
|||||||
AString cLuaTCPLink::StartTLSClient(
|
AString cLuaTCPLink::StartTLSClient(
|
||||||
const AString & a_OwnCertData,
|
const AString & a_OwnCertData,
|
||||||
const AString & a_OwnPrivKeyData,
|
const AString & a_OwnPrivKeyData,
|
||||||
const AString & a_OwnPrivKeyPassword
|
const AString & a_OwnPrivKeyPassword,
|
||||||
|
const AString & a_TrustedRootCAs
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
auto link = m_Link;
|
auto link = m_Link;
|
||||||
@ -193,7 +194,17 @@ AString cLuaTCPLink::StartTLSClient(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return link->StartTLSClient(ownCert, ownPrivKey);
|
cX509CertPtr trustedRootCAs;
|
||||||
|
if (!a_TrustedRootCAs.empty())
|
||||||
|
{
|
||||||
|
trustedRootCAs = std::make_shared<cX509Cert>();
|
||||||
|
auto res = trustedRootCAs->Parse(a_TrustedRootCAs.data(), a_TrustedRootCAs.size());
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
return fmt::format("Cannot parse trusted root CAs: {}", res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return link->StartTLSClient(ownCert, ownPrivKey, trustedRootCAs);
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -66,11 +66,13 @@ public:
|
|||||||
If a client certificate should be used for the connection, set the certificate into a_OwnCertData and
|
If a client certificate should be used for the connection, set the certificate into a_OwnCertData and
|
||||||
its corresponding private key to a_OwnPrivKeyData. If both are empty, no client cert is presented.
|
its corresponding private key to a_OwnPrivKeyData. If both are empty, no client cert is presented.
|
||||||
a_OwnPrivKeyPassword is the password to be used for decoding PrivKey, empty if not passworded.
|
a_OwnPrivKeyPassword is the password to be used for decoding PrivKey, empty if not passworded.
|
||||||
|
a_TrustedRootCAs is a \n-delimited concatenation of trusted root CAs' certificates in PEM format
|
||||||
Returns empty string on success, non-empty error description on failure. */
|
Returns empty string on success, non-empty error description on failure. */
|
||||||
AString StartTLSClient(
|
AString StartTLSClient(
|
||||||
const AString & a_OwnCertData,
|
const AString & a_OwnCertData,
|
||||||
const AString & a_OwnPrivKeyData,
|
const AString & a_OwnPrivKeyData,
|
||||||
const AString & a_OwnPrivKeyPassword
|
const AString & a_OwnPrivKeyPassword,
|
||||||
|
const AString & a_TrustedRootCAs
|
||||||
);
|
);
|
||||||
|
|
||||||
/** Starts a TLS handshake as a server connection.
|
/** Starts a TLS handshake as a server connection.
|
||||||
|
@ -546,7 +546,7 @@ static int tolua_cTCPLink_Shutdown(lua_State * L)
|
|||||||
static int tolua_cTCPLink_StartTLSClient(lua_State * L)
|
static int tolua_cTCPLink_StartTLSClient(lua_State * L)
|
||||||
{
|
{
|
||||||
// Function signature:
|
// Function signature:
|
||||||
// LinkInstance:StartTLSClient(OwnCert, OwnPrivKey, OwnPrivKeyPassword) -> [true] or [nil, ErrMsg]
|
// LinkInstance:StartTLSClient(OwnCert, OwnPrivKey, OwnPrivKeyPassword, TrustedRootCAs) -> [true] or [nil, ErrMsg]
|
||||||
|
|
||||||
// Get the link:
|
// Get the link:
|
||||||
cLuaState S(L);
|
cLuaState S(L);
|
||||||
@ -558,11 +558,11 @@ static int tolua_cTCPLink_StartTLSClient(lua_State * L)
|
|||||||
ASSERT(Link != nullptr); // Checked by CheckParamSelf()
|
ASSERT(Link != nullptr); // Checked by CheckParamSelf()
|
||||||
|
|
||||||
// Read the (optional) params:
|
// Read the (optional) params:
|
||||||
AString OwnCert, OwnPrivKey, OwnPrivKeyPassword;
|
AString OwnCert, OwnPrivKey, OwnPrivKeyPassword, TrustedRootCAs;
|
||||||
S.GetStackValues(2, OwnCert, OwnPrivKey, OwnPrivKeyPassword);
|
S.GetStackValues(2, OwnCert, OwnPrivKey, OwnPrivKeyPassword, cLuaState::cOptionalParam<std::string>(TrustedRootCAs));
|
||||||
|
|
||||||
// Start the TLS handshake:
|
// Start the TLS handshake:
|
||||||
AString res = Link->StartTLSClient(OwnCert, OwnPrivKey, OwnPrivKeyPassword);
|
AString res = Link->StartTLSClient(OwnCert, OwnPrivKey, OwnPrivKeyPassword, TrustedRootCAs);
|
||||||
if (!res.empty())
|
if (!res.empty())
|
||||||
{
|
{
|
||||||
S.Push(cLuaState::Nil, fmt::format(
|
S.Push(cLuaState::Nil, fmt::format(
|
||||||
|
@ -20,15 +20,18 @@ class cSchemeHandler;
|
|||||||
using cSchemeHandlerPtr = std::shared_ptr<cSchemeHandler>;
|
using cSchemeHandlerPtr = std::shared_ptr<cSchemeHandler>;
|
||||||
|
|
||||||
|
|
||||||
/** This is a basic set of callbacks to enable quick implementation of HTTP request. */
|
|
||||||
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
class cSimpleHTTPCallbacks :
|
/** Callbacks implementing the blocking UrlClient behavior. */
|
||||||
|
class cBlockingHTTPCallbacks :
|
||||||
public cUrlClient::cCallbacks
|
public cUrlClient::cCallbacks
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit cSimpleHTTPCallbacks(std::shared_ptr<cEvent> a_Event, AString & a_ResponseBody) :
|
explicit cBlockingHTTPCallbacks(std::shared_ptr<cEvent> a_Event, AString & a_ResponseBody) :
|
||||||
m_Event(std::move(a_Event)), m_ResponseBody(a_ResponseBody)
|
m_Event(std::move(a_Event)), m_ResponseBody(a_ResponseBody)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -73,13 +76,13 @@ public:
|
|||||||
cUrlClient::cCallbacksPtr && a_Callbacks,
|
cUrlClient::cCallbacksPtr && a_Callbacks,
|
||||||
AStringMap && a_Headers,
|
AStringMap && a_Headers,
|
||||||
const AString & a_Body,
|
const AString & a_Body,
|
||||||
AStringMap && a_Options
|
const AStringMap & a_Options
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Create a new instance of cUrlClientRequest, wrapped in a SharedPtr, so that it has a controlled lifetime.
|
// Create a new instance of cUrlClientRequest, wrapped in a SharedPtr, so that it has a controlled lifetime.
|
||||||
// Cannot use std::make_shared, because the constructor is not public
|
// Cannot use std::make_shared, because the constructor is not public
|
||||||
std::shared_ptr<cUrlClientRequest> ptr (new cUrlClientRequest(
|
std::shared_ptr<cUrlClientRequest> ptr (new cUrlClientRequest(
|
||||||
a_Method, a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, std::move(a_Options)
|
a_Method, a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, a_Options
|
||||||
));
|
));
|
||||||
return ptr->DoRequest(ptr);
|
return ptr->DoRequest(ptr);
|
||||||
}
|
}
|
||||||
@ -138,6 +141,24 @@ public:
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the parsed TrustedRootCAs from the options, or an empty pointer if the option is not set.
|
||||||
|
Throws a std::runtime_error if CAs are provided, but parsing them fails. */
|
||||||
|
cX509CertPtr GetTrustedRootCAs() const
|
||||||
|
{
|
||||||
|
auto itr = m_Options.find("TrustedRootCAs");
|
||||||
|
if (itr == m_Options.end())
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto Cert = std::make_shared<cX509Cert>();
|
||||||
|
auto Res = Cert->Parse(itr->second.data(), itr->second.size());
|
||||||
|
if (Res != 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(fmt::format("Failed to parse the TrustedRootCAs certificate: {}", Res));
|
||||||
|
}
|
||||||
|
return Cert;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/** Method to be used for the request */
|
/** Method to be used for the request */
|
||||||
@ -184,14 +205,14 @@ protected:
|
|||||||
cUrlClient::cCallbacksPtr && a_Callbacks,
|
cUrlClient::cCallbacksPtr && a_Callbacks,
|
||||||
AStringMap && a_Headers,
|
AStringMap && a_Headers,
|
||||||
const AString & a_Body,
|
const AString & a_Body,
|
||||||
AStringMap && a_Options
|
const AStringMap & a_Options
|
||||||
):
|
):
|
||||||
m_Method(a_Method),
|
m_Method(a_Method),
|
||||||
m_Url(a_Url),
|
m_Url(a_Url),
|
||||||
m_Callbacks(std::move(a_Callbacks)),
|
m_Callbacks(std::move(a_Callbacks)),
|
||||||
m_Headers(std::move(a_Headers)),
|
m_Headers(std::move(a_Headers)),
|
||||||
m_Body(a_Body),
|
m_Body(a_Body),
|
||||||
m_Options(std::move(a_Options))
|
m_Options(a_Options)
|
||||||
{
|
{
|
||||||
m_NumRemainingRedirects = GetStringMapInteger(m_Options, "MaxRedirects", 30);
|
m_NumRemainingRedirects = GetStringMapInteger(m_Options, "MaxRedirects", 30);
|
||||||
}
|
}
|
||||||
@ -299,7 +320,7 @@ public:
|
|||||||
m_Link = &a_Link;
|
m_Link = &a_Link;
|
||||||
if (m_IsTls)
|
if (m_IsTls)
|
||||||
{
|
{
|
||||||
m_Link->StartTLSClient(m_ParentRequest.GetOwnCert(), m_ParentRequest.GetOwnPrivKey());
|
m_Link->StartTLSClient(m_ParentRequest.GetOwnCert(), m_ParentRequest.GetOwnPrivKey(), m_ParentRequest.GetTrustedRootCAs());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -652,11 +673,11 @@ std::pair<bool, AString> cUrlClient::Request(
|
|||||||
cCallbacksPtr && a_Callbacks,
|
cCallbacksPtr && a_Callbacks,
|
||||||
AStringMap && a_Headers,
|
AStringMap && a_Headers,
|
||||||
const AString & a_Body,
|
const AString & a_Body,
|
||||||
AStringMap && a_Options
|
const AStringMap & a_Options
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return cUrlClientRequest::Request(
|
return cUrlClientRequest::Request(
|
||||||
a_Method, a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, std::move(a_Options)
|
a_Method, a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, a_Options
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -669,11 +690,11 @@ std::pair<bool, AString> cUrlClient::Get(
|
|||||||
cCallbacksPtr && a_Callbacks,
|
cCallbacksPtr && a_Callbacks,
|
||||||
AStringMap && a_Headers,
|
AStringMap && a_Headers,
|
||||||
const AString & a_Body,
|
const AString & a_Body,
|
||||||
AStringMap && a_Options
|
const AStringMap & a_Options
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return cUrlClientRequest::Request(
|
return cUrlClientRequest::Request(
|
||||||
"GET", a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, std::move(a_Options)
|
"GET", a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, a_Options
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -686,11 +707,11 @@ std::pair<bool, AString> cUrlClient::Post(
|
|||||||
cCallbacksPtr && a_Callbacks,
|
cCallbacksPtr && a_Callbacks,
|
||||||
AStringMap && a_Headers,
|
AStringMap && a_Headers,
|
||||||
const AString & a_Body,
|
const AString & a_Body,
|
||||||
AStringMap && a_Options
|
const AStringMap & a_Options
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return cUrlClientRequest::Request(
|
return cUrlClientRequest::Request(
|
||||||
"POST", a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, std::move(a_Options)
|
"POST", a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, a_Options
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -703,11 +724,11 @@ std::pair<bool, AString> cUrlClient::Put(
|
|||||||
cCallbacksPtr && a_Callbacks,
|
cCallbacksPtr && a_Callbacks,
|
||||||
AStringMap && a_Headers,
|
AStringMap && a_Headers,
|
||||||
const AString & a_Body,
|
const AString & a_Body,
|
||||||
AStringMap && a_Options
|
const AStringMap & a_Options
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return cUrlClientRequest::Request(
|
return cUrlClientRequest::Request(
|
||||||
"PUT", a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, std::move(a_Options)
|
"PUT", a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, a_Options
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -715,15 +736,24 @@ 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)
|
std::pair<bool, AString> cUrlClient::BlockingRequest(
|
||||||
|
const AString & a_Method,
|
||||||
|
const AString & a_URL,
|
||||||
|
AStringMap && a_Headers,
|
||||||
|
const AString & a_Body,
|
||||||
|
const AStringMap & a_Options
|
||||||
|
)
|
||||||
{
|
{
|
||||||
auto EvtFinished = std::make_shared<cEvent>();
|
auto EvtFinished = std::make_shared<cEvent>();
|
||||||
AString Response;
|
AString Response;
|
||||||
auto Callbacks = std::make_unique<cSimpleHTTPCallbacks>(EvtFinished, Response);
|
auto Callbacks = std::make_unique<cBlockingHTTPCallbacks>(EvtFinished, Response);
|
||||||
auto [Success, ErrorMessage] = cUrlClient::Request(a_Method, a_URL, std::move(Callbacks), std::move(a_Headers), a_Body, std::move(a_Options));
|
auto [Success, ErrorMessage] = cUrlClient::Request(a_Method, a_URL, std::move(Callbacks), std::move(a_Headers), a_Body, a_Options);
|
||||||
if (Success)
|
if (Success)
|
||||||
{
|
{
|
||||||
EvtFinished->Wait();
|
if (!EvtFinished->Wait(10000))
|
||||||
|
{
|
||||||
|
return std::make_pair(false, "Timeout");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -741,9 +771,10 @@ std::pair<bool, AString> cUrlClient::BlockingGet(
|
|||||||
const AString & a_URL,
|
const AString & a_URL,
|
||||||
AStringMap a_Headers,
|
AStringMap a_Headers,
|
||||||
const AString & a_Body,
|
const AString & a_Body,
|
||||||
AStringMap a_Options)
|
const AStringMap & a_Options
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return BlockingRequest("GET", a_URL, std::move(a_Headers), a_Body, std::move(a_Options));
|
return BlockingRequest("GET", a_URL, std::move(a_Headers), a_Body, a_Options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -754,9 +785,10 @@ std::pair<bool, AString> cUrlClient::BlockingPost(
|
|||||||
const AString & a_URL,
|
const AString & a_URL,
|
||||||
AStringMap && a_Headers,
|
AStringMap && a_Headers,
|
||||||
const AString & a_Body,
|
const AString & a_Body,
|
||||||
AStringMap && a_Options)
|
const AStringMap & a_Options
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return BlockingRequest("POST", a_URL, std::move(a_Headers), a_Body, std::move(a_Options));
|
return BlockingRequest("POST", a_URL, std::move(a_Headers), a_Body, a_Options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -767,9 +799,10 @@ std::pair<bool, AString> cUrlClient::BlockingPut(
|
|||||||
const AString & a_URL,
|
const AString & a_URL,
|
||||||
AStringMap && a_Headers,
|
AStringMap && a_Headers,
|
||||||
const AString & a_Body,
|
const AString & a_Body,
|
||||||
AStringMap && a_Options)
|
const AStringMap & a_Options
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return BlockingRequest("PUT", a_URL, std::move(a_Headers), a_Body, std::move(a_Options));
|
return BlockingRequest("PUT", a_URL, std::move(a_Headers), a_Body, a_Options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ Options that can be set via the Options parameter to the cUrlClient calls:
|
|||||||
"OwnCert": The client certificate to use, if requested by the server. Any string that can be parsed by cX509Cert.
|
"OwnCert": The client certificate to use, if requested by the server. Any string that can be parsed by cX509Cert.
|
||||||
"OwnPrivKey": The private key appropriate for OwnCert. Any string that can be parsed by cCryptoKey.
|
"OwnPrivKey": The private key appropriate for OwnCert. Any string that can be parsed by cCryptoKey.
|
||||||
"OwnPrivKeyPassword": The password for OwnPrivKey. If not present or empty, no password is assumed.
|
"OwnPrivKeyPassword": The password for OwnPrivKey. If not present or empty, no password is assumed.
|
||||||
|
"TrustedRootCAs": The trusted root CA certificates (\n-delimited concatenated PEM format) to be used for peer cert verification. If not present, peer cert is not verified.
|
||||||
|
|
||||||
Behavior:
|
Behavior:
|
||||||
- If a redirect is received, and redirection is allowed, the redirection is reported via OnRedirecting() callback
|
- If a redirect is received, and redirection is allowed, the redirection is reported via OnRedirecting() callback
|
||||||
@ -116,16 +117,16 @@ public:
|
|||||||
cCallbacksPtr && a_Callbacks,
|
cCallbacksPtr && a_Callbacks,
|
||||||
AStringMap && a_Headers,
|
AStringMap && a_Headers,
|
||||||
const AString & a_Body,
|
const AString & a_Body,
|
||||||
AStringMap && a_Options
|
const AStringMap & a_Options
|
||||||
);
|
);
|
||||||
|
|
||||||
/** Alias for Request("GET", ...) */
|
/** Alias for Request("GET", ...) */
|
||||||
static std::pair<bool, AString> Get(
|
static std::pair<bool, AString> Get(
|
||||||
const AString & a_URL,
|
const AString & a_URL,
|
||||||
cCallbacksPtr && a_Callbacks,
|
cCallbacksPtr && a_Callbacks,
|
||||||
AStringMap && a_Headers = AStringMap(),
|
AStringMap && a_Headers = {},
|
||||||
const AString & a_Body = AString(),
|
const AString & a_Body = {},
|
||||||
AStringMap && a_Options = AStringMap()
|
const AStringMap & a_Options = {}
|
||||||
);
|
);
|
||||||
|
|
||||||
/** Alias for Request("POST", ...) */
|
/** Alias for Request("POST", ...) */
|
||||||
@ -134,7 +135,7 @@ public:
|
|||||||
cCallbacksPtr && a_Callbacks,
|
cCallbacksPtr && a_Callbacks,
|
||||||
AStringMap && a_Headers,
|
AStringMap && a_Headers,
|
||||||
const AString & a_Body,
|
const AString & a_Body,
|
||||||
AStringMap && a_Options
|
const AStringMap & a_Options = {}
|
||||||
);
|
);
|
||||||
|
|
||||||
/** Alias for Request("PUT", ...) */
|
/** Alias for Request("PUT", ...) */
|
||||||
@ -143,7 +144,7 @@ public:
|
|||||||
cCallbacksPtr && a_Callbacks,
|
cCallbacksPtr && a_Callbacks,
|
||||||
AStringMap && a_Headers,
|
AStringMap && a_Headers,
|
||||||
const AString & a_Body,
|
const AString & a_Body,
|
||||||
AStringMap && a_Options
|
const AStringMap & a_Options = {}
|
||||||
);
|
);
|
||||||
|
|
||||||
/** The method will run a thread blocking HTTP request. Any error handling
|
/** The method will run a thread blocking HTTP request. Any error handling
|
||||||
@ -153,17 +154,17 @@ public:
|
|||||||
static std::pair<bool, AString> BlockingRequest(
|
static std::pair<bool, AString> BlockingRequest(
|
||||||
const AString & a_Method,
|
const AString & a_Method,
|
||||||
const AString & a_URL,
|
const AString & a_URL,
|
||||||
AStringMap && a_Headers = AStringMap(),
|
AStringMap && a_Headers = {},
|
||||||
const AString & a_Body = AString(),
|
const AString & a_Body = {},
|
||||||
AStringMap && a_Options = AStringMap()
|
const AStringMap & a_Options = {}
|
||||||
);
|
);
|
||||||
|
|
||||||
/** Alias for BlockingRequest("GET", ...) */
|
/** Alias for BlockingRequest("GET", ...) */
|
||||||
static std::pair<bool, AString> BlockingGet(
|
static std::pair<bool, AString> BlockingGet(
|
||||||
const AString & a_URL,
|
const AString & a_URL,
|
||||||
AStringMap a_Headers = AStringMap(),
|
AStringMap a_Headers = {},
|
||||||
const AString & a_Body = AString(),
|
const AString & a_Body = {},
|
||||||
AStringMap a_Options = AStringMap()
|
const AStringMap & a_Options = {}
|
||||||
);
|
);
|
||||||
|
|
||||||
/** Alias for BlockingRequest("POST", ...) */
|
/** Alias for BlockingRequest("POST", ...) */
|
||||||
@ -171,7 +172,7 @@ public:
|
|||||||
const AString & a_URL,
|
const AString & a_URL,
|
||||||
AStringMap && a_Headers,
|
AStringMap && a_Headers,
|
||||||
const AString & a_Body,
|
const AString & a_Body,
|
||||||
AStringMap && a_Options
|
const AStringMap & a_Options = {}
|
||||||
);
|
);
|
||||||
|
|
||||||
/** Alias for BlockingRequest("PUT", ...) */
|
/** Alias for BlockingRequest("PUT", ...) */
|
||||||
@ -179,7 +180,7 @@ public:
|
|||||||
const AString & a_URL,
|
const AString & a_URL,
|
||||||
AStringMap && a_Headers,
|
AStringMap && a_Headers,
|
||||||
const AString & a_Body,
|
const AString & a_Body,
|
||||||
AStringMap && a_Options
|
const AStringMap & a_Options = {}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -113,7 +113,8 @@ public:
|
|||||||
Returns empty string on success, non-empty error description on failure. */
|
Returns empty string on success, non-empty error description on failure. */
|
||||||
virtual AString StartTLSClient(
|
virtual AString StartTLSClient(
|
||||||
cX509CertPtr a_OwnCert,
|
cX509CertPtr a_OwnCert,
|
||||||
cCryptoKeyPtr a_OwnPrivKey
|
cCryptoKeyPtr a_OwnPrivKey,
|
||||||
|
cX509CertPtr a_TrustedRootCAs
|
||||||
) = 0;
|
) = 0;
|
||||||
|
|
||||||
/** Starts a TLS handshake as a server connection.
|
/** Starts a TLS handshake as a server connection.
|
||||||
|
@ -244,7 +244,8 @@ void cTCPLinkImpl::Close(void)
|
|||||||
|
|
||||||
AString cTCPLinkImpl::StartTLSClient(
|
AString cTCPLinkImpl::StartTLSClient(
|
||||||
cX509CertPtr a_OwnCert,
|
cX509CertPtr a_OwnCert,
|
||||||
cCryptoKeyPtr a_OwnPrivKey
|
cCryptoKeyPtr a_OwnPrivKey,
|
||||||
|
cX509CertPtr a_TrustedRootCAs
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Check preconditions:
|
// Check preconditions:
|
||||||
@ -259,15 +260,25 @@ AString cTCPLinkImpl::StartTLSClient(
|
|||||||
|
|
||||||
// Create the TLS context:
|
// Create the TLS context:
|
||||||
m_TlsContext = std::make_shared<cLinkTlsContext>(*this);
|
m_TlsContext = std::make_shared<cLinkTlsContext>(*this);
|
||||||
if (a_OwnCert != nullptr)
|
if ((a_OwnCert == nullptr) && (a_TrustedRootCAs == nullptr))
|
||||||
{
|
{
|
||||||
auto Config = cSslConfig::MakeDefaultConfig(true);
|
// Use the (shared) default TLS config
|
||||||
Config->SetOwnCert(std::move(a_OwnCert), std::move(a_OwnPrivKey));
|
m_TlsContext->Initialize(true);
|
||||||
m_TlsContext->Initialize(Config);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_TlsContext->Initialize(true);
|
// Need a specialized config for the own certificate / trusted root CAs:
|
||||||
|
auto Config = cSslConfig::MakeDefaultConfig(true);
|
||||||
|
if (a_OwnCert != nullptr)
|
||||||
|
{
|
||||||
|
Config->SetOwnCert(std::move(a_OwnCert), std::move(a_OwnPrivKey));
|
||||||
|
}
|
||||||
|
if (a_TrustedRootCAs != nullptr)
|
||||||
|
{
|
||||||
|
Config->SetAuthMode(eSslAuthMode::Required);
|
||||||
|
Config->SetCACerts(std::move(a_TrustedRootCAs));
|
||||||
|
}
|
||||||
|
m_TlsContext->Initialize(Config);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable SNI / peer name verification:
|
// Enable SNI / peer name verification:
|
||||||
|
@ -75,7 +75,8 @@ public:
|
|||||||
virtual void Close(void) override;
|
virtual void Close(void) override;
|
||||||
virtual AString StartTLSClient(
|
virtual AString StartTLSClient(
|
||||||
cX509CertPtr a_OwnCert,
|
cX509CertPtr a_OwnCert,
|
||||||
cCryptoKeyPtr a_OwnPrivKey
|
cCryptoKeyPtr a_OwnPrivKey,
|
||||||
|
cX509CertPtr a_TrustedRootCAs
|
||||||
) override;
|
) override;
|
||||||
virtual AString StartTLSServer(
|
virtual AString StartTLSServer(
|
||||||
cX509CertPtr a_OwnCert,
|
cX509CertPtr a_OwnCert,
|
||||||
|
@ -65,8 +65,8 @@ void cAuthenticator::ReadSettings(cSettingsRepositoryInterface & a_Settings)
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto [IsSuccessfull, ErrorMessage] = cUrlParser::Validate(m_Server);
|
auto [IsSuccessful, ErrorMessage] = cUrlParser::Validate(m_Server);
|
||||||
if (!IsSuccessfull)
|
if (!IsSuccessful)
|
||||||
{
|
{
|
||||||
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());
|
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;
|
m_Server = DEFAULT_AUTH_SERVER;
|
||||||
@ -74,8 +74,8 @@ void cAuthenticator::ReadSettings(cSettingsRepositoryInterface & a_Settings)
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto [IsSuccessfull, ErrorMessage] = cUrlParser::Validate(m_Server);
|
auto [IsSuccessful, ErrorMessage] = cUrlParser::Validate(m_Server);
|
||||||
if (!IsSuccessfull)
|
if (!IsSuccessful)
|
||||||
{
|
{
|
||||||
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());
|
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;
|
m_Address = DEFAULT_AUTH_ADDRESS;
|
||||||
@ -183,8 +183,8 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
|
|||||||
ReplaceURL(ActualAddress, "%SERVERID%", a_ServerId);
|
ReplaceURL(ActualAddress, "%SERVERID%", a_ServerId);
|
||||||
|
|
||||||
// Create and send the HTTP request
|
// Create and send the HTTP request
|
||||||
auto [IsSuccessfull, Response] = cUrlClient::BlockingGet(m_Server + ActualAddress);
|
auto [IsSuccessful, Response] = cUrlClient::BlockingGet(m_Server + ActualAddress);
|
||||||
if (!IsSuccessfull)
|
if (!IsSuccessful)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -230,8 +230,8 @@ bool cAuthenticator::GetPlayerProperties(const AString & a_UUID, Json::Value & a
|
|||||||
LOGD("Trying to get properties for user %s", a_UUID.c_str());
|
LOGD("Trying to get properties for user %s", a_UUID.c_str());
|
||||||
|
|
||||||
// Create and send the HTTP request
|
// Create and send the HTTP request
|
||||||
auto [IsSuccessfull, Response] = cUrlClient::BlockingGet(m_Server + ActualAddress);
|
auto [IsSuccessful, Response] = cUrlClient::BlockingGet(m_Server + ActualAddress);
|
||||||
if (!IsSuccessfull)
|
if (!IsSuccessful)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,99 @@ constexpr char DEFAULT_UUID_TO_PROFILE_ADDRESS[] = "/session/minecraft/profile/%
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace MojangTrustedRootCAs
|
||||||
|
{
|
||||||
|
/** Returns the Options that should be used for cUrlClient queries to the Mojang APIs. */
|
||||||
|
static const AStringMap & UrlClientOptions()
|
||||||
|
{
|
||||||
|
static const AString 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 const AStringMap UrlClientOptions = {{"TrustedRootCAs", CertString}};
|
||||||
|
return UrlClientOptions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cMojangAPI::sProfile:
|
// cMojangAPI::sProfile:
|
||||||
|
|
||||||
@ -143,11 +236,7 @@ protected:
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cMojangAPI:
|
// cMojangAPI:
|
||||||
|
|
||||||
cMojangAPI::cMojangAPI(void) :
|
cMojangAPI::cMojangAPI():
|
||||||
m_NameToUUIDServer(DEFAULT_NAME_TO_UUID_SERVER),
|
|
||||||
m_NameToUUIDAddress(DEFAULT_NAME_TO_UUID_ADDRESS),
|
|
||||||
m_UUIDToProfileServer(DEFAULT_UUID_TO_PROFILE_SERVER),
|
|
||||||
m_UUIDToProfileAddress(DEFAULT_UUID_TO_PROFILE_ADDRESS),
|
|
||||||
m_RankMgr(nullptr),
|
m_RankMgr(nullptr),
|
||||||
m_UpdateThread(new cUpdateThread(*this))
|
m_UpdateThread(new cUpdateThread(*this))
|
||||||
{
|
{
|
||||||
@ -168,10 +257,12 @@ cMojangAPI::~cMojangAPI()
|
|||||||
|
|
||||||
void cMojangAPI::Start(cSettingsRepositoryInterface & a_Settings, bool a_ShouldAuth)
|
void cMojangAPI::Start(cSettingsRepositoryInterface & a_Settings, bool a_ShouldAuth)
|
||||||
{
|
{
|
||||||
m_NameToUUIDServer = a_Settings.GetValueSet("MojangAPI", "NameToUUIDServer", DEFAULT_NAME_TO_UUID_SERVER);
|
auto NameToUUIDServer = a_Settings.GetValueSet("MojangAPI", "NameToUUIDServer", DEFAULT_NAME_TO_UUID_SERVER);
|
||||||
m_NameToUUIDAddress = a_Settings.GetValueSet("MojangAPI", "NameToUUIDAddress", DEFAULT_NAME_TO_UUID_ADDRESS);
|
auto NameToUUIDAddress = a_Settings.GetValueSet("MojangAPI", "NameToUUIDAddress", DEFAULT_NAME_TO_UUID_ADDRESS);
|
||||||
m_UUIDToProfileServer = a_Settings.GetValueSet("MojangAPI", "UUIDToProfileServer", DEFAULT_UUID_TO_PROFILE_SERVER);
|
auto UUIDToProfileServer = a_Settings.GetValueSet("MojangAPI", "UUIDToProfileServer", DEFAULT_UUID_TO_PROFILE_SERVER);
|
||||||
m_UUIDToProfileAddress = a_Settings.GetValueSet("MojangAPI", "UUIDToProfileAddress", DEFAULT_UUID_TO_PROFILE_ADDRESS);
|
auto UUIDToProfileAddress = a_Settings.GetValueSet("MojangAPI", "UUIDToProfileAddress", DEFAULT_UUID_TO_PROFILE_ADDRESS);
|
||||||
|
m_NameToUUIDUrl = "https://" + NameToUUIDServer + NameToUUIDAddress;
|
||||||
|
m_UUIDToProfileUrl = "https://" + UUIDToProfileServer + UUIDToProfileAddress;
|
||||||
LoadCachesFromDisk();
|
LoadCachesFromDisk();
|
||||||
if (a_ShouldAuth)
|
if (a_ShouldAuth)
|
||||||
{
|
{
|
||||||
@ -485,8 +576,8 @@ void cMojangAPI::QueryNamesToUUIDs(AStringVector & a_NamesToQuery)
|
|||||||
auto RequestBody = JsonUtils::WriteFastString(root);
|
auto RequestBody = JsonUtils::WriteFastString(root);
|
||||||
|
|
||||||
// Create and send the HTTP request
|
// Create and send the HTTP request
|
||||||
auto [IsSuccessfull, Response] = cUrlClient::BlockingPost(m_NameToUUIDAddress, AStringMap(), std::move(RequestBody), AStringMap());
|
auto [IsSuccessful, Response] = cUrlClient::BlockingPost(m_NameToUUIDUrl, {}, std::move(RequestBody), MojangTrustedRootCAs::UrlClientOptions());
|
||||||
if (!IsSuccessfull)
|
if (!IsSuccessful)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -562,13 +653,11 @@ void cMojangAPI::CacheUUIDToProfile(const cUUID & a_UUID)
|
|||||||
|
|
||||||
void cMojangAPI::QueryUUIDToProfile(const cUUID & a_UUID)
|
void cMojangAPI::QueryUUIDToProfile(const cUUID & a_UUID)
|
||||||
{
|
{
|
||||||
// Create the request address:
|
|
||||||
AString Address = m_UUIDToProfileAddress;
|
|
||||||
ReplaceURL(Address, "%UUID%", a_UUID.ToShortString());
|
|
||||||
|
|
||||||
// Create and send the HTTP request
|
// Create and send the HTTP request
|
||||||
auto [IsSuccessfull, Response] = cUrlClient::BlockingGet(Address);
|
auto Url = m_UUIDToProfileUrl;
|
||||||
if (!IsSuccessfull)
|
ReplaceString(Url, "%UUID%", URLEncode(a_UUID.ToShortString()));
|
||||||
|
auto [IsSuccessful, Response] = cUrlClient::BlockingGet(Url, {}, {}, MojangTrustedRootCAs::UrlClientOptions());
|
||||||
|
if (!IsSuccessful)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -130,19 +130,14 @@ protected:
|
|||||||
using cUUIDProfileMap = std::map<cUUID, sProfile>;
|
using cUUIDProfileMap = std::map<cUUID, sProfile>;
|
||||||
|
|
||||||
|
|
||||||
/** The server to connect to when converting player names to UUIDs. For example "api.mojang.com". */
|
/** The full URL to check when converting player names to UUIDs.
|
||||||
AString m_NameToUUIDServer;
|
For example: "https://api.mojang.com/profiles/page/1". */
|
||||||
|
AString m_NameToUUIDUrl;
|
||||||
|
|
||||||
/** The URL to use for converting player names to UUIDs, without server part.
|
/** The full URL to use for converting UUID to profile.
|
||||||
For example "/profiles/page/1". */
|
%UUID% will get replaced with the actual UUID.
|
||||||
AString m_NameToUUIDAddress;
|
For example "https://sessionserver.mojang.com/session/minecraft/profile/%UUID%?unsigned=false". */
|
||||||
|
AString m_UUIDToProfileUrl;
|
||||||
/** The server to connect to when converting UUID to profile. For example "sessionserver.mojang.com". */
|
|
||||||
AString m_UUIDToProfileServer;
|
|
||||||
|
|
||||||
/** The URL to use for converting UUID to profile, without the server part.
|
|
||||||
Will replace %UUID% with the actual UUID. For example "session/minecraft/profile/%UUID%?unsigned=false". */
|
|
||||||
AString m_UUIDToProfileAddress;
|
|
||||||
|
|
||||||
/** Cache for the Name-to-UUID lookups. The map key is lowercased PlayerName. Protected by m_CSNameToUUID. */
|
/** Cache for the Name-to-UUID lookups. The map key is lowercased PlayerName. Protected by m_CSNameToUUID. */
|
||||||
cProfileMap m_NameToUUID;
|
cProfileMap m_NameToUUID;
|
||||||
|
@ -25,7 +25,6 @@ target_sources(
|
|||||||
EntropyContext.h
|
EntropyContext.h
|
||||||
ErrorCodes.h
|
ErrorCodes.h
|
||||||
RsaPrivateKey.h
|
RsaPrivateKey.h
|
||||||
RootCA.h
|
|
||||||
SslConfig.h
|
SslConfig.h
|
||||||
SslContext.h
|
SslContext.h
|
||||||
Sha1Checksum.h
|
Sha1Checksum.h
|
||||||
|
@ -1,97 +0,0 @@
|
|||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include "mbedTLS++/CryptoKey.h"
|
#include "mbedTLS++/CryptoKey.h"
|
||||||
#include "mbedTLS++/EntropyContext.h"
|
#include "mbedTLS++/EntropyContext.h"
|
||||||
#include "mbedTLS++/RootCA.h"
|
#include "mbedTLS++/X509Cert.h"
|
||||||
|
|
||||||
|
|
||||||
// This allows us to debug SSL and certificate problems, but produce way too much output,
|
// This allows us to debug SSL and certificate problems, but produce way too much output,
|
||||||
@ -235,8 +235,8 @@ std::shared_ptr<cSslConfig> cSslConfig::MakeDefaultConfig(bool a_IsClient)
|
|||||||
Ret->SetRng(std::move(CtrDrbg));
|
Ret->SetRng(std::move(CtrDrbg));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ret->SetAuthMode(eSslAuthMode::Required);
|
// By default we have no root CAs, so no cert verification can be done:
|
||||||
Ret->SetCACerts(GetCACerts());
|
Ret->SetAuthMode(eSslAuthMode::None);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#ifdef ENABLE_SSL_DEBUG_MSG
|
#ifdef ENABLE_SSL_DEBUG_MSG
|
||||||
|
Loading…
x
Reference in New Issue
Block a user