Some more authentication stuff.
This commit is contained in:
parent
99af8fbae7
commit
00b7e3f920
@ -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",
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user