1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-24 00:03:11 +01:00

Make sure the challenge token is random and handled properly

This change also fixes passworded servers not working properly, as
strlen() was getting called on something that was not guaranteed to be
null-terminated string when signing the token.
This commit is contained in:
Michał Janiszewski
2016-05-22 11:29:22 +02:00
parent 66abc31fee
commit 4ffceafdbb
4 changed files with 20 additions and 15 deletions

View File

@@ -333,7 +333,7 @@ std::string NetworkKey::PublicKeyHash()
return digest_out;
}
bool NetworkKey::Sign(const char * md, const size_t len, char ** signature, size_t * out_size)
bool NetworkKey::Sign(const uint8_t *md, const size_t len, char ** signature, size_t * out_size)
{
EVP_MD_CTX * mdctx = nullptr;
@@ -393,7 +393,7 @@ bool NetworkKey::Sign(const char * md, const size_t len, char ** signature, size
return true;
}
bool NetworkKey::Verify(const char * md, const size_t len, const char * sig, const size_t siglen)
bool NetworkKey::Verify(const uint8_t * md, const size_t len, const char * sig, const size_t siglen)
{
EVP_MD_CTX * mdctx = NULL;

View File

@@ -38,8 +38,8 @@ public:
std::string PublicKeyString();
std::string PublicKeyHash();
void Unload();
bool Sign(const char * md, const size_t len, char ** signature, size_t * out_size);
bool Verify(const char * md, const size_t len, const char * sig, const size_t siglen);
bool Sign(const uint8_t * md, const size_t len, char ** signature, size_t * out_size);
bool Verify(const uint8_t *md, const size_t len, const char * sig, const size_t siglen);
private:
NetworkKey ( const NetworkKey & ) = delete;
EVP_PKEY_CTX * m_ctx = nullptr;

View File

@@ -1480,7 +1480,7 @@ void Network::Server_Send_TOKEN(NetworkConnection& connection)
{
std::unique_ptr<NetworkPacket> packet = std::move(NetworkPacket::Allocate());
*packet << (uint32)NETWORK_COMMAND_TOKEN << (uint32)connection.challenge.size();
packet->Write((const uint8 *)connection.challenge.c_str(), connection.challenge.size());
packet->Write(connection.challenge.data(), connection.challenge.size());
connection.QueuePacket(std::move(packet));
}
@@ -1889,7 +1889,9 @@ void Network::Client_Handle_TOKEN(NetworkConnection& connection, NetworkPacket&
size_t sigsize;
char *signature;
const std::string pubkey = key.PublicKeyString();
ok = key.Sign(challenge, challenge_size, &signature, &sigsize);
this->challenge.resize(challenge_size);
memcpy(this->challenge.data(), challenge, challenge_size);
ok = key.Sign(this->challenge.data(), this->challenge.size(), &signature, &sigsize);
if (!ok) {
log_error("Failed to sign server's challenge.");
connection.setLastDisconnectReason(STR_MULTIPLAYER_VERIFICATION_FAILURE);
@@ -1955,8 +1957,11 @@ void Network::Server_Client_Joined(const char* name, const std::string &keyhash,
void Network::Server_Handle_TOKEN(NetworkConnection& connection, NetworkPacket& packet)
{
// TODO: add some randomness here
connection.challenge = "test";
uint8 token_size = 10 + (rand() & 0x7f);
connection.challenge.resize(token_size);
for (int i = 0; i < token_size; i++) {
connection.challenge[i] = (uint8)(rand() & 0xff);
}
Server_Send_TOKEN(connection);
}
@@ -1976,7 +1981,7 @@ void Network::Server_Handle_AUTH(NetworkConnection& connection, NetworkPacket& p
SDL_RWops *pubkey_rw = SDL_RWFromConstMem(pubkey, strlen(pubkey));
connection.key.LoadPublic(pubkey_rw);
SDL_RWclose(pubkey_rw);
bool verified = connection.key.Verify(connection.challenge.c_str(), connection.challenge.size(), signature, sigsize);
bool verified = connection.key.Verify(connection.challenge.data(), connection.challenge.size(), signature, sigsize);
if (verified) {
connection.authstatus = NETWORK_AUTH_VERIFIED;
const std::string hash = connection.key.PublicKeyHash();
@@ -2007,8 +2012,9 @@ void Network::Server_Handle_AUTH(NetworkConnection& connection, NetworkPacket& p
connection.authstatus = NETWORK_AUTH_OK;
const std::string hash = connection.key.PublicKeyHash();
Server_Client_Joined(name, hash, connection);
} else {
log_error("Unkown failure while authenticating client");
} else
if (!connection.authstatus != NETWORK_AUTH_REQUIREPASSWORD) {
log_error("Unkown failure (%d) while authenticating client", connection.authstatus);
}
Server_Send_AUTH(connection);
}
@@ -2720,7 +2726,6 @@ void network_send_gamecmd(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32
void network_send_password(const char* password)
{
log_warning("client name: %s", gConfigNetwork.player_name);
char path[MAX_PATH];
platform_get_user_directory(path, NULL);
char keyPath[MAX_PATH] = "";
@@ -2736,7 +2741,7 @@ void network_send_password(const char* password)
const std::string pubkey = gNetwork.key.PublicKeyString();
size_t sigsize;
char *signature;
bool ok = gNetwork.key.Sign(gNetwork.challenge.c_str(), gNetwork.challenge.size(), &signature, &sigsize);
bool ok = gNetwork.key.Sign(gNetwork.challenge.data(), gNetwork.challenge.size(), &signature, &sigsize);
// Don't keep private key in memory. There's no need and it may get leaked
// when process dump gets collected at some point in future.
gNetwork.key.Unload();

View File

@@ -301,7 +301,7 @@ public:
NetworkPlayer* player;
uint32 ping_time = 0;
NetworkKey key;
std::string challenge;
std::vector<uint8> challenge;
private:
char* last_disconnect_reason;
@@ -399,7 +399,7 @@ public:
std::vector<std::unique_ptr<NetworkPlayer>> player_list;
std::vector<std::unique_ptr<NetworkGroup>> group_list;
NetworkKey key;
std::string challenge;
std::vector<uint8> challenge;
std::map<std::string, uint8> key_group_map;
private: