mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Merge pull request #160 from heinrich5991/pr_ddnet_random_windows
Make the secure random stuff platform-independent
This commit is contained in:
commit
1d061986d3
1
bam.lua
1
bam.lua
|
@ -240,6 +240,7 @@ function build(settings)
|
|||
settings.link.libs:Add("ws2_32")
|
||||
settings.link.libs:Add("ole32")
|
||||
settings.link.libs:Add("shell32")
|
||||
settings.link.libs:Add("advapi32")
|
||||
end
|
||||
|
||||
-- compile zlib if needed
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
#include <errno.h>
|
||||
#include <process.h>
|
||||
#include <shellapi.h>
|
||||
#include <wincrypt.h>
|
||||
#else
|
||||
#error NOT IMPLEMENTED
|
||||
#endif
|
||||
|
@ -2355,6 +2356,70 @@ void shell_execute(const char *file, const char *argv)
|
|||
#endif
|
||||
}
|
||||
|
||||
struct SECURE_RANDOM_DATA
|
||||
{
|
||||
int initialized;
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
HCRYPTPROV provider;
|
||||
#else
|
||||
IOHANDLE urandom;
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct SECURE_RANDOM_DATA secure_random_data = { 0 };
|
||||
|
||||
int secure_random_init()
|
||||
{
|
||||
if(secure_random_data.initialized)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
if(CryptAcquireContext(&secure_random_data.provider, NULL, NULL, PROV_RSA_FULL, 0))
|
||||
{
|
||||
secure_random_data.initialized = 1;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
secure_random_data.urandom = io_open("/dev/urandom", IOFLAG_READ);
|
||||
if(secure_random_data.urandom)
|
||||
{
|
||||
secure_random_data.initialized = 1;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void secure_random_fill(unsigned char *bytes, size_t length)
|
||||
{
|
||||
if(!secure_random_data.initialized)
|
||||
{
|
||||
dbg_msg("secure", "called secure_random_fill before secure_random_init");
|
||||
dbg_break();
|
||||
}
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
if(!CryptGenRandom(secure_random_data.provider, length, bytes))
|
||||
{
|
||||
dbg_msg("secure", "CryptGenRandom failed, last_error=%d", GetLastError());
|
||||
dbg_break();
|
||||
}
|
||||
#else
|
||||
if(length != io_read(secure_random_data.urandom, bytes, length))
|
||||
{
|
||||
dbg_msg("secure", "io_read returned with a short read");
|
||||
dbg_break();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1328,6 +1328,27 @@ int pid();
|
|||
|
||||
void shell_execute(const char *file, const char *argv);
|
||||
|
||||
/*
|
||||
Function: secure_random_init
|
||||
Initializes the secure random module.
|
||||
You *MUST* check the return value of this function.
|
||||
|
||||
Returns:
|
||||
0 - Initialization succeeded.
|
||||
1 - Initialization failed.
|
||||
*/
|
||||
int secure_random_init();
|
||||
|
||||
/*
|
||||
Function: secure_random_fill
|
||||
Fills the buffer with the specified amount of random bytes.
|
||||
|
||||
Parameters:
|
||||
buffer - Pointer to the start of the buffer.
|
||||
length - Length of the buffer.
|
||||
*/
|
||||
void secure_random_fill(unsigned char *bytes, size_t length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -101,7 +101,7 @@ void CNetBase::SendPacketConnless(NETSOCKET Socket, NETADDR *pAddr, const void *
|
|||
net_udp_send(Socket, pAddr, aBuffer, 6+DataSize);
|
||||
}
|
||||
|
||||
void CNetBase::SendPacket(NETSOCKET Socket, NETADDR *pAddr, CNetPacketConstruct *pPacket)
|
||||
void CNetBase::SendPacket(NETSOCKET Socket, NETADDR *pAddr, CNetPacketConstruct *pPacket, SECURITY_TOKEN SecurityToken)
|
||||
{
|
||||
unsigned char aBuffer[NET_MAX_PACKETSIZE];
|
||||
int CompressedSize = -1;
|
||||
|
@ -117,6 +117,14 @@ void CNetBase::SendPacket(NETSOCKET Socket, NETADDR *pAddr, CNetPacketConstruct
|
|||
io_flush(ms_DataLogSent);
|
||||
}
|
||||
|
||||
if (SecurityToken != NET_SECURITY_TOKEN_UNSUPPORTED)
|
||||
{
|
||||
// append security token
|
||||
// if SecurityToken is NET_SECURITY_TOKEN_UNKNOWN we will still append it hoping to negotiate it
|
||||
mem_copy(&pPacket->m_aChunkData[pPacket->m_DataSize], &SecurityToken, sizeof(SecurityToken));
|
||||
pPacket->m_DataSize += sizeof(SecurityToken);
|
||||
}
|
||||
|
||||
// compress
|
||||
CompressedSize = ms_Huffman.Compress(pPacket->m_aChunkData, pPacket->m_DataSize, &aBuffer[3], NET_MAX_PACKETSIZE-4);
|
||||
|
||||
|
@ -228,7 +236,7 @@ int CNetBase::UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct
|
|||
}
|
||||
|
||||
|
||||
void CNetBase::SendControlMsg(NETSOCKET Socket, NETADDR *pAddr, int Ack, int ControlMsg, const void *pExtra, int ExtraSize)
|
||||
void CNetBase::SendControlMsg(NETSOCKET Socket, NETADDR *pAddr, int Ack, int ControlMsg, const void *pExtra, int ExtraSize, SECURITY_TOKEN SecurityToken)
|
||||
{
|
||||
CNetPacketConstruct Construct;
|
||||
Construct.m_Flags = NET_PACKETFLAG_CONTROL;
|
||||
|
@ -239,7 +247,7 @@ void CNetBase::SendControlMsg(NETSOCKET Socket, NETADDR *pAddr, int Ack, int Con
|
|||
mem_copy(&Construct.m_aChunkData[1], pExtra, ExtraSize);
|
||||
|
||||
// send the control message
|
||||
CNetBase::SendPacket(Socket, pAddr, &Construct);
|
||||
CNetBase::SendPacket(Socket, pAddr, &Construct, SecurityToken);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -78,6 +78,15 @@ enum
|
|||
NET_ENUM_TERMINATOR
|
||||
};
|
||||
|
||||
typedef int SECURITY_TOKEN;
|
||||
|
||||
static const unsigned char SECURITY_TOKEN_MAGIC[] = {'T', 'K', 'E', 'N'};
|
||||
|
||||
enum
|
||||
{
|
||||
NET_SECURITY_TOKEN_UNKNOWN = -1,
|
||||
NET_SECURITY_TOKEN_UNSUPPORTED = 0,
|
||||
};
|
||||
|
||||
typedef int (*NETFUNC_DELCLIENT)(int ClientID, const char* pReason, void *pUser);
|
||||
typedef int (*NETFUNC_NEWCLIENT)(int ClientID, void *pUser);
|
||||
|
@ -139,6 +148,7 @@ private:
|
|||
unsigned m_State;
|
||||
|
||||
int m_Token;
|
||||
SECURITY_TOKEN m_SecurityToken;
|
||||
int m_RemoteClosed;
|
||||
bool m_BlockCloseMsg;
|
||||
|
||||
|
@ -178,7 +188,7 @@ public:
|
|||
int Update();
|
||||
int Flush();
|
||||
|
||||
int Feed(CNetPacketConstruct *pPacket, NETADDR *pAddr);
|
||||
int Feed(CNetPacketConstruct *pPacket, NETADDR *pAddr, SECURITY_TOKEN SecurityToken = NET_SECURITY_TOKEN_UNSUPPORTED);
|
||||
int QueueChunk(int Flags, int DataSize, const void *pData);
|
||||
|
||||
const char *ErrorString();
|
||||
|
@ -265,6 +275,8 @@ class CNetServer
|
|||
NETFUNC_DELCLIENT m_pfnDelClient;
|
||||
void *m_UserPtr;
|
||||
|
||||
unsigned char m_SecurityTokenSeed[16];
|
||||
|
||||
CNetRecvUnpacker m_RecvUnpacker;
|
||||
|
||||
public:
|
||||
|
@ -386,9 +398,9 @@ public:
|
|||
static int Compress(const void *pData, int DataSize, void *pOutput, int OutputSize);
|
||||
static int Decompress(const void *pData, int DataSize, void *pOutput, int OutputSize);
|
||||
|
||||
static void SendControlMsg(NETSOCKET Socket, NETADDR *pAddr, int Ack, int ControlMsg, const void *pExtra, int ExtraSize);
|
||||
static void SendControlMsg(NETSOCKET Socket, NETADDR *pAddr, int Ack, int ControlMsg, const void *pExtra, int ExtraSize, SECURITY_TOKEN SecurityToken);
|
||||
static void SendPacketConnless(NETSOCKET Socket, NETADDR *pAddr, const void *pData, int DataSize);
|
||||
static void SendPacket(NETSOCKET Socket, NETADDR *pAddr, CNetPacketConstruct *pPacket);
|
||||
static void SendPacket(NETSOCKET Socket, NETADDR *pAddr, CNetPacketConstruct *pPacket, SECURITY_TOKEN SecurityToken);
|
||||
static int UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct *pPacket);
|
||||
|
||||
// The backroom is ack-NET_MAX_SEQUENCE/2. Used for knowing if we acked a packet or not
|
||||
|
|
|
@ -24,6 +24,7 @@ void CNetConnection::Reset()
|
|||
m_LastRecvTime = 0;
|
||||
//m_LastUpdateTime = 0;
|
||||
m_Token = -1;
|
||||
m_SecurityToken = NET_SECURITY_TOKEN_UNKNOWN;
|
||||
//mem_zero(&m_PeerAddr, sizeof(m_PeerAddr));
|
||||
|
||||
m_Buffer.Init();
|
||||
|
@ -79,7 +80,7 @@ int CNetConnection::Flush()
|
|||
|
||||
// send of the packets
|
||||
m_Construct.m_Ack = m_Ack;
|
||||
CNetBase::SendPacket(m_Socket, &m_PeerAddr, &m_Construct);
|
||||
CNetBase::SendPacket(m_Socket, &m_PeerAddr, &m_Construct, m_SecurityToken);
|
||||
|
||||
// update send times
|
||||
m_LastSendTime = time_get();
|
||||
|
@ -94,7 +95,7 @@ int CNetConnection::QueueChunkEx(int Flags, int DataSize, const void *pData, int
|
|||
unsigned char *pChunkData;
|
||||
|
||||
// check if we have space for it, if not, flush the connection
|
||||
if(m_Construct.m_DataSize + DataSize + NET_MAX_CHUNKHEADERSIZE > (int)sizeof(m_Construct.m_aChunkData))
|
||||
if(m_Construct.m_DataSize + DataSize + NET_MAX_CHUNKHEADERSIZE > (int)sizeof(m_Construct.m_aChunkData) - (int)sizeof(SECURITY_TOKEN))
|
||||
Flush();
|
||||
|
||||
// pack all the data
|
||||
|
@ -148,7 +149,7 @@ void CNetConnection::SendControl(int ControlMsg, const void *pExtra, int ExtraSi
|
|||
{
|
||||
// send the control message
|
||||
m_LastSendTime = time_get();
|
||||
CNetBase::SendControlMsg(m_Socket, &m_PeerAddr, m_Ack, ControlMsg, pExtra, ExtraSize);
|
||||
CNetBase::SendControlMsg(m_Socket, &m_PeerAddr, m_Ack, ControlMsg, pExtra, ExtraSize, m_SecurityToken);
|
||||
}
|
||||
|
||||
void CNetConnection::ResendChunk(CNetChunkResend *pResend)
|
||||
|
@ -173,7 +174,7 @@ int CNetConnection::Connect(NETADDR *pAddr)
|
|||
m_PeerAddr = *pAddr;
|
||||
mem_zero(m_ErrorString, sizeof(m_ErrorString));
|
||||
m_State = NET_CONNSTATE_CONNECT;
|
||||
SendControl(NET_CTRLMSG_CONNECT, 0, 0);
|
||||
SendControl(NET_CTRLMSG_CONNECT, SECURITY_TOKEN_MAGIC, sizeof(SECURITY_TOKEN_MAGIC));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -197,8 +198,22 @@ void CNetConnection::Disconnect(const char *pReason)
|
|||
Reset();
|
||||
}
|
||||
|
||||
int CNetConnection::Feed(CNetPacketConstruct *pPacket, NETADDR *pAddr)
|
||||
int CNetConnection::Feed(CNetPacketConstruct *pPacket, NETADDR *pAddr, SECURITY_TOKEN SecurityToken)
|
||||
{
|
||||
if (m_SecurityToken != NET_SECURITY_TOKEN_UNKNOWN && m_SecurityToken != NET_SECURITY_TOKEN_UNSUPPORTED)
|
||||
{
|
||||
// supposed to have a valid token in this packet, check it
|
||||
if (pPacket->m_DataSize < sizeof(m_SecurityToken))
|
||||
return -1;
|
||||
pPacket->m_DataSize -= sizeof(m_SecurityToken);
|
||||
if (m_SecurityToken != *(SECURITY_TOKEN*)&pPacket->m_aChunkData[pPacket->m_DataSize])
|
||||
{
|
||||
if(g_Config.m_Debug)
|
||||
dbg_msg("security", "token mismatch, expected %d got %d", m_SecurityToken, *(SECURITY_TOKEN*)&pPacket->m_aChunkData[pPacket->m_DataSize]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int64 Now = time_get();
|
||||
|
||||
// check if resend is requested
|
||||
|
@ -262,7 +277,21 @@ int CNetConnection::Feed(CNetPacketConstruct *pPacket, NETADDR *pAddr)
|
|||
m_LastSendTime = Now;
|
||||
m_LastRecvTime = Now;
|
||||
m_LastUpdateTime = Now;
|
||||
SendControl(NET_CTRLMSG_CONNECTACCEPT, 0, 0);
|
||||
if (m_SecurityToken == NET_SECURITY_TOKEN_UNKNOWN
|
||||
&& pPacket->m_DataSize >= 1 + sizeof(SECURITY_TOKEN_MAGIC) + sizeof(m_SecurityToken)
|
||||
&& !mem_comp(&pPacket->m_aChunkData[1], SECURITY_TOKEN_MAGIC, sizeof(SECURITY_TOKEN_MAGIC)))
|
||||
{
|
||||
m_SecurityToken = SecurityToken;
|
||||
if(g_Config.m_Debug)
|
||||
dbg_msg("security", "generated token %d", m_SecurityToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(g_Config.m_Debug)
|
||||
dbg_msg("security", "token not supported by client (packet size %d)", pPacket->m_DataSize);
|
||||
m_SecurityToken = NET_SECURITY_TOKEN_UNSUPPORTED;
|
||||
}
|
||||
SendControl(NET_CTRLMSG_CONNECTACCEPT, SECURITY_TOKEN_MAGIC, sizeof(SECURITY_TOKEN_MAGIC));
|
||||
if(g_Config.m_Debug)
|
||||
dbg_msg("connection", "got connection, sending connect+accept");
|
||||
}
|
||||
|
@ -272,6 +301,20 @@ int CNetConnection::Feed(CNetPacketConstruct *pPacket, NETADDR *pAddr)
|
|||
// connection made
|
||||
if(CtrlMsg == NET_CTRLMSG_CONNECTACCEPT)
|
||||
{
|
||||
if (m_SecurityToken == NET_SECURITY_TOKEN_UNKNOWN
|
||||
&& pPacket->m_DataSize >= 1 + sizeof(SECURITY_TOKEN_MAGIC) + sizeof(m_SecurityToken)
|
||||
&& !mem_comp(&pPacket->m_aChunkData[1], SECURITY_TOKEN_MAGIC, sizeof(SECURITY_TOKEN_MAGIC)))
|
||||
{
|
||||
m_SecurityToken = *(SECURITY_TOKEN*)(&pPacket->m_aChunkData[1 + sizeof(SECURITY_TOKEN_MAGIC)]);
|
||||
if(g_Config.m_Debug)
|
||||
dbg_msg("security", "got token %d", m_SecurityToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_SecurityToken = NET_SECURITY_TOKEN_UNSUPPORTED;
|
||||
if(g_Config.m_Debug)
|
||||
dbg_msg("security", "token not supported by server");
|
||||
}
|
||||
m_LastRecvTime = Now;
|
||||
SendControl(NET_CTRLMSG_ACCEPT, 0, 0);
|
||||
m_State = NET_CONNSTATE_ONLINE;
|
||||
|
@ -364,12 +407,12 @@ int CNetConnection::Update()
|
|||
else if(State() == NET_CONNSTATE_CONNECT)
|
||||
{
|
||||
if(time_get()-m_LastSendTime > time_freq()/2) // send a new connect every 500ms
|
||||
SendControl(NET_CTRLMSG_CONNECT, 0, 0);
|
||||
SendControl(NET_CTRLMSG_CONNECT, SECURITY_TOKEN_MAGIC, sizeof(SECURITY_TOKEN_MAGIC));
|
||||
}
|
||||
else if(State() == NET_CONNSTATE_PENDING)
|
||||
{
|
||||
if(time_get()-m_LastSendTime > time_freq()/2) // send a new connect/accept every 500ms
|
||||
SendControl(NET_CTRLMSG_CONNECTACCEPT, 0, 0);
|
||||
SendControl(NET_CTRLMSG_CONNECTACCEPT, SECURITY_TOKEN_MAGIC, sizeof(SECURITY_TOKEN_MAGIC));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -4,9 +4,10 @@
|
|||
|
||||
#include <engine/console.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "netban.h"
|
||||
#include "network.h"
|
||||
|
||||
#include <engine/external/md5/md5.h>
|
||||
|
||||
bool CNetServer::Open(NETADDR BindAddr, CNetBan *pNetBan, int MaxClients, int MaxClientsPerIP, int Flags)
|
||||
{
|
||||
|
@ -29,6 +30,14 @@ bool CNetServer::Open(NETADDR BindAddr, CNetBan *pNetBan, int MaxClients, int Ma
|
|||
|
||||
m_MaxClientsPerIP = MaxClientsPerIP;
|
||||
|
||||
if(secure_random_init() != 0)
|
||||
{
|
||||
dbg_msg("secure", "could not initialize secure RNG");
|
||||
return false;
|
||||
}
|
||||
|
||||
secure_random_fill(m_SecurityTokenSeed, sizeof(m_SecurityTokenSeed));
|
||||
|
||||
for(int i = 0; i < NET_MAX_CLIENTS; i++)
|
||||
m_aSlots[i].m_Connection.Init(m_Socket, true);
|
||||
|
||||
|
@ -108,7 +117,7 @@ int CNetServer::Recv(CNetChunk *pChunk)
|
|||
if(NetBan() && NetBan()->IsBanned(&Addr, aBuf, sizeof(aBuf)))
|
||||
{
|
||||
// banned, reply with a message
|
||||
CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, aBuf, str_length(aBuf)+1);
|
||||
CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, aBuf, str_length(aBuf)+1, NET_SECURITY_TOKEN_UNSUPPORTED);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -170,7 +179,7 @@ int CNetServer::Recv(CNetChunk *pChunk)
|
|||
{
|
||||
char aBuf[128];
|
||||
str_format(aBuf, sizeof(aBuf), "Only %d players with the same IP are allowed", m_MaxClientsPerIP);
|
||||
CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, aBuf, sizeof(aBuf));
|
||||
CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, aBuf, sizeof(aBuf), NET_SECURITY_TOKEN_UNSUPPORTED);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +190,22 @@ int CNetServer::Recv(CNetChunk *pChunk)
|
|||
if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE)
|
||||
{
|
||||
Found = true;
|
||||
m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr);
|
||||
long timestamp = time_get();
|
||||
md5_state_t md5;
|
||||
md5_byte_t digest[16];
|
||||
SECURITY_TOKEN securityToken;
|
||||
do
|
||||
{
|
||||
md5_init(&md5);
|
||||
md5_append(&md5, (unsigned char*)m_SecurityTokenSeed, sizeof(m_SecurityTokenSeed));
|
||||
md5_append(&md5, (unsigned char*)&Addr, sizeof(Addr));
|
||||
md5_append(&md5, (unsigned char*)×tamp, sizeof(timestamp));
|
||||
md5_finish(&md5, digest);
|
||||
securityToken = *(SECURITY_TOKEN*)digest;
|
||||
timestamp++;
|
||||
}
|
||||
while (securityToken == NET_SECURITY_TOKEN_UNKNOWN || securityToken == NET_SECURITY_TOKEN_UNSUPPORTED);
|
||||
m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr, securityToken);
|
||||
if(m_pfnNewClient)
|
||||
m_pfnNewClient(i, m_UserPtr);
|
||||
break;
|
||||
|
@ -191,7 +215,7 @@ int CNetServer::Recv(CNetChunk *pChunk)
|
|||
if(!Found)
|
||||
{
|
||||
const char FullMsg[] = "This server is full";
|
||||
CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, FullMsg, sizeof(FullMsg));
|
||||
CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, FullMsg, sizeof(FullMsg), NET_SECURITY_TOKEN_UNSUPPORTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue