Some more authentication stuff.

This commit is contained in:
momo5502 2016-02-22 13:37:13 +01:00
parent 99af8fbae7
commit 00b7e3f920
7 changed files with 48 additions and 14 deletions

View File

@ -103,7 +103,7 @@ workspace "iw4x"
-- Pre-compiled header -- Pre-compiled header
pchheader "STDInclude.hpp" -- must be exactly same as used in #include directives pchheader "STDInclude.hpp" -- must be exactly same as used in #include directives
pchsource "src/STDInclude.cpp" -- real path pchsource "src/STDInclude.cpp" -- real path
buildoptions { "/Zm100 -Zm100" } buildoptions { "/Zm96 -Zm96" }
filter "files:**.pb.*" filter "files:**.pb.*"
flags { flags {
"NoPCH", "NoPCH",

View File

@ -24,13 +24,13 @@ namespace Components
// Not sending a response might allow the player to connect for a few seconds (<= 5) until the timeout is reached. // Not sending a response might allow the player to connect for a few seconds (<= 5) until the timeout is reached.
if (client->state >= 5) if (client->state >= 5)
{ {
if (info->state == Auth::STATE_NEGOTIATING && (Game::Com_Milliseconds() - info->time) > 1000 * 3) if (info->state == Auth::STATE_NEGOTIATING && (Game::Com_Milliseconds() - info->time) > 1000 * 5)
{ {
info->state = Auth::STATE_INVALID; info->state = Auth::STATE_INVALID;
info->time = Game::Com_Milliseconds(); info->time = Game::Com_Milliseconds();
Game::SV_KickClientError(client, "XUID verification timed out!"); Game::SV_KickClientError(client, "XUID verification timed out!");
} }
else if (info->state == Auth::STATE_UNKNOWN && info->time && (Game::Com_Milliseconds() - info->time) > 1000 * 2) // Wait 2 seconds (error delay) else if (info->state == Auth::STATE_UNKNOWN && info->time && (Game::Com_Milliseconds() - info->time) > 1000 * 5) // Wait 5 seconds (error delay)
{ {
Logger::Print("Sending XUID authentication request to %s\n", Network::Address(client->adr).GetString()); Logger::Print("Sending XUID authentication request to %s\n", Network::Address(client->adr).GetString());
@ -90,6 +90,9 @@ namespace Components
// Only accept requests from the server we're connected to // Only accept requests from the server we're connected to
if (address != *Game::connectedHost) return; if (address != *Game::connectedHost) return;
// Ensure our certificate is loaded
Steam::SteamUser()->GetSteamID();
if (!Steam::User::GuidKey.IsValid()) return; if (!Steam::User::GuidKey.IsValid()) return;
Proto::Auth::Response response; Proto::Auth::Response response;
@ -104,12 +107,6 @@ namespace Components
{ {
Logger::Print("Received XUID authentication response from %s\n", address.GetString()); Logger::Print("Received XUID authentication response from %s\n", address.GetString());
Proto::Auth::Response response;
response.ParseFromString(data);
if (response.signature().empty()) return;
if (response.publickey().empty()) return;
for (int i = 0; i < *Game::svs_numclients; i++) for (int i = 0; i < *Game::svs_numclients; i++)
{ {
Game::client_t* client = &Game::svs_clients[i]; Game::client_t* client = &Game::svs_clients[i];
@ -117,14 +114,24 @@ namespace Components
if (client->state >= 3 && address == client->adr && info->state == Auth::STATE_NEGOTIATING) if (client->state >= 3 && address == client->adr && info->state == Auth::STATE_NEGOTIATING)
{ {
Proto::Auth::Response response;
unsigned int id = static_cast<unsigned int>(~0x110000100000000 & client->steamid); unsigned int id = static_cast<unsigned int>(~0x110000100000000 & client->steamid);
// Check if response is valid
if (!response.ParseFromString(data) || response.signature().empty() || response.publickey().empty())
{
info->state = Auth::STATE_INVALID;
Game::SV_KickClientError(client, "XUID authentication response was invalid!");
}
// Check if guid matches the certificate // Check if guid matches the certificate
if (id != (Utils::OneAtATime(response.publickey().data(), response.publickey().size()) & ~0x80000000)) else if (id != (Utils::OneAtATime(response.publickey().data(), response.publickey().size()) & ~0x80000000))
{ {
info->state = Auth::STATE_INVALID; info->state = Auth::STATE_INVALID;
Game::SV_KickClientError(client, "XUID doesn't match the certificate!"); Game::SV_KickClientError(client, "XUID doesn't match the certificate!");
} }
// Verify GUID using the signature and certificate
else else
{ {
info->publicKey.Set(response.publickey()); info->publicKey.Set(response.publickey());
@ -140,6 +147,8 @@ namespace Components
Game::SV_KickClientError(client, "Challenge signature was invalid!"); Game::SV_KickClientError(client, "Challenge signature was invalid!");
} }
} }
break;
} }
} }
}); });

View File

@ -7,3 +7,9 @@ message Response
bytes signature = 1; bytes signature = 1;
bytes publickey = 2; bytes publickey = 2;
} }
message Certificate
{
bytes privatekey = 1;
bytes token = 2;
}

View File

@ -2,6 +2,7 @@
namespace Steam namespace Steam
{ {
::Utils::Cryptography::Token User::GuidToken;
::Utils::Cryptography::ECDSA::Key User::GuidKey; ::Utils::Cryptography::ECDSA::Key User::GuidKey;
int User::GetHSteamUser() int User::GetHSteamUser()
@ -30,12 +31,23 @@ namespace Steam
{ {
if (!User::GuidKey.IsValid()) if (!User::GuidKey.IsValid())
{ {
User::GuidKey.Import(::Utils::ReadFile("players/guid.dat"), PK_PRIVATE); Proto::Auth::Certificate cert;
if (cert.ParseFromString(::Utils::ReadFile("players/guid.dat")))
{
User::GuidKey.Import(cert.privatekey(), PK_PRIVATE);
User::GuidToken = cert.token();
}
if (!User::GuidKey.IsValid()) if (!User::GuidKey.IsValid())
{ {
User::GuidToken.Clear();
User::GuidKey = ::Utils::Cryptography::ECDSA::GenerateKey(512); User::GuidKey = ::Utils::Cryptography::ECDSA::GenerateKey(512);
::Utils::WriteFile("players/guid.dat", User::GuidKey.Export(PK_PRIVATE));
cert.set_token(User::GuidToken.ToString());
cert.set_privatekey(User::GuidKey.Export(PK_PRIVATE));
::Utils::WriteFile("players/guid.dat", cert.SerializeAsString());
} }
} }

View File

@ -21,6 +21,7 @@ namespace Steam
virtual void CancelAuthTicket(unsigned int hAuthTicket); virtual void CancelAuthTicket(unsigned int hAuthTicket);
virtual unsigned int UserHasLicenseForApp(SteamID steamID, unsigned int appID); virtual unsigned int UserHasLicenseForApp(SteamID steamID, unsigned int appID);
static ::Utils::Cryptography::Token GuidToken;
static ::Utils::Cryptography::ECDSA::Key GuidKey; static ::Utils::Cryptography::ECDSA::Key GuidKey;
}; };
} }

View File

@ -19,6 +19,7 @@ namespace Utils
void Rand::Initialize() void Rand::Initialize()
{ {
ltc_mp = ltm_desc;
register_prng(&fortuna_desc); register_prng(&fortuna_desc);
rng_make_prng(128, find_prng("fortuna"), &Rand::State, NULL); rng_make_prng(128, find_prng("fortuna"), &Rand::State, NULL);
} }

View File

@ -6,6 +6,7 @@ namespace Utils
{ {
public: public:
Token() { this->TokenString.clear(); }; Token() { this->TokenString.clear(); };
Token(const Token& obj) : TokenString(obj.TokenString) { };
Token(std::string token) : TokenString(token.begin(), token.end()) { }; Token(std::string token) : TokenString(token.begin(), token.end()) { };
Token(std::basic_string<uint8_t> token) : TokenString(token.begin(), token.end()) { }; Token(std::basic_string<uint8_t> token) : TokenString(token.begin(), token.end()) { };
@ -50,8 +51,7 @@ namespace Utils
std::string ToString() std::string ToString()
{ {
auto str = this->ToUnsignedString(); return std::string(this->TokenString.begin(), this->TokenString.end());
return std::string(str.begin(), str.end());
} }
std::basic_string<uint8_t> ToUnsignedString() std::basic_string<uint8_t> ToUnsignedString()
@ -59,6 +59,11 @@ namespace Utils
return this->TokenString; return this->TokenString;
} }
void Clear()
{
this->TokenString.clear();
}
private: private:
std::basic_string<uint8_t> TokenString; std::basic_string<uint8_t> TokenString;
}; };