diff --git a/premake5.lua b/premake5.lua index b5d12f96..55fe755c 100644 --- a/premake5.lua +++ b/premake5.lua @@ -103,7 +103,7 @@ workspace "iw4x" -- Pre-compiled header pchheader "STDInclude.hpp" -- must be exactly same as used in #include directives pchsource "src/STDInclude.cpp" -- real path - buildoptions { "/Zm100 -Zm100" } + buildoptions { "/Zm96 -Zm96" } filter "files:**.pb.*" flags { "NoPCH", diff --git a/src/Components/Modules/Auth.cpp b/src/Components/Modules/Auth.cpp index 7b323f35..a1ef2b97 100644 --- a/src/Components/Modules/Auth.cpp +++ b/src/Components/Modules/Auth.cpp @@ -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. 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->time = Game::Com_Milliseconds(); 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()); @@ -90,6 +90,9 @@ namespace Components // Only accept requests from the server we're connected to if (address != *Game::connectedHost) return; + + // Ensure our certificate is loaded + Steam::SteamUser()->GetSteamID(); if (!Steam::User::GuidKey.IsValid()) return; Proto::Auth::Response response; @@ -104,12 +107,6 @@ namespace Components { 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++) { 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) { + Proto::Auth::Response response; unsigned int id = static_cast(~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 - 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; Game::SV_KickClientError(client, "XUID doesn't match the certificate!"); } + + // Verify GUID using the signature and certificate else { info->publicKey.Set(response.publickey()); @@ -140,6 +147,8 @@ namespace Components Game::SV_KickClientError(client, "Challenge signature was invalid!"); } } + + break; } } }); diff --git a/src/Proto/auth.proto b/src/Proto/auth.proto index 375c1a0f..dc1acdb7 100644 --- a/src/Proto/auth.proto +++ b/src/Proto/auth.proto @@ -7,3 +7,9 @@ message Response bytes signature = 1; bytes publickey = 2; } + +message Certificate +{ + bytes privatekey = 1; + bytes token = 2; +} diff --git a/src/Steam/Interfaces/SteamUser.cpp b/src/Steam/Interfaces/SteamUser.cpp index a8341f18..c1e1c8bf 100644 --- a/src/Steam/Interfaces/SteamUser.cpp +++ b/src/Steam/Interfaces/SteamUser.cpp @@ -2,6 +2,7 @@ namespace Steam { + ::Utils::Cryptography::Token User::GuidToken; ::Utils::Cryptography::ECDSA::Key User::GuidKey; int User::GetHSteamUser() @@ -30,12 +31,23 @@ namespace Steam { 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()) { + User::GuidToken.Clear(); 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()); } } diff --git a/src/Steam/Interfaces/SteamUser.hpp b/src/Steam/Interfaces/SteamUser.hpp index 187d3425..02cf487d 100644 --- a/src/Steam/Interfaces/SteamUser.hpp +++ b/src/Steam/Interfaces/SteamUser.hpp @@ -21,6 +21,7 @@ namespace Steam virtual void CancelAuthTicket(unsigned int hAuthTicket); virtual unsigned int UserHasLicenseForApp(SteamID steamID, unsigned int appID); + static ::Utils::Cryptography::Token GuidToken; static ::Utils::Cryptography::ECDSA::Key GuidKey; }; } diff --git a/src/Utils/Cryptography.cpp b/src/Utils/Cryptography.cpp index aabea0f4..3f8b6dba 100644 --- a/src/Utils/Cryptography.cpp +++ b/src/Utils/Cryptography.cpp @@ -19,6 +19,7 @@ namespace Utils void Rand::Initialize() { + ltc_mp = ltm_desc; register_prng(&fortuna_desc); rng_make_prng(128, find_prng("fortuna"), &Rand::State, NULL); } diff --git a/src/Utils/Cryptography.hpp b/src/Utils/Cryptography.hpp index 204e3731..0b5c8175 100644 --- a/src/Utils/Cryptography.hpp +++ b/src/Utils/Cryptography.hpp @@ -6,6 +6,7 @@ namespace Utils { public: Token() { this->TokenString.clear(); }; + Token(const Token& obj) : TokenString(obj.TokenString) { }; Token(std::string token) : TokenString(token.begin(), token.end()) { }; Token(std::basic_string token) : TokenString(token.begin(), token.end()) { }; @@ -50,8 +51,7 @@ namespace Utils std::string ToString() { - auto str = this->ToUnsignedString(); - return std::string(str.begin(), str.end()); + return std::string(this->TokenString.begin(), this->TokenString.end()); } std::basic_string ToUnsignedString() @@ -59,6 +59,11 @@ namespace Utils return this->TokenString; } + void Clear() + { + this->TokenString.clear(); + } + private: std::basic_string TokenString; };