commit
e0c56b7522
4
MCServer/.gitignore
vendored
4
MCServer/.gitignore
vendored
@ -30,3 +30,7 @@ motd.txt
|
|||||||
*.xml
|
*.xml
|
||||||
mcserver_api.lua
|
mcserver_api.lua
|
||||||
|
|
||||||
|
# Ignore the webadmin certs / privkey, so that no-one commits theirs by accident:
|
||||||
|
webadmin/httpscert.crt
|
||||||
|
webadmin/httpskey.pem
|
||||||
|
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
echo This script generates the certificate and private key for the https webadmin
|
||||||
|
echo Note that the generated certificate is self-signed, and therefore not trusted by browsers
|
||||||
|
echo Note that this script requires openssl to be installed and in PATH
|
||||||
|
echo.
|
||||||
|
echo When OpenSSL asks you for Common Name, you need to enter the fully qualified domain name of the server, that is, e. g. gallery.xoft.cz
|
||||||
|
echo.
|
||||||
|
echo If OpenSSL fails with an error, "WARNING: can't open config file: /usr/local/ssl/openssl.cnf", you need to run this script as an administrator
|
||||||
|
echo.
|
||||||
|
|
||||||
|
openssl req -x509 -newkey rsa:2048 -keyout httpskey.pem -out httpscert.crt -days 3650 -nodes
|
||||||
|
pause
|
10
MCServer/webadmin/GenerateSelfSignedHTTPSCertUsingOpenssl.sh
Executable file
10
MCServer/webadmin/GenerateSelfSignedHTTPSCertUsingOpenssl.sh
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "This script generates the certificate and private key for the https webadmin"
|
||||||
|
echo "Note that the generated certificate is self-signed, and therefore not trusted by browsers"
|
||||||
|
echo "Note that this script requires openssl to be installed and in PATH"
|
||||||
|
echo ""
|
||||||
|
echo "When OpenSSL asks you for Common Name, you need to enter the fully qualified domain name of the server, that is, e. g. gallery.xoft.cz"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
openssl req -x509 -newkey rsa:2048 -keyout httpskey.pem -out httpscert.crt -days 3650 -nodes
|
@ -38,9 +38,9 @@ set(SHARED_SRC
|
|||||||
../../src/MCLogger.cpp
|
../../src/MCLogger.cpp
|
||||||
../../src/PolarSSL++/AesCfb128Decryptor.cpp
|
../../src/PolarSSL++/AesCfb128Decryptor.cpp
|
||||||
../../src/PolarSSL++/AesCfb128Encryptor.cpp
|
../../src/PolarSSL++/AesCfb128Encryptor.cpp
|
||||||
|
../../src/PolarSSL++/CryptoKey.cpp
|
||||||
../../src/PolarSSL++/CtrDrbgContext.cpp
|
../../src/PolarSSL++/CtrDrbgContext.cpp
|
||||||
../../src/PolarSSL++/EntropyContext.cpp
|
../../src/PolarSSL++/EntropyContext.cpp
|
||||||
../../src/PolarSSL++/PublicKey.cpp
|
|
||||||
../../src/PolarSSL++/RsaPrivateKey.cpp
|
../../src/PolarSSL++/RsaPrivateKey.cpp
|
||||||
)
|
)
|
||||||
set(SHARED_HDR
|
set(SHARED_HDR
|
||||||
@ -50,9 +50,9 @@ set(SHARED_HDR
|
|||||||
../../src/MCLogger.h
|
../../src/MCLogger.h
|
||||||
../../src/PolarSSL++/AesCfb128Decryptor.h
|
../../src/PolarSSL++/AesCfb128Decryptor.h
|
||||||
../../src/PolarSSL++/AesCfb128Encryptor.h
|
../../src/PolarSSL++/AesCfb128Encryptor.h
|
||||||
|
../../src/PolarSSL++/CryptoKey.h
|
||||||
../../src/PolarSSL++/CtrDrbgContext.h
|
../../src/PolarSSL++/CtrDrbgContext.h
|
||||||
../../src/PolarSSL++/EntropyContext.h
|
../../src/PolarSSL++/EntropyContext.h
|
||||||
../../src/PolarSSL++/PublicKey.h
|
|
||||||
../../src/PolarSSL++/RsaPrivateKey.h
|
../../src/PolarSSL++/RsaPrivateKey.h
|
||||||
)
|
)
|
||||||
set(SHARED_OSS_SRC
|
set(SHARED_OSS_SRC
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#include "Connection.h"
|
#include "Connection.h"
|
||||||
#include "Server.h"
|
#include "Server.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "PolarSSL++/PublicKey.h"
|
#include "PolarSSL++/CryptoKey.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <direct.h> // For _mkdir()
|
#include <direct.h> // For _mkdir()
|
||||||
@ -2900,7 +2900,7 @@ void cConnection::SendEncryptionKeyResponse(const AString & a_ServerPublicKey, c
|
|||||||
Byte SharedSecret[16];
|
Byte SharedSecret[16];
|
||||||
Byte EncryptedSecret[128];
|
Byte EncryptedSecret[128];
|
||||||
memset(SharedSecret, 0, sizeof(SharedSecret)); // Use all zeroes for the initial secret
|
memset(SharedSecret, 0, sizeof(SharedSecret)); // Use all zeroes for the initial secret
|
||||||
cPublicKey PubKey(a_ServerPublicKey);
|
cCryptoKey PubKey(a_ServerPublicKey);
|
||||||
int res = PubKey.Encrypt(SharedSecret, sizeof(SharedSecret), EncryptedSecret, sizeof(EncryptedSecret));
|
int res = PubKey.Encrypt(SharedSecret, sizeof(SharedSecret), EncryptedSecret, sizeof(EncryptedSecret));
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
|
@ -30,25 +30,25 @@ public:
|
|||||||
cByteBuffer(size_t a_BufferSize);
|
cByteBuffer(size_t a_BufferSize);
|
||||||
~cByteBuffer();
|
~cByteBuffer();
|
||||||
|
|
||||||
/// Writes the bytes specified to the ringbuffer. Returns true if successful, false if not
|
/** Writes the bytes specified to the ringbuffer. Returns true if successful, false if not */
|
||||||
bool Write(const void * a_Bytes, size_t a_Count);
|
bool Write(const void * a_Bytes, size_t a_Count);
|
||||||
|
|
||||||
/// Returns the number of bytes that can be successfully written to the ringbuffer
|
/** Returns the number of bytes that can be successfully written to the ringbuffer */
|
||||||
size_t GetFreeSpace(void) const;
|
size_t GetFreeSpace(void) const;
|
||||||
|
|
||||||
/// Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes()
|
/** Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes() */
|
||||||
size_t GetUsedSpace(void) const;
|
size_t GetUsedSpace(void) const;
|
||||||
|
|
||||||
/// Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already)
|
/** Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already) */
|
||||||
size_t GetReadableSpace(void) const;
|
size_t GetReadableSpace(void) const;
|
||||||
|
|
||||||
/// Returns the current data start index. For debugging purposes.
|
/** Returns the current data start index. For debugging purposes. */
|
||||||
size_t GetDataStart(void) const { return m_DataStart; }
|
size_t GetDataStart(void) const { return m_DataStart; }
|
||||||
|
|
||||||
/// Returns true if the specified amount of bytes are available for reading
|
/** Returns true if the specified amount of bytes are available for reading */
|
||||||
bool CanReadBytes(size_t a_Count) const;
|
bool CanReadBytes(size_t a_Count) const;
|
||||||
|
|
||||||
/// Returns true if the specified amount of bytes are available for writing
|
/** Returns true if the specified amount of bytes are available for writing */
|
||||||
bool CanWriteBytes(size_t a_Count) const;
|
bool CanWriteBytes(size_t a_Count) const;
|
||||||
|
|
||||||
// Read the specified datatype and advance the read pointer; return true if successfully read:
|
// Read the specified datatype and advance the read pointer; return true if successfully read:
|
||||||
@ -65,7 +65,7 @@ public:
|
|||||||
bool ReadVarUTF8String (AString & a_Value); // string length as VarInt, then string as UTF-8
|
bool ReadVarUTF8String (AString & a_Value); // string length as VarInt, then string as UTF-8
|
||||||
bool ReadLEInt (int & a_Value);
|
bool ReadLEInt (int & a_Value);
|
||||||
|
|
||||||
/// Reads VarInt, assigns it to anything that can be assigned from an UInt32 (unsigned short, char, Byte, double, ...)
|
/** Reads VarInt, assigns it to anything that can be assigned from an UInt32 (unsigned short, char, Byte, double, ...) */
|
||||||
template <typename T> bool ReadVarInt(T & a_Value)
|
template <typename T> bool ReadVarInt(T & a_Value)
|
||||||
{
|
{
|
||||||
UInt32 v;
|
UInt32 v;
|
||||||
@ -91,37 +91,37 @@ public:
|
|||||||
bool WriteVarUTF8String (const AString & a_Value); // string length as VarInt, then string as UTF-8
|
bool WriteVarUTF8String (const AString & a_Value); // string length as VarInt, then string as UTF-8
|
||||||
bool WriteLEInt (int a_Value);
|
bool WriteLEInt (int a_Value);
|
||||||
|
|
||||||
/// Reads a_Count bytes into a_Buffer; returns true if successful
|
/** Reads a_Count bytes into a_Buffer; returns true if successful */
|
||||||
bool ReadBuf(void * a_Buffer, size_t a_Count);
|
bool ReadBuf(void * a_Buffer, size_t a_Count);
|
||||||
|
|
||||||
/// Writes a_Count bytes into a_Buffer; returns true if successful
|
/** Writes a_Count bytes into a_Buffer; returns true if successful */
|
||||||
bool WriteBuf(const void * a_Buffer, size_t a_Count);
|
bool WriteBuf(const void * a_Buffer, size_t a_Count);
|
||||||
|
|
||||||
/// Reads a_Count bytes into a_String; returns true if successful
|
/** Reads a_Count bytes into a_String; returns true if successful */
|
||||||
bool ReadString(AString & a_String, size_t a_Count);
|
bool ReadString(AString & a_String, size_t a_Count);
|
||||||
|
|
||||||
/// Reads 2 * a_NumChars bytes and interprets it as a UTF16-BE string, converting it into UTF8 string a_String
|
/** Reads 2 * a_NumChars bytes and interprets it as a UTF16-BE string, converting it into UTF8 string a_String */
|
||||||
bool ReadUTF16String(AString & a_String, size_t a_NumChars);
|
bool ReadUTF16String(AString & a_String, size_t a_NumChars);
|
||||||
|
|
||||||
/// Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer
|
/** Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer */
|
||||||
bool SkipRead(size_t a_Count);
|
bool SkipRead(size_t a_Count);
|
||||||
|
|
||||||
/// Reads all available data into a_Data
|
/** Reads all available data into a_Data */
|
||||||
void ReadAll(AString & a_Data);
|
void ReadAll(AString & a_Data);
|
||||||
|
|
||||||
/// Reads the specified number of bytes and writes it into the destinatio bytebuffer. Returns true on success.
|
/** Reads the specified number of bytes and writes it into the destinatio bytebuffer. Returns true on success. */
|
||||||
bool ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes);
|
bool ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes);
|
||||||
|
|
||||||
/// Removes the bytes that have been read from the ringbuffer
|
/** Removes the bytes that have been read from the ringbuffer */
|
||||||
void CommitRead(void);
|
void CommitRead(void);
|
||||||
|
|
||||||
/// Restarts next reading operation at the start of the ringbuffer
|
/** Restarts next reading operation at the start of the ringbuffer */
|
||||||
void ResetRead(void);
|
void ResetRead(void);
|
||||||
|
|
||||||
/// Re-reads the data that has been read since the last commit to the current readpos. Used by ProtoProxy to duplicate communication
|
/** Re-reads the data that has been read since the last commit to the current readpos. Used by ProtoProxy to duplicate communication */
|
||||||
void ReadAgain(AString & a_Out);
|
void ReadAgain(AString & a_Out);
|
||||||
|
|
||||||
/// Checks if the internal state is valid (read and write positions in the correct bounds) using ASSERTs
|
/** Checks if the internal state is valid (read and write positions in the correct bounds) using ASSERTs */
|
||||||
void CheckValid(void) const;
|
void CheckValid(void) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -136,7 +136,7 @@ protected:
|
|||||||
size_t m_WritePos; // Where the data ends in the ringbuffer
|
size_t m_WritePos; // Where the data ends in the ringbuffer
|
||||||
size_t m_ReadPos; // Where the next read will start in the ringbuffer
|
size_t m_ReadPos; // Where the next read will start in the ringbuffer
|
||||||
|
|
||||||
/// Advances the m_ReadPos by a_Count bytes
|
/** Advances the m_ReadPos by a_Count bytes */
|
||||||
void AdvanceReadPos(size_t a_Count);
|
void AdvanceReadPos(size_t a_Count);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
@ -2676,12 +2676,13 @@ void cClientHandle::PacketError(unsigned char a_PacketType)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cClientHandle::DataReceived(const char * a_Data, size_t a_Size)
|
bool cClientHandle::DataReceived(const char * a_Data, size_t a_Size)
|
||||||
{
|
{
|
||||||
// Data is received from the client, store it in the buffer to be processed by the Tick thread:
|
// Data is received from the client, store it in the buffer to be processed by the Tick thread:
|
||||||
m_TimeSinceLastPacket = 0;
|
m_TimeSinceLastPacket = 0;
|
||||||
cCSLock Lock(m_CSIncomingData);
|
cCSLock Lock(m_CSIncomingData);
|
||||||
m_IncomingData.append(a_Data, a_Size);
|
m_IncomingData.append(a_Data, a_Size);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -390,7 +390,7 @@ private:
|
|||||||
void HandleAnvilItemName(const char * a_Data, size_t a_Length);
|
void HandleAnvilItemName(const char * a_Data, size_t a_Length);
|
||||||
|
|
||||||
// cSocketThreads::cCallback overrides:
|
// cSocketThreads::cCallback overrides:
|
||||||
virtual void DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client
|
virtual bool DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client
|
||||||
virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client
|
virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client
|
||||||
virtual void SocketClosed (void) override; // The socket has been closed for any reason
|
virtual void SocketClosed (void) override; // The socket has been closed for any reason
|
||||||
}; // tolua_export
|
}; // tolua_export
|
||||||
|
@ -26,6 +26,7 @@ cHTTPConnection::cHTTPConnection(cHTTPServer & a_HTTPServer) :
|
|||||||
|
|
||||||
cHTTPConnection::~cHTTPConnection()
|
cHTTPConnection::~cHTTPConnection()
|
||||||
{
|
{
|
||||||
|
// LOGD("HTTP: Connection deleting: %p", this);
|
||||||
delete m_CurrentRequest;
|
delete m_CurrentRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +145,7 @@ void cHTTPConnection::Terminate(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size)
|
bool cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size)
|
||||||
{
|
{
|
||||||
switch (m_State)
|
switch (m_State)
|
||||||
{
|
{
|
||||||
@ -162,12 +163,12 @@ void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size)
|
|||||||
m_CurrentRequest = NULL;
|
m_CurrentRequest = NULL;
|
||||||
m_State = wcsInvalid;
|
m_State = wcsInvalid;
|
||||||
m_HTTPServer.CloseConnection(*this);
|
m_HTTPServer.CloseConnection(*this);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
if (m_CurrentRequest->IsInHeaders())
|
if (m_CurrentRequest->IsInHeaders())
|
||||||
{
|
{
|
||||||
// The request headers are not yet complete
|
// The request headers are not yet complete
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The request has finished parsing its headers successfully, notify of it:
|
// The request has finished parsing its headers successfully, notify of it:
|
||||||
@ -183,13 +184,12 @@ void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size)
|
|||||||
// Process the rest of the incoming data into the request body:
|
// Process the rest of the incoming data into the request body:
|
||||||
if (a_Size > BytesConsumed)
|
if (a_Size > BytesConsumed)
|
||||||
{
|
{
|
||||||
DataReceived(a_Data + BytesConsumed, a_Size - BytesConsumed);
|
return cHTTPConnection::DataReceived(a_Data + BytesConsumed, a_Size - BytesConsumed);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DataReceived("", 0); // If the request has zero body length, let it be processed right-away
|
return cHTTPConnection::DataReceived("", 0); // If the request has zero body length, let it be processed right-away
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case wcsRecvBody:
|
case wcsRecvBody:
|
||||||
@ -209,7 +209,7 @@ void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size)
|
|||||||
{
|
{
|
||||||
m_State = wcsInvalid;
|
m_State = wcsInvalid;
|
||||||
m_HTTPServer.CloseConnection(*this);
|
m_HTTPServer.CloseConnection(*this);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
delete m_CurrentRequest;
|
delete m_CurrentRequest;
|
||||||
m_CurrentRequest = NULL;
|
m_CurrentRequest = NULL;
|
||||||
@ -223,6 +223,7 @@ void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,9 +91,15 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
// cSocketThreads::cCallback overrides:
|
// cSocketThreads::cCallback overrides:
|
||||||
virtual void DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client
|
/** Data is received from the client.
|
||||||
virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client
|
Returns true if the connection has been closed as the result of parsing the data. */
|
||||||
virtual void SocketClosed (void) override; // The socket has been closed for any reason
|
virtual bool DataReceived(const char * a_Data, size_t a_Size) override;
|
||||||
|
|
||||||
|
/** Data can be sent to client */
|
||||||
|
virtual void GetOutgoingData(AString & a_Data) override;
|
||||||
|
|
||||||
|
/** The socket has been closed for any reason */
|
||||||
|
virtual void SocketClosed(void) override;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
typedef std::vector<cHTTPConnection *> cHTTPConnections;
|
typedef std::vector<cHTTPConnection *> cHTTPConnections;
|
||||||
|
@ -201,7 +201,7 @@ size_t cHTTPRequest::ParseRequestLine(const char * a_Data, size_t a_Size)
|
|||||||
return AString::npos;
|
return AString::npos;
|
||||||
}
|
}
|
||||||
// Check that there's HTTP/version at the end
|
// Check that there's HTTP/version at the end
|
||||||
if (strncmp(a_Data + URLEnd + 1, "HTTP/1.", 7) != 0)
|
if (strncmp(m_IncomingHeaderData.c_str() + URLEnd + 1, "HTTP/1.", 7) != 0)
|
||||||
{
|
{
|
||||||
m_IsValid = false;
|
m_IsValid = false;
|
||||||
return AString::npos;
|
return AString::npos;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "HTTPMessage.h"
|
#include "HTTPMessage.h"
|
||||||
#include "HTTPConnection.h"
|
#include "HTTPConnection.h"
|
||||||
#include "HTTPFormParser.h"
|
#include "HTTPFormParser.h"
|
||||||
|
#include "SslHTTPConnection.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -142,6 +143,41 @@ cHTTPServer::~cHTTPServer()
|
|||||||
|
|
||||||
bool cHTTPServer::Initialize(const AString & a_PortsIPv4, const AString & a_PortsIPv6)
|
bool cHTTPServer::Initialize(const AString & a_PortsIPv4, const AString & a_PortsIPv6)
|
||||||
{
|
{
|
||||||
|
// Read the HTTPS cert + key:
|
||||||
|
AString CertFile = cFile::ReadWholeFile("webadmin/httpscert.crt");
|
||||||
|
AString KeyFile = cFile::ReadWholeFile("webadmin/httpskey.pem");
|
||||||
|
if (!CertFile.empty() && !KeyFile.empty())
|
||||||
|
{
|
||||||
|
m_Cert.reset(new cX509Cert);
|
||||||
|
int res = m_Cert->Parse(CertFile.data(), CertFile.size());
|
||||||
|
if (res == 0)
|
||||||
|
{
|
||||||
|
m_CertPrivKey.reset(new cCryptoKey);
|
||||||
|
int res2 = m_CertPrivKey->ParsePrivate(KeyFile.data(), KeyFile.size(), "");
|
||||||
|
if (res2 != 0)
|
||||||
|
{
|
||||||
|
// Reading the private key failed, reset the cert:
|
||||||
|
LOGWARNING("WebServer: Cannot read HTTPS certificate private key: -0x%x", -res2);
|
||||||
|
m_Cert.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOGWARNING("WebServer: Cannot read HTTPS certificate: -0x%x", -res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify the admin about the HTTPS / HTTP status
|
||||||
|
if (m_Cert.get() == NULL)
|
||||||
|
{
|
||||||
|
LOGWARNING("WebServer: The server is running in unsecure HTTP mode.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOGINFO("WebServer: The server is running in secure HTTPS mode.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open up requested ports:
|
||||||
bool HasAnyPort;
|
bool HasAnyPort;
|
||||||
HasAnyPort = m_ListenThreadIPv4.Initialize(a_PortsIPv4);
|
HasAnyPort = m_ListenThreadIPv4.Initialize(a_PortsIPv4);
|
||||||
HasAnyPort = m_ListenThreadIPv6.Initialize(a_PortsIPv6) || HasAnyPort;
|
HasAnyPort = m_ListenThreadIPv6.Initialize(a_PortsIPv6) || HasAnyPort;
|
||||||
@ -195,7 +231,15 @@ void cHTTPServer::Stop(void)
|
|||||||
|
|
||||||
void cHTTPServer::OnConnectionAccepted(cSocket & a_Socket)
|
void cHTTPServer::OnConnectionAccepted(cSocket & a_Socket)
|
||||||
{
|
{
|
||||||
cHTTPConnection * Connection = new cHTTPConnection(*this);
|
cHTTPConnection * Connection;
|
||||||
|
if (m_Cert.get() != NULL)
|
||||||
|
{
|
||||||
|
Connection = new cSslHTTPConnection(*this, m_Cert, m_CertPrivKey);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Connection = new cHTTPConnection(*this);
|
||||||
|
}
|
||||||
m_SocketThreads.AddClient(a_Socket, Connection);
|
m_SocketThreads.AddClient(a_Socket, Connection);
|
||||||
cCSLock Lock(m_CSConnections);
|
cCSLock Lock(m_CSConnections);
|
||||||
m_Connections.push_back(Connection);
|
m_Connections.push_back(Connection);
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
#include "../OSSupport/ListenThread.h"
|
#include "../OSSupport/ListenThread.h"
|
||||||
#include "../OSSupport/SocketThreads.h"
|
#include "../OSSupport/SocketThreads.h"
|
||||||
#include "inifile/iniFile.h"
|
#include "inifile/iniFile.h"
|
||||||
|
#include "PolarSSL++/RsaPrivateKey.h"
|
||||||
|
#include "PolarSSL++/CryptoKey.h"
|
||||||
|
#include "PolarSSL++/X509Cert.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -66,6 +69,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class cHTTPConnection;
|
friend class cHTTPConnection;
|
||||||
|
friend class cSslHTTPConnection;
|
||||||
|
|
||||||
cListenThread m_ListenThreadIPv4;
|
cListenThread m_ListenThreadIPv4;
|
||||||
cListenThread m_ListenThreadIPv6;
|
cListenThread m_ListenThreadIPv6;
|
||||||
@ -78,6 +82,12 @@ protected:
|
|||||||
/// The callbacks to call for various events
|
/// The callbacks to call for various events
|
||||||
cCallbacks * m_Callbacks;
|
cCallbacks * m_Callbacks;
|
||||||
|
|
||||||
|
/** The server certificate to use for the SSL connections */
|
||||||
|
cX509CertPtr m_Cert;
|
||||||
|
|
||||||
|
/** The private key for m_Cert. */
|
||||||
|
cCryptoKeyPtr m_CertPrivKey;
|
||||||
|
|
||||||
|
|
||||||
// cListenThread::cCallback overrides:
|
// cListenThread::cCallback overrides:
|
||||||
virtual void OnConnectionAccepted(cSocket & a_Socket) override;
|
virtual void OnConnectionAccepted(cSocket & a_Socket) override;
|
||||||
|
107
src/HTTPServer/SslHTTPConnection.cpp
Normal file
107
src/HTTPServer/SslHTTPConnection.cpp
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
// SslHTTPConnection.cpp
|
||||||
|
|
||||||
|
// Implements the cSslHTTPConnection class representing a HTTP connection made over a SSL link
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "SslHTTPConnection.h"
|
||||||
|
#include "HTTPServer.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cSslHTTPConnection::cSslHTTPConnection(cHTTPServer & a_HTTPServer, const cX509CertPtr & a_Cert, const cCryptoKeyPtr & a_PrivateKey) :
|
||||||
|
super(a_HTTPServer),
|
||||||
|
m_Ssl(64000),
|
||||||
|
m_Cert(a_Cert),
|
||||||
|
m_PrivateKey(a_PrivateKey)
|
||||||
|
{
|
||||||
|
m_Ssl.Initialize(false);
|
||||||
|
m_Ssl.SetOwnCert(a_Cert, a_PrivateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cSslHTTPConnection::DataReceived(const char * a_Data, size_t a_Size)
|
||||||
|
{
|
||||||
|
// If there is outgoing data in the queue, notify the server that it should write it out:
|
||||||
|
if (!m_OutgoingData.empty())
|
||||||
|
{
|
||||||
|
m_HTTPServer.NotifyConnectionWrite(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the received data:
|
||||||
|
const char * Data = a_Data;
|
||||||
|
size_t Size = a_Size;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
// Try to write as many bytes into Ssl's "incoming" buffer as possible:
|
||||||
|
size_t BytesWritten = 0;
|
||||||
|
if (Size > 0)
|
||||||
|
{
|
||||||
|
BytesWritten = m_Ssl.WriteIncoming(Data, Size);
|
||||||
|
Data += BytesWritten;
|
||||||
|
Size -= BytesWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read as many bytes from SSL's decryption as possible:
|
||||||
|
char Buffer[32000];
|
||||||
|
int NumRead = m_Ssl.ReadPlain(Buffer, sizeof(Buffer));
|
||||||
|
if (NumRead > 0)
|
||||||
|
{
|
||||||
|
if (super::DataReceived(Buffer, (size_t)NumRead))
|
||||||
|
{
|
||||||
|
// The socket has been closed, and the object is already deleted. Bail out.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If both failed, bail out:
|
||||||
|
if ((BytesWritten == 0) && (NumRead <= 0))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cSslHTTPConnection::GetOutgoingData(AString & a_Data)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
// Write as many bytes from our buffer to SSL's encryption as possible:
|
||||||
|
int NumWritten = 0;
|
||||||
|
if (!m_OutgoingData.empty())
|
||||||
|
{
|
||||||
|
NumWritten = m_Ssl.WritePlain(m_OutgoingData.data(), m_OutgoingData.size());
|
||||||
|
if (NumWritten > 0)
|
||||||
|
{
|
||||||
|
m_OutgoingData.erase(0, (size_t)NumWritten);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read as many bytes from SSL's "outgoing" buffer as possible:
|
||||||
|
char Buffer[32000];
|
||||||
|
size_t NumBytes = m_Ssl.ReadOutgoing(Buffer, sizeof(Buffer));
|
||||||
|
if (NumBytes > 0)
|
||||||
|
{
|
||||||
|
a_Data.append(Buffer, NumBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If both failed, bail out:
|
||||||
|
if ((NumWritten <= 0) && (NumBytes == 0))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
45
src/HTTPServer/SslHTTPConnection.h
Normal file
45
src/HTTPServer/SslHTTPConnection.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
|
||||||
|
// SslHTTPConnection.h
|
||||||
|
|
||||||
|
// Declared the cSslHTTPConnection class representing a HTTP connection made over a SSL link
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "HTTPConnection.h"
|
||||||
|
#include "PolarSSL++/BufferedSslContext.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cSslHTTPConnection :
|
||||||
|
public cHTTPConnection
|
||||||
|
{
|
||||||
|
typedef cHTTPConnection super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Creates a new connection on the specified server.
|
||||||
|
Sends the specified cert as the server certificate, uses the private key for decryption. */
|
||||||
|
cSslHTTPConnection(cHTTPServer & a_HTTPServer, const cX509CertPtr & a_Cert, const cCryptoKeyPtr & a_PrivateKey);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
cBufferedSslContext m_Ssl;
|
||||||
|
|
||||||
|
/** The certificate to send to the client */
|
||||||
|
cX509CertPtr m_Cert;
|
||||||
|
|
||||||
|
/** The private key used for the certificate */
|
||||||
|
cCryptoKeyPtr m_PrivateKey;
|
||||||
|
|
||||||
|
// cHTTPConnection overrides:
|
||||||
|
virtual bool DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client
|
||||||
|
virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -63,8 +63,10 @@ public:
|
|||||||
// Force a virtual destructor in all subclasses:
|
// Force a virtual destructor in all subclasses:
|
||||||
virtual ~cCallback() {}
|
virtual ~cCallback() {}
|
||||||
|
|
||||||
/** Called when data is received from the remote party */
|
/** Called when data is received from the remote party.
|
||||||
virtual void DataReceived(const char * a_Data, size_t a_Size) = 0;
|
SocketThreads does not care about the return value, others can use it for their specific purpose -
|
||||||
|
for example HTTPServer uses it to signal if the connection was terminated as a result of the data received. */
|
||||||
|
virtual bool DataReceived(const char * a_Data, size_t a_Size) = 0;
|
||||||
|
|
||||||
/** Called when data can be sent to remote party
|
/** Called when data can be sent to remote party
|
||||||
The function is supposed to *set* outgoing data to a_Data (overwrite) */
|
The function is supposed to *set* outgoing data to a_Data (overwrite) */
|
||||||
|
@ -20,6 +20,37 @@ cBufferedSslContext::cBufferedSslContext(size_t a_BufferSize):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
size_t cBufferedSslContext::WriteIncoming(const void * a_Data, size_t a_NumBytes)
|
||||||
|
{
|
||||||
|
size_t NumBytes = std::min(m_IncomingData.GetFreeSpace(), a_NumBytes);
|
||||||
|
if (NumBytes > 0)
|
||||||
|
{
|
||||||
|
m_IncomingData.Write(a_Data, NumBytes);
|
||||||
|
return NumBytes;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
size_t cBufferedSslContext::ReadOutgoing(void * a_Data, size_t a_DataMaxSize)
|
||||||
|
{
|
||||||
|
size_t NumBytes = std::min(m_OutgoingData.GetReadableSpace(), a_DataMaxSize);
|
||||||
|
if (NumBytes > 0)
|
||||||
|
{
|
||||||
|
m_OutgoingData.ReadBuf(a_Data, NumBytes);
|
||||||
|
m_OutgoingData.CommitRead();
|
||||||
|
return NumBytes;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cBufferedSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes)
|
int cBufferedSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes)
|
||||||
{
|
{
|
||||||
// Called when PolarSSL wants to read encrypted data from the SSL peer
|
// Called when PolarSSL wants to read encrypted data from the SSL peer
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
cmake_minimum_required (VERSION 2.6)
|
cmake_minimum_required (VERSION 2.6)
|
||||||
project (MCServer)
|
project (MCServer)
|
||||||
|
|
||||||
@ -11,8 +10,8 @@ set(SOURCES
|
|||||||
BufferedSslContext.cpp
|
BufferedSslContext.cpp
|
||||||
CallbackSslContext.cpp
|
CallbackSslContext.cpp
|
||||||
CtrDrbgContext.cpp
|
CtrDrbgContext.cpp
|
||||||
|
CryptoKey.cpp
|
||||||
EntropyContext.cpp
|
EntropyContext.cpp
|
||||||
PublicKey.cpp
|
|
||||||
RsaPrivateKey.cpp
|
RsaPrivateKey.cpp
|
||||||
Sha1Checksum.cpp
|
Sha1Checksum.cpp
|
||||||
SslContext.cpp
|
SslContext.cpp
|
||||||
@ -26,8 +25,8 @@ set(HEADERS
|
|||||||
BufferedSslContext.h
|
BufferedSslContext.h
|
||||||
CallbackSslContext.h
|
CallbackSslContext.h
|
||||||
CtrDrbgContext.h
|
CtrDrbgContext.h
|
||||||
|
CryptoKey.h
|
||||||
EntropyContext.h
|
EntropyContext.h
|
||||||
PublicKey.h
|
|
||||||
RsaPrivateKey.h
|
RsaPrivateKey.h
|
||||||
SslContext.h
|
SslContext.h
|
||||||
Sha1Checksum.h
|
Sha1Checksum.h
|
||||||
|
149
src/PolarSSL++/CryptoKey.cpp
Normal file
149
src/PolarSSL++/CryptoKey.cpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
|
||||||
|
// CryptoKey.cpp
|
||||||
|
|
||||||
|
// Implements the cCryptoKey class representing a RSA public key in PolarSSL
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "CryptoKey.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cCryptoKey::cCryptoKey(void)
|
||||||
|
{
|
||||||
|
pk_init(&m_Pk);
|
||||||
|
m_CtrDrbg.Initialize("rsa_pubkey", 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cCryptoKey::cCryptoKey(const AString & a_PublicKeyData)
|
||||||
|
{
|
||||||
|
pk_init(&m_Pk);
|
||||||
|
m_CtrDrbg.Initialize("rsa_pubkey", 10);
|
||||||
|
int res = ParsePublic(a_PublicKeyData.data(), a_PublicKeyData.size());
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
LOGWARNING("Failed to parse public key: -0x%x", res);
|
||||||
|
ASSERT(!"Cannot parse PubKey");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cCryptoKey::cCryptoKey(const AString & a_PrivateKeyData, const AString & a_Password)
|
||||||
|
{
|
||||||
|
pk_init(&m_Pk);
|
||||||
|
m_CtrDrbg.Initialize("rsa_privkey", 11);
|
||||||
|
int res = ParsePrivate(a_PrivateKeyData.data(), a_PrivateKeyData.size(), a_Password);
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
LOGWARNING("Failed to parse private key: -0x%x", res);
|
||||||
|
ASSERT(!"Cannot parse PubKey");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cCryptoKey::~cCryptoKey()
|
||||||
|
{
|
||||||
|
pk_free(&m_Pk);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int cCryptoKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
|
||||||
|
{
|
||||||
|
ASSERT(IsValid());
|
||||||
|
|
||||||
|
size_t DecryptedLen = a_DecryptedMaxLength;
|
||||||
|
int res = pk_decrypt(&m_Pk,
|
||||||
|
a_EncryptedData, a_EncryptedLength,
|
||||||
|
a_DecryptedData, &DecryptedLen, a_DecryptedMaxLength,
|
||||||
|
ctr_drbg_random, m_CtrDrbg.GetInternal()
|
||||||
|
);
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return (int)DecryptedLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int cCryptoKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
|
||||||
|
{
|
||||||
|
ASSERT(IsValid());
|
||||||
|
|
||||||
|
size_t EncryptedLength = a_EncryptedMaxLength;
|
||||||
|
int res = pk_encrypt(&m_Pk,
|
||||||
|
a_PlainData, a_PlainLength, a_EncryptedData, &EncryptedLength, a_EncryptedMaxLength,
|
||||||
|
ctr_drbg_random, m_CtrDrbg.GetInternal()
|
||||||
|
);
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return (int)EncryptedLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int cCryptoKey::ParsePublic(const void * a_Data, size_t a_NumBytes)
|
||||||
|
{
|
||||||
|
ASSERT(!IsValid()); // Cannot parse a second key
|
||||||
|
|
||||||
|
return pk_parse_public_key(&m_Pk, (const unsigned char *)a_Data, a_NumBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int cCryptoKey::ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password)
|
||||||
|
{
|
||||||
|
ASSERT(!IsValid()); // Cannot parse a second key
|
||||||
|
|
||||||
|
if (a_Password.empty())
|
||||||
|
{
|
||||||
|
return pk_parse_key(&m_Pk, (const unsigned char *)a_Data, a_NumBytes, NULL, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return pk_parse_key(
|
||||||
|
&m_Pk,
|
||||||
|
(const unsigned char *)a_Data, a_NumBytes,
|
||||||
|
(const unsigned char *)a_Password.c_str(), a_Password.size()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cCryptoKey::IsValid(void) const
|
||||||
|
{
|
||||||
|
return (pk_get_type(&m_Pk) != POLARSSL_PK_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
76
src/PolarSSL++/CryptoKey.h
Normal file
76
src/PolarSSL++/CryptoKey.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
|
||||||
|
// CryptoKey.h
|
||||||
|
|
||||||
|
// Declares the cCryptoKey class representing a RSA public key in PolarSSL
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CtrDrbgContext.h"
|
||||||
|
#include "polarssl/pk.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cCryptoKey
|
||||||
|
{
|
||||||
|
friend class cSslContext;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Constructs an empty key instance. Before use, it needs to be filled by ParsePublic() or ParsePrivate() */
|
||||||
|
cCryptoKey(void);
|
||||||
|
|
||||||
|
/** Constructs the public key out of the DER- or PEM-encoded pubkey data */
|
||||||
|
cCryptoKey(const AString & a_PublicKeyData);
|
||||||
|
|
||||||
|
/** Constructs the private key out of the DER- or PEM-encoded privkey data, with the specified password.
|
||||||
|
If a_Password is empty, no password is assumed. */
|
||||||
|
cCryptoKey(const AString & a_PrivateKeyData, const AString & a_Password);
|
||||||
|
|
||||||
|
~cCryptoKey();
|
||||||
|
|
||||||
|
/** Decrypts the data using the stored public key
|
||||||
|
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
||||||
|
Returns the number of bytes decrypted, or negative number for error. */
|
||||||
|
int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength);
|
||||||
|
|
||||||
|
/** Encrypts the data using the stored public key
|
||||||
|
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
||||||
|
Returns the number of bytes decrypted, or negative number for error. */
|
||||||
|
int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength);
|
||||||
|
|
||||||
|
/** Parses the specified data into a public key representation.
|
||||||
|
The key can be DER- or PEM-encoded.
|
||||||
|
Returns 0 on success, PolarSSL error code on failure. */
|
||||||
|
int ParsePublic(const void * a_Data, size_t a_NumBytes);
|
||||||
|
|
||||||
|
/** Parses the specified data into a private key representation.
|
||||||
|
If a_Password is empty, no password is assumed.
|
||||||
|
The key can be DER- or PEM-encoded.
|
||||||
|
Returns 0 on success, PolarSSL error code on failure. */
|
||||||
|
int ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password);
|
||||||
|
|
||||||
|
/** Returns true if the contained key is valid. */
|
||||||
|
bool IsValid(void) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** The PolarSSL representation of the key data */
|
||||||
|
pk_context m_Pk;
|
||||||
|
|
||||||
|
/** The random generator used in encryption and decryption */
|
||||||
|
cCtrDrbgContext m_CtrDrbg;
|
||||||
|
|
||||||
|
|
||||||
|
/** Returns the internal context ptr. Only use in PolarSSL API calls. */
|
||||||
|
pk_context * GetInternal(void) { return &m_Pk; }
|
||||||
|
} ;
|
||||||
|
|
||||||
|
typedef SharedPtr<cCryptoKey> cCryptoKeyPtr;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -26,7 +26,7 @@ class cCtrDrbgContext
|
|||||||
{
|
{
|
||||||
friend class cSslContext;
|
friend class cSslContext;
|
||||||
friend class cRsaPrivateKey;
|
friend class cRsaPrivateKey;
|
||||||
friend class cPublicKey;
|
friend class cCryptoKey;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Constructs the context with a new entropy context. */
|
/** Constructs the context with a new entropy context. */
|
||||||
|
@ -1,73 +0,0 @@
|
|||||||
|
|
||||||
// PublicKey.cpp
|
|
||||||
|
|
||||||
// Implements the cPublicKey class representing a RSA public key in PolarSSL
|
|
||||||
|
|
||||||
#include "Globals.h"
|
|
||||||
#include "PublicKey.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cPublicKey::cPublicKey(const AString & a_PublicKeyDER)
|
|
||||||
{
|
|
||||||
pk_init(&m_Pk);
|
|
||||||
if (pk_parse_public_key(&m_Pk, (const Byte *)a_PublicKeyDER.data(), a_PublicKeyDER.size()) != 0)
|
|
||||||
{
|
|
||||||
ASSERT(!"Cannot parse PubKey");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_CtrDrbg.Initialize("rsa_pubkey", 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cPublicKey::~cPublicKey()
|
|
||||||
{
|
|
||||||
pk_free(&m_Pk);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cPublicKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
|
|
||||||
{
|
|
||||||
size_t DecryptedLen = a_DecryptedMaxLength;
|
|
||||||
int res = pk_decrypt(&m_Pk,
|
|
||||||
a_EncryptedData, a_EncryptedLength,
|
|
||||||
a_DecryptedData, &DecryptedLen, a_DecryptedMaxLength,
|
|
||||||
ctr_drbg_random, m_CtrDrbg.GetInternal()
|
|
||||||
);
|
|
||||||
if (res != 0)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return (int)DecryptedLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cPublicKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
|
|
||||||
{
|
|
||||||
size_t EncryptedLength = a_EncryptedMaxLength;
|
|
||||||
int res = pk_encrypt(&m_Pk,
|
|
||||||
a_PlainData, a_PlainLength, a_EncryptedData, &EncryptedLength, a_EncryptedMaxLength,
|
|
||||||
ctr_drbg_random, m_CtrDrbg.GetInternal()
|
|
||||||
);
|
|
||||||
if (res != 0)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return (int)EncryptedLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
|||||||
|
|
||||||
// PublicKey.h
|
|
||||||
|
|
||||||
// Declares the cPublicKey class representing a RSA public key in PolarSSL
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "CtrDrbgContext.h"
|
|
||||||
#include "polarssl/pk.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cPublicKey
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/** Constructs the public key out of the DER-encoded pubkey data */
|
|
||||||
cPublicKey(const AString & a_PublicKeyDER);
|
|
||||||
|
|
||||||
~cPublicKey();
|
|
||||||
|
|
||||||
/** Decrypts the data using the stored public key
|
|
||||||
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
|
||||||
Returns the number of bytes decrypted, or negative number for error. */
|
|
||||||
int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength);
|
|
||||||
|
|
||||||
/** Encrypts the data using the stored public key
|
|
||||||
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
|
||||||
Returns the number of bytes decrypted, or negative number for error. */
|
|
||||||
int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/** The public key PolarSSL representation */
|
|
||||||
pk_context m_Pk;
|
|
||||||
|
|
||||||
/** The random generator used in encryption and decryption */
|
|
||||||
cCtrDrbgContext m_CtrDrbg;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -19,6 +19,8 @@
|
|||||||
/** Encapsulates an RSA private key used in PKI cryptography */
|
/** Encapsulates an RSA private key used in PKI cryptography */
|
||||||
class cRsaPrivateKey
|
class cRsaPrivateKey
|
||||||
{
|
{
|
||||||
|
friend class cSslContext;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Creates a new empty object, the key is not assigned */
|
/** Creates a new empty object, the key is not assigned */
|
||||||
cRsaPrivateKey(void);
|
cRsaPrivateKey(void);
|
||||||
@ -51,8 +53,14 @@ protected:
|
|||||||
|
|
||||||
/** The random generator used for generating the key and encryption / decryption */
|
/** The random generator used for generating the key and encryption / decryption */
|
||||||
cCtrDrbgContext m_CtrDrbg;
|
cCtrDrbgContext m_CtrDrbg;
|
||||||
|
|
||||||
|
|
||||||
|
/** Returns the internal context ptr. Only use in PolarSSL API calls. */
|
||||||
|
rsa_context * GetInternal(void) { return &m_Rsa; }
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
typedef SharedPtr<cRsaPrivateKey> cRsaPrivateKeyPtr;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ int cSslContext::Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> &
|
|||||||
if (m_IsValid)
|
if (m_IsValid)
|
||||||
{
|
{
|
||||||
LOGWARNING("SSL: Double initialization is not supported.");
|
LOGWARNING("SSL: Double initialization is not supported.");
|
||||||
return POLARSSL_ERR_SSL_MALLOC_FAILED; // There is no return value well-suited for this, reuse this one.
|
return POLARSSL_ERR_SSL_BAD_INPUT_DATA; // There is no return value well-suited for this, reuse this one.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the CtrDrbg context, create a new one if needed:
|
// Set the CtrDrbg context, create a new one if needed:
|
||||||
@ -59,7 +59,7 @@ int cSslContext::Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> &
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
ssl_set_endpoint(&m_Ssl, a_IsClient ? SSL_IS_CLIENT : SSL_IS_SERVER);
|
ssl_set_endpoint(&m_Ssl, a_IsClient ? SSL_IS_CLIENT : SSL_IS_SERVER);
|
||||||
ssl_set_authmode(&m_Ssl, SSL_VERIFY_OPTIONAL);
|
ssl_set_authmode(&m_Ssl, a_IsClient ? SSL_VERIFY_OPTIONAL : SSL_VERIFY_NONE); // Clients ask for server's cert but don't verify strictly; servers don't ask clients for certs by default
|
||||||
ssl_set_rng(&m_Ssl, ctr_drbg_random, &m_CtrDrbg->m_CtrDrbg);
|
ssl_set_rng(&m_Ssl, ctr_drbg_random, &m_CtrDrbg->m_CtrDrbg);
|
||||||
ssl_set_bio(&m_Ssl, ReceiveEncrypted, this, SendEncrypted, this);
|
ssl_set_bio(&m_Ssl, ReceiveEncrypted, this, SendEncrypted, this);
|
||||||
|
|
||||||
@ -70,6 +70,18 @@ int cSslContext::Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> &
|
|||||||
ssl_set_dbg(&m_Ssl, &SSLDebugMessage, this);
|
ssl_set_dbg(&m_Ssl, &SSLDebugMessage, this);
|
||||||
ssl_set_verify(&m_Ssl, &SSLVerifyCert, this);
|
ssl_set_verify(&m_Ssl, &SSLVerifyCert, this);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Set ciphersuite to the easiest one to decode, so that the connection can be wireshark-decoded:
|
||||||
|
static const int CipherSuites[] =
|
||||||
|
{
|
||||||
|
TLS_RSA_WITH_RC4_128_MD5,
|
||||||
|
TLS_RSA_WITH_RC4_128_SHA,
|
||||||
|
TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||||
|
0, // Must be 0-terminated!
|
||||||
|
};
|
||||||
|
ssl_set_ciphersuites(&m_Ssl, CipherSuites);
|
||||||
|
*/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_IsValid = true;
|
m_IsValid = true;
|
||||||
@ -80,8 +92,56 @@ int cSslContext::Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> &
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cRsaPrivateKeyPtr & a_OwnCertPrivKey)
|
||||||
|
{
|
||||||
|
ASSERT(m_IsValid); // Call Initialize() first
|
||||||
|
|
||||||
|
// Check that both the cert and the key is valid:
|
||||||
|
if ((a_OwnCert.get() == NULL) || (a_OwnCertPrivKey.get() == NULL))
|
||||||
|
{
|
||||||
|
LOGWARNING("SSL: Own certificate is not valid, skipping the set.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we have the cert stored for later, PolarSSL only uses the cert later on
|
||||||
|
m_OwnCert = a_OwnCert;
|
||||||
|
m_OwnCertPrivKey = a_OwnCertPrivKey;
|
||||||
|
|
||||||
|
// Set into the context:
|
||||||
|
ssl_set_own_cert_rsa(&m_Ssl, m_OwnCert->GetInternal(), m_OwnCertPrivKey->GetInternal());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cCryptoKeyPtr & a_OwnCertPrivKey)
|
||||||
|
{
|
||||||
|
ASSERT(m_IsValid); // Call Initialize() first
|
||||||
|
|
||||||
|
// Check that both the cert and the key is valid:
|
||||||
|
if ((a_OwnCert.get() == NULL) || (a_OwnCertPrivKey.get() == NULL))
|
||||||
|
{
|
||||||
|
LOGWARNING("SSL: Own certificate is not valid, skipping the set.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we have the cert stored for later, PolarSSL only uses the cert later on
|
||||||
|
m_OwnCert = a_OwnCert;
|
||||||
|
m_OwnCertPrivKey2 = a_OwnCertPrivKey;
|
||||||
|
|
||||||
|
// Set into the context:
|
||||||
|
ssl_set_own_cert(&m_Ssl, m_OwnCert->GetInternal(), m_OwnCertPrivKey2->GetInternal());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cSslContext::SetCACerts(const cX509CertPtr & a_CACert, const AString & a_ExpectedPeerName)
|
void cSslContext::SetCACerts(const cX509CertPtr & a_CACert, const AString & a_ExpectedPeerName)
|
||||||
{
|
{
|
||||||
|
ASSERT(m_IsValid); // Call Initialize() first
|
||||||
|
|
||||||
// Store the data in our internal buffers, to avoid losing the pointers later on
|
// Store the data in our internal buffers, to avoid losing the pointers later on
|
||||||
// PolarSSL will need these after this call returns, and the caller may move / delete the data before that:
|
// PolarSSL will need these after this call returns, and the caller may move / delete the data before that:
|
||||||
m_ExpectedPeerName = a_ExpectedPeerName;
|
m_ExpectedPeerName = a_ExpectedPeerName;
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
#include "polarssl/ssl.h"
|
#include "polarssl/ssl.h"
|
||||||
#include "../ByteBuffer.h"
|
#include "../ByteBuffer.h"
|
||||||
|
#include "CryptoKey.h"
|
||||||
|
#include "RsaPrivateKey.h"
|
||||||
#include "X509Cert.h"
|
#include "X509Cert.h"
|
||||||
|
|
||||||
|
|
||||||
@ -38,7 +40,7 @@ public:
|
|||||||
/** Creates a new uninitialized context */
|
/** Creates a new uninitialized context */
|
||||||
cSslContext(void);
|
cSslContext(void);
|
||||||
|
|
||||||
~cSslContext();
|
virtual ~cSslContext();
|
||||||
|
|
||||||
/** Initializes the context for use as a server or client.
|
/** Initializes the context for use as a server or client.
|
||||||
Returns 0 on success, PolarSSL error on failure. */
|
Returns 0 on success, PolarSSL error on failure. */
|
||||||
@ -47,7 +49,15 @@ public:
|
|||||||
/** Returns true if the object has been initialized properly. */
|
/** Returns true if the object has been initialized properly. */
|
||||||
bool IsValid(void) const { return m_IsValid; }
|
bool IsValid(void) const { return m_IsValid; }
|
||||||
|
|
||||||
/** Sets a cert chain as the trusted cert store for this context.
|
/** Sets the certificate to use as our own. Must be used when representing a server, optional when client.
|
||||||
|
Must be called after Initialize(). */
|
||||||
|
void SetOwnCert(const cX509CertPtr & a_OwnCert, const cRsaPrivateKeyPtr & a_OwnCertPrivKey);
|
||||||
|
|
||||||
|
/** Sets the certificate to use as our own. Must be used when representing a server, optional when client.
|
||||||
|
Must be called after Initialize(). */
|
||||||
|
void SetOwnCert(const cX509CertPtr & a_OwnCert, const cCryptoKeyPtr & a_OwnCertPrivKey);
|
||||||
|
|
||||||
|
/** Sets a cert chain as the trusted cert store for this context. Must be called after Initialize().
|
||||||
Calling this will switch the context into strict cert verification mode.
|
Calling this will switch the context into strict cert verification mode.
|
||||||
a_ExpectedPeerName is the CommonName that we expect the SSL peer to have in its cert,
|
a_ExpectedPeerName is the CommonName that we expect the SSL peer to have in its cert,
|
||||||
if it is different, the verification will fail. An empty string will disable the CN check. */
|
if it is different, the verification will fail. An empty string will disable the CN check. */
|
||||||
@ -93,6 +103,15 @@ protected:
|
|||||||
/** The SSL context that PolarSSL uses. */
|
/** The SSL context that PolarSSL uses. */
|
||||||
ssl_context m_Ssl;
|
ssl_context m_Ssl;
|
||||||
|
|
||||||
|
/** The certificate that we present to the peer. */
|
||||||
|
cX509CertPtr m_OwnCert;
|
||||||
|
|
||||||
|
/** Private key for m_OwnCert, if initialized from a cRsaPrivateKey. */
|
||||||
|
cRsaPrivateKeyPtr m_OwnCertPrivKey;
|
||||||
|
|
||||||
|
/** Private key for m_OwnCert, if initialized from a cCryptoKey. */
|
||||||
|
cCryptoKeyPtr m_OwnCertPrivKey2;
|
||||||
|
|
||||||
/** True if the SSL handshake has been completed. */
|
/** True if the SSL handshake has been completed. */
|
||||||
bool m_HasHandshaken;
|
bool m_HasHandshaken;
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ cRCONServer::cConnection::cConnection(cRCONServer & a_RCONServer, cSocket & a_So
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cRCONServer::cConnection::DataReceived(const char * a_Data, size_t a_Size)
|
bool cRCONServer::cConnection::DataReceived(const char * a_Data, size_t a_Size)
|
||||||
{
|
{
|
||||||
// Append data to the buffer:
|
// Append data to the buffer:
|
||||||
m_Buffer.append(a_Data, a_Size);
|
m_Buffer.append(a_Data, a_Size);
|
||||||
@ -187,12 +187,12 @@ void cRCONServer::cConnection::DataReceived(const char * a_Data, size_t a_Size)
|
|||||||
m_RCONServer.m_SocketThreads.RemoveClient(this);
|
m_RCONServer.m_SocketThreads.RemoveClient(this);
|
||||||
m_Socket.CloseSocket();
|
m_Socket.CloseSocket();
|
||||||
delete this;
|
delete this;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if (Length > (int)(m_Buffer.size() + 4))
|
if (Length > (int)(m_Buffer.size() + 4))
|
||||||
{
|
{
|
||||||
// Incomplete packet yet, wait for more data to come
|
// Incomplete packet yet, wait for more data to come
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RequestID = IntFromBuffer(m_Buffer.data() + 4);
|
int RequestID = IntFromBuffer(m_Buffer.data() + 4);
|
||||||
@ -202,10 +202,11 @@ void cRCONServer::cConnection::DataReceived(const char * a_Data, size_t a_Size)
|
|||||||
m_RCONServer.m_SocketThreads.RemoveClient(this);
|
m_RCONServer.m_SocketThreads.RemoveClient(this);
|
||||||
m_Socket.CloseSocket();
|
m_Socket.CloseSocket();
|
||||||
delete this;
|
delete this;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
m_Buffer.erase(0, Length + 4);
|
m_Buffer.erase(0, Length + 4);
|
||||||
} // while (m_Buffer.size() >= 14)
|
} // while (m_Buffer.size() >= 14)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
// cSocketThreads::cCallback overrides:
|
// cSocketThreads::cCallback overrides:
|
||||||
virtual void DataReceived(const char * a_Data, size_t a_Size) override;
|
virtual bool DataReceived(const char * a_Data, size_t a_Size) override;
|
||||||
virtual void GetOutgoingData(AString & a_Data) override;
|
virtual void GetOutgoingData(AString & a_Data) override;
|
||||||
virtual void SocketClosed(void) override;
|
virtual void SocketClosed(void) override;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user