1
0

Merge pull request #965 from mc-server/SslWrappers

Ssl wrappers
This commit is contained in:
Mattes D 2014-04-30 17:05:13 +02:00
commit 014fab58e6
44 changed files with 2128 additions and 873 deletions

View File

@ -36,14 +36,24 @@ set(SHARED_SRC
../../src/StringUtils.cpp
../../src/Log.cpp
../../src/MCLogger.cpp
../../src/Crypto.cpp
../../src/PolarSSL++/AesCfb128Decryptor.cpp
../../src/PolarSSL++/AesCfb128Encryptor.cpp
../../src/PolarSSL++/CtrDrbgContext.cpp
../../src/PolarSSL++/EntropyContext.cpp
../../src/PolarSSL++/PublicKey.cpp
../../src/PolarSSL++/RsaPrivateKey.cpp
)
set(SHARED_HDR
../../src/ByteBuffer.h
../../src/StringUtils.h
../../src/Log.h
../../src/MCLogger.h
../../src/Crypto.h
../../src/PolarSSL++/AesCfb128Decryptor.h
../../src/PolarSSL++/AesCfb128Encryptor.h
../../src/PolarSSL++/CtrDrbgContext.h
../../src/PolarSSL++/EntropyContext.h
../../src/PolarSSL++/PublicKey.h
../../src/PolarSSL++/RsaPrivateKey.h
)
set(SHARED_OSS_SRC
../../src/OSSupport/CriticalSection.cpp

View File

@ -7,6 +7,7 @@
#include "Connection.h"
#include "Server.h"
#include <iostream>
#include "PolarSSL++/PublicKey.h"
#ifdef _WIN32
#include <direct.h> // For _mkdir()
@ -471,7 +472,7 @@ bool cConnection::SendData(SOCKET a_Socket, cByteBuffer & a_Data, const char * a
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer)
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer)
{
DataLog(a_Data, a_Size, "Encrypting %d bytes to %s", a_Size, a_Peer);
const Byte * Data = (const Byte *)a_Data;
@ -495,7 +496,7 @@ bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryp
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer)
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer)
{
AString All;
a_Data.ReadAll(All);

View File

@ -11,6 +11,8 @@
#include "ByteBuffer.h"
#include "OSSupport/Timer.h"
#include "PolarSSL++/AesCfb128Decryptor.h"
#include "PolarSSL++/AesCfb128Encryptor.h"
@ -66,8 +68,8 @@ protected:
cByteBuffer m_ClientBuffer;
cByteBuffer m_ServerBuffer;
cAESCFBDecryptor m_ServerDecryptor;
cAESCFBEncryptor m_ServerEncryptor;
cAesCfb128Decryptor m_ServerDecryptor;
cAesCfb128Encryptor m_ServerEncryptor;
AString m_ServerEncryptionBuffer; // Buffer for the data to be sent to the server once encryption is established
@ -109,10 +111,10 @@ protected:
bool SendData(SOCKET a_Socket, cByteBuffer & a_Data, const char * a_Peer);
/// Sends data to the specfied socket, after encrypting it using a_Encryptor. If sending fails, prints a fail message using a_Peer and returns false
bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer);
bool SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer);
/// Sends data to the specfied socket, after encrypting it using a_Encryptor. If sending fails, prints a fail message using a_Peer and returns false
bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer);
bool SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer);
/// Decodes packets coming from the client, sends appropriate counterparts to the server; returns false if the connection is to be dropped
bool DecodeClientsPackets(const char * a_Data, int a_Size);

View File

@ -216,6 +216,20 @@ typedef unsigned char Byte;
// Pretty much the same as ASSERT() but stays in Release builds
#define VERIFY( x ) ( !!(x) || ( LOGERROR("Verification failed: %s, file %s, line %i", #x, __FILE__, __LINE__ ), exit(1), 0 ) )
// Allow both Older versions of MSVC and newer versions of everything use a shared_ptr:
// Note that we cannot typedef, because C++ doesn't allow (partial) templates to be typedeffed.
#if (defined(_MSC_VER) && (_MSC_VER < 1600))
// MSVC before 2010 doesn't have std::shared_ptr, but has std::tr1::shared_ptr, defined in <memory> included earlier
#define SharedPtr std::tr1::shared_ptr
#elif (__cplusplus >= 201103L)
// C++11 has std::shared_ptr in <memory>, included earlier
#define SharedPtr std::shared_ptr
#else
// C++03 has std::tr1::shared_ptr in <tr1/memory>
#include <tr1/memory>
#define SharedPtr std::tr1::shared_ptr
#endif
@ -232,12 +246,6 @@ public:
#include "../../src/Crypto.h"
#define LOGERROR printf
#define LOGINFO printf
#define LOGWARNING printf

View File

@ -20,7 +20,7 @@ You need to set the server *not* to verify usernames ("online-mode=false" in ser
ProtoProxy is not much dependent on the protocol - it will work with unknown packets, it just won't parse them into human-readable format.
The latest protocol which has been tested is 1.6.1 (#73).
The latest protocol which has been tested is 1.7.9 (#5).
*/

View File

@ -9,6 +9,8 @@
#pragma once
#include "PolarSSL++/RsaPrivateKey.h"
@ -17,7 +19,7 @@
class cServer
{
SOCKET m_ListenSocket;
cRSAPrivateKey m_PrivateKey;
cRsaPrivateKey m_PrivateKey;
AString m_PublicKeyDER;
short m_ConnectPort;
@ -27,7 +29,7 @@ public:
int Init(short a_ListenPort, short a_ConnectPort);
void Run(void);
cRSAPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
cRsaPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
const AString & GetPublicKeyDER (void) { return m_PublicKeyDER; }
short GetConnectPort(void) const { return m_ConnectPort; }

View File

@ -171,7 +171,7 @@ cByteBuffer::~cByteBuffer()
bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
bool cByteBuffer::Write(const void * a_Bytes, size_t a_Count)
{
CHECK_THREAD;
CheckValid();
@ -187,13 +187,14 @@ bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
}
ASSERT(m_BufferSize >= m_WritePos);
size_t TillEnd = m_BufferSize - m_WritePos;
const char * Bytes = (const char *)a_Bytes;
if (TillEnd <= a_Count)
{
// Need to wrap around the ringbuffer end
if (TillEnd > 0)
{
memcpy(m_Buffer + m_WritePos, a_Bytes, TillEnd);
a_Bytes += TillEnd;
memcpy(m_Buffer + m_WritePos, Bytes, TillEnd);
Bytes += TillEnd;
a_Count -= TillEnd;
WrittenBytes = TillEnd;
}
@ -203,7 +204,7 @@ bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
// We're guaranteed that we'll fit in a single write op
if (a_Count > 0)
{
memcpy(m_Buffer + m_WritePos, a_Bytes, a_Count);
memcpy(m_Buffer + m_WritePos, Bytes, a_Count);
m_WritePos += a_Count;
WrittenBytes += a_Count;
}

View File

@ -31,7 +31,7 @@ public:
~cByteBuffer();
/// Writes the bytes specified to the ringbuffer. Returns true if successful, false if not
bool Write(const char * 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
size_t GetFreeSpace(void) const;

View File

@ -5,7 +5,7 @@ include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/")
include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/jsoncpp/include")
include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/polarssl/include")
set(FOLDERS OSSupport HTTPServer Items Blocks Protocol Generating)
set(FOLDERS OSSupport HTTPServer Items Blocks Protocol Generating PolarSSL++)
set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities Generating/Prefabs)
@ -242,7 +242,7 @@ endif ()
if (NOT MSVC)
target_link_libraries(${EXECUTABLE} OSSupport HTTPServer Bindings Items Blocks)
target_link_libraries(${EXECUTABLE} Protocol Generating Generating_Prefabs WorldStorage)
target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities)
target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities PolarSSL++)
endif ()
if (WIN32)
target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib)

View File

@ -1,509 +0,0 @@
// Crypto.cpp
// Implements classes that wrap the cryptographic code library
#include "Globals.h"
#include "Crypto.h"
#include "polarssl/pk.h"
/*
// Self-test the hash formatting for known values:
// sha1(Notch) : 4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48
// sha1(jeb_) : -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1
// sha1(simon) : 88e16a1019277b15d58faf0541e11910eb756f6
class Test
{
public:
Test(void)
{
AString DigestNotch, DigestJeb, DigestSimon;
Byte Digest[20];
cSHA1Checksum Checksum;
Checksum.Update((const Byte *)"Notch", 5);
Checksum.Finalize(Digest);
cSHA1Checksum::DigestToJava(Digest, DigestNotch);
Checksum.Restart();
Checksum.Update((const Byte *)"jeb_", 4);
Checksum.Finalize(Digest);
cSHA1Checksum::DigestToJava(Digest, DigestJeb);
Checksum.Restart();
Checksum.Update((const Byte *)"simon", 5);
Checksum.Finalize(Digest);
cSHA1Checksum::DigestToJava(Digest, DigestSimon);
printf("Notch: \"%s\"\n", DigestNotch.c_str());
printf("jeb_: \"%s\"\n", DigestJeb.c_str());
printf("simon: \"%s\"\n", DigestSimon.c_str());
assert(DigestNotch == "4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48");
assert(DigestJeb == "-7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1");
assert(DigestSimon == "88e16a1019277b15d58faf0541e11910eb756f6");
}
} test;
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cRSAPrivateKey:
cRSAPrivateKey::cRSAPrivateKey(void)
{
rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
InitRnd();
}
cRSAPrivateKey::cRSAPrivateKey(const cRSAPrivateKey & a_Other)
{
rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
rsa_copy(&m_Rsa, &a_Other.m_Rsa);
InitRnd();
}
cRSAPrivateKey::~cRSAPrivateKey()
{
entropy_free(&m_Entropy);
rsa_free(&m_Rsa);
}
void cRSAPrivateKey::InitRnd(void)
{
entropy_init(&m_Entropy);
const unsigned char pers[] = "rsa_genkey";
ctr_drbg_init(&m_Ctr_drbg, entropy_func, &m_Entropy, pers, sizeof(pers) - 1);
}
bool cRSAPrivateKey::Generate(unsigned a_KeySizeBits)
{
if (rsa_gen_key(&m_Rsa, ctr_drbg_random, &m_Ctr_drbg, a_KeySizeBits, 65537) != 0)
{
// Key generation failed
return false;
}
return true;
}
AString cRSAPrivateKey::GetPubKeyDER(void)
{
class cPubKey
{
public:
cPubKey(rsa_context * a_Rsa) :
m_IsValid(false)
{
pk_init(&m_Key);
if (pk_init_ctx(&m_Key, pk_info_from_type(POLARSSL_PK_RSA)) != 0)
{
ASSERT(!"Cannot init PrivKey context");
return;
}
if (rsa_copy(pk_rsa(m_Key), a_Rsa) != 0)
{
ASSERT(!"Cannot copy PrivKey to PK context");
return;
}
m_IsValid = true;
}
~cPubKey()
{
if (m_IsValid)
{
pk_free(&m_Key);
}
}
operator pk_context * (void) { return &m_Key; }
protected:
bool m_IsValid;
pk_context m_Key;
} PkCtx(&m_Rsa);
unsigned char buf[3000];
int res = pk_write_pubkey_der(PkCtx, buf, sizeof(buf));
if (res < 0)
{
return AString();
}
return AString((const char *)(buf + sizeof(buf) - res), (size_t)res);
}
int cRSAPrivateKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
{
if (a_EncryptedLength < m_Rsa.len)
{
LOGD("%s: Invalid a_EncryptedLength: got %u, exp at least %u",
__FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len)
);
ASSERT(!"Invalid a_DecryptedMaxLength!");
return -1;
}
if (a_DecryptedMaxLength < m_Rsa.len)
{
LOGD("%s: Invalid a_DecryptedMaxLength: got %u, exp at least %u",
__FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len)
);
ASSERT(!"Invalid a_DecryptedMaxLength!");
return -1;
}
size_t DecryptedLength;
int res = rsa_pkcs1_decrypt(
&m_Rsa, ctr_drbg_random, &m_Ctr_drbg, RSA_PRIVATE, &DecryptedLength,
a_EncryptedData, a_DecryptedData, a_DecryptedMaxLength
);
if (res != 0)
{
return -1;
}
return (int)DecryptedLength;
}
int cRSAPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
{
if (a_EncryptedMaxLength < m_Rsa.len)
{
LOGD("%s: Invalid a_EncryptedMaxLength: got %u, exp at least %u",
__FUNCTION__, (unsigned)a_EncryptedMaxLength, (unsigned)(m_Rsa.len)
);
ASSERT(!"Invalid a_DecryptedMaxLength!");
return -1;
}
if (a_PlainLength < m_Rsa.len)
{
LOGD("%s: Invalid a_PlainLength: got %u, exp at least %u",
__FUNCTION__, (unsigned)a_PlainLength, (unsigned)(m_Rsa.len)
);
ASSERT(!"Invalid a_PlainLength!");
return -1;
}
int res = rsa_pkcs1_encrypt(
&m_Rsa, ctr_drbg_random, &m_Ctr_drbg, RSA_PRIVATE,
a_PlainLength, a_PlainData, a_EncryptedData
);
if (res != 0)
{
return -1;
}
return (int)m_Rsa.len;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cPublicKey:
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;
}
InitRnd();
}
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_Ctr_drbg
);
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_Ctr_drbg
);
if (res != 0)
{
return res;
}
return (int)EncryptedLength;
}
void cPublicKey::InitRnd(void)
{
entropy_init(&m_Entropy);
const unsigned char pers[] = "rsa_genkey";
ctr_drbg_init(&m_Ctr_drbg, entropy_func, &m_Entropy, pers, sizeof(pers) - 1);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cAESCFBDecryptor:
cAESCFBDecryptor::cAESCFBDecryptor(void) :
m_IVOffset(0),
m_IsValid(false)
{
}
cAESCFBDecryptor::~cAESCFBDecryptor()
{
// Clear the leftover in-memory data, so that they can't be accessed by a backdoor
memset(&m_Aes, 0, sizeof(m_Aes));
}
void cAESCFBDecryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
{
ASSERT(!IsValid()); // Cannot Init twice
memcpy(m_IV, a_IV, 16);
aes_setkey_enc(&m_Aes, a_Key, 128);
m_IsValid = true;
}
void cAESCFBDecryptor::ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length)
{
ASSERT(IsValid()); // Must Init() first
// PolarSSL doesn't support AES-CFB8, need to implement it manually:
for (size_t i = 0; i < a_Length; i++)
{
Byte Buffer[sizeof(m_IV)];
aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
{
m_IV[idx] = m_IV[idx + 1];
}
m_IV[sizeof(m_IV) - 1] = a_EncryptedIn[i];
a_DecryptedOut[i] = a_EncryptedIn[i] ^ Buffer[0];
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cAESCFBEncryptor:
cAESCFBEncryptor::cAESCFBEncryptor(void) :
m_IVOffset(0),
m_IsValid(false)
{
}
cAESCFBEncryptor::~cAESCFBEncryptor()
{
// Clear the leftover in-memory data, so that they can't be accessed by a backdoor
memset(&m_Aes, 0, sizeof(m_Aes));
}
void cAESCFBEncryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
{
ASSERT(!IsValid()); // Cannot Init twice
ASSERT(m_IVOffset == 0);
memcpy(m_IV, a_IV, 16);
aes_setkey_enc(&m_Aes, a_Key, 128);
m_IsValid = true;
}
void cAESCFBEncryptor::ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length)
{
ASSERT(IsValid()); // Must Init() first
// PolarSSL doesn't do AES-CFB8, so we need to implement it ourselves:
for (size_t i = 0; i < a_Length; i++)
{
Byte Buffer[sizeof(m_IV)];
aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
{
m_IV[idx] = m_IV[idx + 1];
}
a_EncryptedOut[i] = a_PlainIn[i] ^ Buffer[0];
m_IV[sizeof(m_IV) - 1] = a_EncryptedOut[i];
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cSHA1Checksum:
cSHA1Checksum::cSHA1Checksum(void) :
m_DoesAcceptInput(true)
{
sha1_starts(&m_Sha1);
}
void cSHA1Checksum::Update(const Byte * a_Data, size_t a_Length)
{
ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
sha1_update(&m_Sha1, a_Data, a_Length);
}
void cSHA1Checksum::Finalize(cSHA1Checksum::Checksum & a_Output)
{
ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
sha1_finish(&m_Sha1, a_Output);
m_DoesAcceptInput = false;
}
void cSHA1Checksum::DigestToJava(const Checksum & a_Digest, AString & a_Out)
{
Checksum Digest;
memcpy(Digest, a_Digest, sizeof(Digest));
bool IsNegative = (Digest[0] >= 0x80);
if (IsNegative)
{
// Two's complement:
bool carry = true; // Add one to the whole number
for (int i = 19; i >= 0; i--)
{
Digest[i] = ~Digest[i];
if (carry)
{
carry = (Digest[i] == 0xff);
Digest[i]++;
}
}
}
a_Out.clear();
a_Out.reserve(40);
for (int i = 0; i < 20; i++)
{
AppendPrintf(a_Out, "%02x", Digest[i]);
}
while ((a_Out.length() > 0) && (a_Out[0] == '0'))
{
a_Out.erase(0, 1);
}
if (IsNegative)
{
a_Out.insert(0, "-");
}
}
void cSHA1Checksum::Restart(void)
{
sha1_starts(&m_Sha1);
m_DoesAcceptInput = true;
}

View File

@ -1,198 +0,0 @@
// Crypto.h
// Declares classes that wrap the cryptographic code library
#pragma once
#include "polarssl/rsa.h"
#include "polarssl/aes.h"
#include "polarssl/entropy.h"
#include "polarssl/ctr_drbg.h"
#include "polarssl/sha1.h"
#include "polarssl/pk.h"
/** Encapsulates an RSA private key used in PKI cryptography */
class cRSAPrivateKey
{
public:
/** Creates a new empty object, the key is not assigned */
cRSAPrivateKey(void);
/** Deep-copies the key from a_Other */
cRSAPrivateKey(const cRSAPrivateKey & a_Other);
~cRSAPrivateKey();
/** Generates a new key within this object, with the specified size in bits.
Returns true on success, false on failure. */
bool Generate(unsigned a_KeySizeBits = 1024);
/** Returns the public key part encoded in ASN1 DER encoding */
AString GetPubKeyDER(void);
/** Decrypts the data using RSAES-PKCS#1 algorithm.
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 RSAES-PKCS#1 algorithm.
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:
rsa_context m_Rsa;
entropy_context m_Entropy;
ctr_drbg_context m_Ctr_drbg;
/** Initializes the m_Entropy and m_Ctr_drbg contexts
Common part of this object's construction, called from all constructors. */
void InitRnd(void);
} ;
class cPublicKey
{
public:
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:
pk_context m_Pk;
entropy_context m_Entropy;
ctr_drbg_context m_Ctr_drbg;
/** Initializes the m_Entropy and m_Ctr_drbg contexts
Common part of this object's construction, called from all constructors. */
void InitRnd(void);
} ;
/** Decrypts data using the AES / CFB (128) algorithm */
class cAESCFBDecryptor
{
public:
Byte test;
cAESCFBDecryptor(void);
~cAESCFBDecryptor();
/** Initializes the decryptor with the specified Key / IV */
void Init(const Byte a_Key[16], const Byte a_IV[16]);
/** Decrypts a_Length bytes of the encrypted data; produces a_Length output bytes */
void ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length);
/** Returns true if the object has been initialized with the Key / IV */
bool IsValid(void) const { return m_IsValid; }
protected:
aes_context m_Aes;
/** The InitialVector, used by the CFB mode decryption */
Byte m_IV[16];
/** Current offset in the m_IV, used by the CFB mode decryption */
size_t m_IVOffset;
/** Indicates whether the object has been initialized with the Key / IV */
bool m_IsValid;
} ;
/** Encrypts data using the AES / CFB (128) algorithm */
class cAESCFBEncryptor
{
public:
cAESCFBEncryptor(void);
~cAESCFBEncryptor();
/** Initializes the decryptor with the specified Key / IV */
void Init(const Byte a_Key[16], const Byte a_IV[16]);
/** Encrypts a_Length bytes of the plain data; produces a_Length output bytes */
void ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length);
/** Returns true if the object has been initialized with the Key / IV */
bool IsValid(void) const { return m_IsValid; }
protected:
aes_context m_Aes;
/** The InitialVector, used by the CFB mode encryption */
Byte m_IV[16];
/** Current offset in the m_IV, used by the CFB mode encryption */
size_t m_IVOffset;
/** Indicates whether the object has been initialized with the Key / IV */
bool m_IsValid;
} ;
/** Calculates a SHA1 checksum for data stream */
class cSHA1Checksum
{
public:
typedef Byte Checksum[20]; // The type used for storing the checksum
cSHA1Checksum(void);
/** Adds the specified data to the checksum */
void Update(const Byte * a_Data, size_t a_Length);
/** Calculates and returns the final checksum */
void Finalize(Checksum & a_Output);
/** Returns true if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
bool DoesAcceptInput(void) const { return m_DoesAcceptInput; }
/** Converts a raw 160-bit SHA1 digest into a Java Hex representation
According to http://wiki.vg/wiki/index.php?title=Protocol_Encryption&oldid=2802
*/
static void DigestToJava(const Checksum & a_Digest, AString & a_JavaOut);
/** Clears the current context and start a new checksum calculation */
void Restart(void);
protected:
/** True if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
bool m_DoesAcceptInput;
sha1_context m_Sha1;
} ;

View File

@ -264,7 +264,21 @@ template class SizeChecker<UInt16, 2>;
// Same as assert but in all Self test builds
#ifdef SELF_TEST
#define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0))
#define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0))
#endif
// Allow both Older versions of MSVC and newer versions of everything use a shared_ptr:
// Note that we cannot typedef, because C++ doesn't allow (partial) templates to be typedeffed.
#if (defined(_MSC_VER) && (_MSC_VER < 1600))
// MSVC before 2010 doesn't have std::shared_ptr, but has std::tr1::shared_ptr, defined in <memory> included earlier
#define SharedPtr std::tr1::shared_ptr
#elif (__cplusplus >= 201103L)
// C++11 has std::shared_ptr in <memory>, included earlier
#define SharedPtr std::shared_ptr
#else
// C++03 has std::tr1::shared_ptr in <tr1/memory>
#include <tr1/memory>
#define SharedPtr std::tr1::shared_ptr
#endif
@ -296,7 +310,7 @@ T Clamp(T a_Value, T a_Min, T a_Max)
#ifndef TOLUA_TEMPLATE_BIND
#define TOLUA_TEMPLATE_BIND(x)
#define TOLUA_TEMPLATE_BIND(x)
#endif

View File

@ -295,7 +295,7 @@ bool cSocket::ConnectToLocalhostIPv4(unsigned short a_Port)
bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Port)
{
// First try IP Address string to hostent conversion, because it's faster
// First try IP Address string to hostent conversion, because it's faster and local:
unsigned long addr = inet_addr(a_HostNameOrAddr.c_str());
if (addr == INADDR_NONE)
{
@ -307,10 +307,16 @@ bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Por
CloseSocket();
return false;
}
// Should be optimised to a single word copy
memcpy(&addr, hp->h_addr, hp->h_length);
}
// If the socket is not created yet, create one:
if (!IsValid())
{
m_Socket = socket((int)IPv4, SOCK_STREAM, 0);
}
// Connect the socket:
sockaddr_in server;
server.sin_addr.s_addr = addr;
server.sin_family = AF_INET;

View File

@ -0,0 +1,67 @@
// AesCfb128Decryptor.cpp
// Implements the cAesCfb128Decryptor class decrypting data using AES CFB-128
#include "Globals.h"
#include "AesCfb128Decryptor.h"
cAesCfb128Decryptor::cAesCfb128Decryptor(void) :
m_IVOffset(0),
m_IsValid(false)
{
}
cAesCfb128Decryptor::~cAesCfb128Decryptor()
{
// Clear the leftover in-memory data, so that they can't be accessed by a backdoor
memset(&m_Aes, 0, sizeof(m_Aes));
}
void cAesCfb128Decryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
{
ASSERT(!IsValid()); // Cannot Init twice
memcpy(m_IV, a_IV, 16);
aes_setkey_enc(&m_Aes, a_Key, 128);
m_IsValid = true;
}
void cAesCfb128Decryptor::ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length)
{
ASSERT(IsValid()); // Must Init() first
// PolarSSL doesn't support AES-CFB8, need to implement it manually:
for (size_t i = 0; i < a_Length; i++)
{
Byte Buffer[sizeof(m_IV)];
aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
{
m_IV[idx] = m_IV[idx + 1];
}
m_IV[sizeof(m_IV) - 1] = a_EncryptedIn[i];
a_DecryptedOut[i] = a_EncryptedIn[i] ^ Buffer[0];
}
}

View File

@ -0,0 +1,52 @@
// AesCfb128Decryptor.h
// Declares the cAesCfb128Decryptor class decrypting data using AES CFB-128
#pragma once
#include "polarssl/aes.h"
/** Decrypts data using the AES / CFB 128 algorithm */
class cAesCfb128Decryptor
{
public:
Byte test;
cAesCfb128Decryptor(void);
~cAesCfb128Decryptor();
/** Initializes the decryptor with the specified Key / IV */
void Init(const Byte a_Key[16], const Byte a_IV[16]);
/** Decrypts a_Length bytes of the encrypted data; produces a_Length output bytes */
void ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length);
/** Returns true if the object has been initialized with the Key / IV */
bool IsValid(void) const { return m_IsValid; }
protected:
aes_context m_Aes;
/** The InitialVector, used by the CFB mode decryption */
Byte m_IV[16];
/** Current offset in the m_IV, used by the CFB mode decryption */
size_t m_IVOffset;
/** Indicates whether the object has been initialized with the Key / IV */
bool m_IsValid;
} ;

View File

@ -0,0 +1,68 @@
// AesCfb128Encryptor.cpp
// Implements the cAesCfb128Encryptor class encrypting data using AES CFB-128
#include "Globals.h"
#include "AesCfb128Encryptor.h"
cAesCfb128Encryptor::cAesCfb128Encryptor(void) :
m_IVOffset(0),
m_IsValid(false)
{
}
cAesCfb128Encryptor::~cAesCfb128Encryptor()
{
// Clear the leftover in-memory data, so that they can't be accessed by a backdoor
memset(&m_Aes, 0, sizeof(m_Aes));
}
void cAesCfb128Encryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
{
ASSERT(!IsValid()); // Cannot Init twice
ASSERT(m_IVOffset == 0);
memcpy(m_IV, a_IV, 16);
aes_setkey_enc(&m_Aes, a_Key, 128);
m_IsValid = true;
}
void cAesCfb128Encryptor::ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length)
{
ASSERT(IsValid()); // Must Init() first
// PolarSSL doesn't do AES-CFB8, so we need to implement it ourselves:
for (size_t i = 0; i < a_Length; i++)
{
Byte Buffer[sizeof(m_IV)];
aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
{
m_IV[idx] = m_IV[idx + 1];
}
a_EncryptedOut[i] = a_PlainIn[i] ^ Buffer[0];
m_IV[sizeof(m_IV) - 1] = a_EncryptedOut[i];
}
}

View File

@ -0,0 +1,50 @@
// AesCfb128Encryptor.h
// Declares the cAesCfb128Encryptor class encrypting data using AES CFB-128
#pragma once
#include "polarssl/aes.h"
/** Encrypts data using the AES / CFB (128) algorithm */
class cAesCfb128Encryptor
{
public:
cAesCfb128Encryptor(void);
~cAesCfb128Encryptor();
/** Initializes the decryptor with the specified Key / IV */
void Init(const Byte a_Key[16], const Byte a_IV[16]);
/** Encrypts a_Length bytes of the plain data; produces a_Length output bytes */
void ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length);
/** Returns true if the object has been initialized with the Key / IV */
bool IsValid(void) const { return m_IsValid; }
protected:
aes_context m_Aes;
/** The InitialVector, used by the CFB mode encryption */
Byte m_IV[16];
/** Current offset in the m_IV, used by the CFB mode encryption */
size_t m_IVOffset;
/** Indicates whether the object has been initialized with the Key / IV */
bool m_IsValid;
} ;

View File

@ -0,0 +1,195 @@
// BlockingSslClientSocket.cpp
// Implements the cBlockingSslClientSocket class representing a blocking TCP socket with client SSL encryption over it
#include "Globals.h"
#include "BlockingSslClientSocket.h"
cBlockingSslClientSocket::cBlockingSslClientSocket(void) :
m_Ssl(*this),
m_IsConnected(false)
{
// Nothing needed yet
}
bool cBlockingSslClientSocket::Connect(const AString & a_ServerName, UInt16 a_Port)
{
// If already connected, report an error:
if (m_IsConnected)
{
// TODO: Handle this better - if connected to the same server and port, and the socket is alive, return success
m_LastErrorText = "Already connected";
return false;
}
// Connect the underlying socket:
m_Socket.CreateSocket(cSocket::IPv4);
if (!m_Socket.ConnectIPv4(a_ServerName.c_str(), a_Port))
{
Printf(m_LastErrorText, "Socket connect failed: %s", m_Socket.GetLastErrorString().c_str());
return false;
}
// Initialize the SSL:
int ret = m_Ssl.Initialize(true);
if (ret != 0)
{
Printf(m_LastErrorText, "SSL initialization failed: -0x%x", -ret);
return false;
}
// If we have been assigned a trusted CA root cert store, push it into the SSL context:
if (m_CACerts.get() != NULL)
{
m_Ssl.SetCACerts(m_CACerts, m_ExpectedPeerName);
}
ret = m_Ssl.Handshake();
if (ret != 0)
{
Printf(m_LastErrorText, "SSL handshake failed: -0x%x", -ret);
return false;
}
m_IsConnected = true;
return true;
}
bool cBlockingSslClientSocket::SetTrustedRootCertsFromString(const AString & a_CACerts, const AString & a_ExpectedPeerName)
{
// Warn if used multiple times, but don't signal an error:
if (m_CACerts.get() != NULL)
{
LOGWARNING(
"SSL: Trying to set multiple trusted CA root cert stores, only the last one will be used. Name: %s",
a_ExpectedPeerName.c_str()
);
}
// Parse the cert:
m_CACerts.reset(new cX509Cert);
int ret = m_CACerts->Parse(a_CACerts.data(), a_CACerts.size());
if (ret < 0)
{
Printf(m_LastErrorText, "CA cert parsing failed: -0x%x", -ret);
return false;
}
m_ExpectedPeerName = a_ExpectedPeerName;
return true;
}
bool cBlockingSslClientSocket::Send(const void * a_Data, size_t a_NumBytes)
{
ASSERT(m_IsConnected);
// Keep sending the data until all of it is sent:
const char * Data = (const char *)a_Data;
size_t NumBytes = a_NumBytes;
for (;;)
{
int res = m_Ssl.WritePlain(a_Data, a_NumBytes);
if (res < 0)
{
ASSERT(res != POLARSSL_ERR_NET_WANT_READ); // This should never happen with callback-based SSL
ASSERT(res != POLARSSL_ERR_NET_WANT_WRITE); // This should never happen with callback-based SSL
Printf(m_LastErrorText, "Data cannot be written to SSL context: -0x%x", -res);
return false;
}
else
{
Data += res;
NumBytes -= res;
if (NumBytes == 0)
{
return true;
}
}
}
}
int cBlockingSslClientSocket::Receive(void * a_Data, size_t a_MaxBytes)
{
ASSERT(m_IsConnected);
int res = m_Ssl.ReadPlain(a_Data, a_MaxBytes);
if (res < 0)
{
Printf(m_LastErrorText, "Data cannot be read form SSL context: -0x%x", -res);
}
return res;
}
void cBlockingSslClientSocket::Disconnect(void)
{
// Ignore if not connected
if (!m_IsConnected)
{
return;
}
m_Ssl.NotifyClose();
m_Socket.CloseSocket();
m_IsConnected = false;
}
int cBlockingSslClientSocket::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes)
{
int res = m_Socket.Receive((char *)a_Buffer, a_NumBytes, 0);
if (res < 0)
{
// PolarSSL's net routines distinguish between connection reset and general failure, we don't need to
return POLARSSL_ERR_NET_RECV_FAILED;
}
return res;
}
int cBlockingSslClientSocket::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes)
{
int res = m_Socket.Send((const char *)a_Buffer, a_NumBytes);
if (res < 0)
{
// PolarSSL's net routines distinguish between connection reset and general failure, we don't need to
return POLARSSL_ERR_NET_SEND_FAILED;
}
return res;
}

View File

@ -0,0 +1,80 @@
// BlockingSslClientSocket.h
// Declares the cBlockingSslClientSocket class representing a blocking TCP socket with client SSL encryption over it
#pragma once
#include "CallbackSslContext.h"
#include "../OSSupport/Socket.h"
class cBlockingSslClientSocket :
protected cCallbackSslContext::cDataCallbacks
{
public:
cBlockingSslClientSocket(void);
/** Connects to the specified server and performs SSL handshake.
Returns true if successful, false on failure. Sets internal error text on failure. */
bool Connect(const AString & a_ServerName, UInt16 a_Port);
/** Sends the specified data over the connection.
Returns true if successful, false on failure. Sets the internal error text on failure. */
bool Send(const void * a_Data, size_t a_NumBytes);
/** Receives data from the connection.
Blocks until there is any data available, then returns as much as possible.
Returns the number of bytes actually received, negative number on failure.
Sets the internal error text on failure. */
int Receive(void * a_Data, size_t a_MaxBytes);
/** Disconnects the connection gracefully, if possible.
Note that this also frees the internal SSL context, so all the certificates etc. are lost. */
void Disconnect(void);
/** Sets the root certificates that are to be trusted. Forces the connection to use strict cert
verification. Needs to be used before calling Connect().
a_ExpectedPeerName is the name that we expect to receive in the SSL peer's cert; verification will fail if
the presented name is different (possible MITM).
Returns true on success, false on failure. Sets internal error text on failure. */
bool SetTrustedRootCertsFromString(const AString & a_CACerts, const AString & a_ExpectedPeerName);
/** Returns the text of the last error that has occurred in this instance. */
const AString & GetLastErrorText(void) const { return m_LastErrorText; }
protected:
/** The SSL context used for the socket */
cCallbackSslContext m_Ssl;
/** The underlying socket to the SSL server */
cSocket m_Socket;
/** The trusted CA root cert store, if we are to verify the cert strictly. Set by SetTrustedRootCertsFromString(). */
cX509CertPtr m_CACerts;
/** The expected SSL peer's name, if we are to verify the cert strictly. Set by SetTrustedRootCertsFromString(). */
AString m_ExpectedPeerName;
/** Text of the last error that has occurred. */
AString m_LastErrorText;
/** Set to true if the connection established successfully. */
bool m_IsConnected;
// cCallbackSslContext::cDataCallbacks overrides:
virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override;
virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override;
} ;

View File

@ -0,0 +1,62 @@
// BufferedSslContext.cpp
// Implements the cBufferedSslContext class representing a SSL context with the SSL peer data backed by a cByteBuffer
#include "Globals.h"
#include "BufferedSslContext.h"
cBufferedSslContext::cBufferedSslContext(size_t a_BufferSize):
m_OutgoingData(a_BufferSize),
m_IncomingData(a_BufferSize)
{
}
int cBufferedSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes)
{
// Called when PolarSSL wants to read encrypted data from the SSL peer
// Read the data from the buffer inside this object, where the owner has stored them using WriteIncoming():
size_t NumBytes = std::min(a_NumBytes, m_IncomingData.GetReadableSpace());
if (NumBytes == 0)
{
return POLARSSL_ERR_NET_WANT_READ;
}
if (!m_IncomingData.ReadBuf(a_Buffer, NumBytes))
{
m_IncomingData.ResetRead();
return POLARSSL_ERR_NET_RECV_FAILED;
}
m_IncomingData.CommitRead();
return (int)NumBytes;
}
int cBufferedSslContext::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes)
{
// Called when PolarSSL wants to write encrypted data to the SSL peer
// Write the data into the buffer inside this object, where the owner can later read them using ReadOutgoing():
if (!m_OutgoingData.CanWriteBytes(a_NumBytes))
{
return POLARSSL_ERR_NET_WANT_WRITE;
}
if (!m_OutgoingData.Write((const char *)a_Buffer, a_NumBytes))
{
return POLARSSL_ERR_NET_SEND_FAILED;
}
return (int)a_NumBytes;
}

View File

@ -0,0 +1,52 @@
// BufferedSslContext.h
// Declares the cBufferedSslContext class representing a SSL context with the SSL peer data backed by a cByteBuffer
#pragma once
#include "SslContext.h"
class cBufferedSslContext :
public cSslContext
{
typedef cSslContext super;
public:
/** Creates a new context with the buffers of specified size for the encrypted / decrypted data. */
cBufferedSslContext(size_t a_BufferSize = 64000);
/** Stores the specified data in the "incoming" buffer, to be process by the SSL decryptor.
This is the data received from the SSL peer.
Returns the number of bytes actually stored. If 0 is returned, owner should check the error state. */
size_t WriteIncoming(const void * a_Data, size_t a_NumBytes);
/** Retrieves data from the "outgoing" buffer, after being processed by the SSL encryptor.
This is the data to be sent to the SSL peer.
Returns the number of bytes actually retrieved. */
size_t ReadOutgoing(void * a_Data, size_t a_DataMaxSize);
protected:
/** Buffer for the data that has been encrypted into the SSL stream and should be sent out. */
cByteBuffer m_OutgoingData;
/** Buffer for the data that has come in and needs to be decrypted from the SSL stream. */
cByteBuffer m_IncomingData;
// cSslContext overrides:
virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override;
virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override;
} ;

View File

@ -0,0 +1,41 @@
cmake_minimum_required (VERSION 2.6)
project (MCServer)
include_directories ("${PROJECT_SOURCE_DIR}/../")
set(SOURCES
AesCfb128Decryptor.cpp
AesCfb128Encryptor.cpp
BlockingSslClientSocket.cpp
BufferedSslContext.cpp
CallbackSslContext.cpp
CtrDrbgContext.cpp
EntropyContext.cpp
PublicKey.cpp
RsaPrivateKey.cpp
Sha1Checksum.cpp
SslContext.cpp
X509Cert.cpp
)
set(HEADERS
AesCfb128Decryptor.h
AesCfb128Encryptor.h
BlockingSslClientSocket.h
BufferedSslContext.h
CallbackSslContext.h
CtrDrbgContext.h
EntropyContext.h
PublicKey.h
RsaPrivateKey.h
SslContext.h
Sha1Checksum.h
X509Cert.h
)
add_library(PolarSSL++ ${SOURCES} ${HEADERS})
if (UNIX)
target_link_libraries(PolarSSL++ polarssl)
endif()

View File

@ -0,0 +1,59 @@
// CallbackSslContext.cpp
// Declares the cCallbackSslContext class representing a SSL context wrapper that uses callbacks to read and write SSL peer data
#include "Globals.h"
#include "CallbackSslContext.h"
cCallbackSslContext::cCallbackSslContext(void)
{
// Nothing needed, but the constructor needs to exist so
}
cCallbackSslContext::cCallbackSslContext(cCallbackSslContext::cDataCallbacks & a_Callbacks) :
m_Callbacks(&a_Callbacks)
{
}
int cCallbackSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes)
{
if (m_Callbacks == NULL)
{
LOGWARNING("SSL: Trying to receive data with no callbacks, aborting.");
return POLARSSL_ERR_NET_RECV_FAILED;
}
return m_Callbacks->ReceiveEncrypted(a_Buffer, a_NumBytes);
}
int cCallbackSslContext::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes)
{
if (m_Callbacks == NULL)
{
LOGWARNING("SSL: Trying to send data with no callbacks, aborting.");
return POLARSSL_ERR_NET_SEND_FAILED;
}
return m_Callbacks->SendEncrypted(a_Buffer, a_NumBytes);
}

View File

@ -0,0 +1,61 @@
// CallbackSslContext.h
// Declares the cCallbackSslContext class representing a SSL context wrapper that uses callbacks to read and write SSL peer data
#pragma once
#include "SslContext.h"
class cCallbackSslContext :
public cSslContext
{
public:
/** Interface used as a data sink for the SSL peer data. */
class cDataCallbacks
{
public:
/** Called when PolarSSL wants to read encrypted data from the SSL peer.
The returned value is the number of bytes received, or a PolarSSL error on failure.
The implementation can return POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE to indicate
that there's currently no more data and that there might be more data in the future. In such cases the
SSL operation that invoked this call will terminate with the same return value, so that the owner is
notified of this condition and can potentially restart the operation later on. */
virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) = 0;
/** Called when PolarSSL wants to write encrypted data to the SSL peer.
The returned value is the number of bytes sent, or a PolarSSL error on failure.
The implementation can return POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE to indicate
that there's currently no more data and that there might be more data in the future. In such cases the
SSL operation that invoked this call will terminate with the same return value, so that the owner is
notified of this condition and can potentially restart the operation later on. */
virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) = 0;
} ;
/** Creates a new SSL context with no callbacks assigned */
cCallbackSslContext(void);
/** Creates a new SSL context with the specified callbacks */
cCallbackSslContext(cDataCallbacks & a_Callbacks);
protected:
/** The callbacks to use to send and receive SSL peer data */
cDataCallbacks * m_Callbacks;
// cSslContext overrides:
virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override;
virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override;
};

View File

@ -0,0 +1,49 @@
// CtrDrbgContext.cpp
// Implements the cCtrDrbgContext class representing a wrapper over CTR-DRBG implementation in PolarSSL
#include "Globals.h"
#include "CtrDrbgContext.h"
#include "EntropyContext.h"
cCtrDrbgContext::cCtrDrbgContext(void) :
m_EntropyContext(new cEntropyContext),
m_IsValid(false)
{
}
cCtrDrbgContext::cCtrDrbgContext(const SharedPtr<cEntropyContext> & a_EntropyContext) :
m_EntropyContext(a_EntropyContext),
m_IsValid(false)
{
}
int cCtrDrbgContext::Initialize(const void * a_Custom, size_t a_CustomSize)
{
if (m_IsValid)
{
// Already initialized
return 0;
}
int res = ctr_drbg_init(&m_CtrDrbg, entropy_func, &(m_EntropyContext->m_Entropy), (const unsigned char *)a_Custom, a_CustomSize);
m_IsValid = (res == 0);
return res;
}

View File

@ -0,0 +1,63 @@
// CtrDrbgContext.h
// Declares the cCtrDrbgContext class representing a wrapper over CTR-DRBG implementation in PolarSSL
#pragma once
#include "polarssl/ctr_drbg.h"
// fwd: EntropyContext.h
class cEntropyContext;
class cCtrDrbgContext
{
friend class cSslContext;
friend class cRsaPrivateKey;
friend class cPublicKey;
public:
/** Constructs the context with a new entropy context. */
cCtrDrbgContext(void);
/** Constructs the context with the specified entropy context. */
cCtrDrbgContext(const SharedPtr<cEntropyContext> & a_EntropyContext);
/** Initializes the context.
a_Custom is optional additional data to use for entropy, nullptr is accepted.
Returns 0 if successful, PolarSSL error code on failure. */
int Initialize(const void * a_Custom, size_t a_CustomSize);
/** Returns true if the object is valid (has been initialized properly) */
bool IsValid(void) const { return m_IsValid; }
protected:
/** The entropy source used for generating the random */
SharedPtr<cEntropyContext> m_EntropyContext;
/** The random generator context */
ctr_drbg_context m_CtrDrbg;
/** Set to true if the object is valid (has been initialized properly) */
bool m_IsValid;
/** Returns the internal context ptr. Only use in PolarSSL API calls. */
ctr_drbg_context * GetInternal(void) { return &m_CtrDrbg; }
} ;

View File

@ -0,0 +1,29 @@
// EntropyContext.cpp
// Implements the cEntropyContext class representing a wrapper over entropy contexts in PolarSSL
#include "Globals.h"
#include "EntropyContext.h"
cEntropyContext::cEntropyContext(void)
{
entropy_init(&m_Entropy);
}
cEntropyContext::~cEntropyContext()
{
entropy_free(&m_Entropy);
}

View File

@ -0,0 +1,31 @@
// EntropyContext.h
// Declares the cEntropyContext class representing a wrapper over entropy contexts in PolarSSL
#pragma once
#include "polarssl/entropy.h"
class cEntropyContext
{
friend class cCtrDrbgContext;
public:
cEntropyContext(void);
~cEntropyContext();
protected:
entropy_context m_Entropy;
} ;

View File

@ -0,0 +1,73 @@
// 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;
}

View File

@ -0,0 +1,48 @@
// 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;
} ;

View File

@ -0,0 +1,176 @@
// RsaPrivateKey.cpp
#include "Globals.h"
#include "RsaPrivateKey.h"
#include "CtrDrbgContext.h"
#include "polarssl/pk.h"
cRsaPrivateKey::cRsaPrivateKey(void)
{
rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
m_CtrDrbg.Initialize("RSA", 3);
}
cRsaPrivateKey::cRsaPrivateKey(const cRsaPrivateKey & a_Other)
{
rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
rsa_copy(&m_Rsa, &a_Other.m_Rsa);
m_CtrDrbg.Initialize("RSA", 3);
}
cRsaPrivateKey::~cRsaPrivateKey()
{
rsa_free(&m_Rsa);
}
bool cRsaPrivateKey::Generate(unsigned a_KeySizeBits)
{
int res = rsa_gen_key(&m_Rsa, ctr_drbg_random, m_CtrDrbg.GetInternal(), a_KeySizeBits, 65537);
if (res != 0)
{
LOG("RSA key generation failed: -0x%x", -res);
return false;
}
return true;
}
AString cRsaPrivateKey::GetPubKeyDER(void)
{
class cPubKey
{
public:
cPubKey(rsa_context * a_Rsa) :
m_IsValid(false)
{
pk_init(&m_Key);
if (pk_init_ctx(&m_Key, pk_info_from_type(POLARSSL_PK_RSA)) != 0)
{
ASSERT(!"Cannot init PrivKey context");
return;
}
if (rsa_copy(pk_rsa(m_Key), a_Rsa) != 0)
{
ASSERT(!"Cannot copy PrivKey to PK context");
return;
}
m_IsValid = true;
}
~cPubKey()
{
if (m_IsValid)
{
pk_free(&m_Key);
}
}
operator pk_context * (void) { return &m_Key; }
protected:
bool m_IsValid;
pk_context m_Key;
} PkCtx(&m_Rsa);
unsigned char buf[3000];
int res = pk_write_pubkey_der(PkCtx, buf, sizeof(buf));
if (res < 0)
{
return AString();
}
return AString((const char *)(buf + sizeof(buf) - res), (size_t)res);
}
int cRsaPrivateKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
{
if (a_EncryptedLength < m_Rsa.len)
{
LOGD("%s: Invalid a_EncryptedLength: got %u, exp at least %u",
__FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len)
);
ASSERT(!"Invalid a_DecryptedMaxLength!");
return -1;
}
if (a_DecryptedMaxLength < m_Rsa.len)
{
LOGD("%s: Invalid a_DecryptedMaxLength: got %u, exp at least %u",
__FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len)
);
ASSERT(!"Invalid a_DecryptedMaxLength!");
return -1;
}
size_t DecryptedLength;
int res = rsa_pkcs1_decrypt(
&m_Rsa, ctr_drbg_random, m_CtrDrbg.GetInternal(), RSA_PRIVATE, &DecryptedLength,
a_EncryptedData, a_DecryptedData, a_DecryptedMaxLength
);
if (res != 0)
{
return -1;
}
return (int)DecryptedLength;
}
int cRsaPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
{
if (a_EncryptedMaxLength < m_Rsa.len)
{
LOGD("%s: Invalid a_EncryptedMaxLength: got %u, exp at least %u",
__FUNCTION__, (unsigned)a_EncryptedMaxLength, (unsigned)(m_Rsa.len)
);
ASSERT(!"Invalid a_DecryptedMaxLength!");
return -1;
}
if (a_PlainLength < m_Rsa.len)
{
LOGD("%s: Invalid a_PlainLength: got %u, exp at least %u",
__FUNCTION__, (unsigned)a_PlainLength, (unsigned)(m_Rsa.len)
);
ASSERT(!"Invalid a_PlainLength!");
return -1;
}
int res = rsa_pkcs1_encrypt(
&m_Rsa, ctr_drbg_random, m_CtrDrbg.GetInternal(), RSA_PRIVATE,
a_PlainLength, a_PlainData, a_EncryptedData
);
if (res != 0)
{
return -1;
}
return (int)m_Rsa.len;
}

View File

@ -0,0 +1,59 @@
// RsaPrivateKey.h
// Declares the cRsaPrivateKey class representing a private key for RSA operations.
#pragma once
#include "CtrDrbgContext.h"
#include "polarssl/rsa.h"
/** Encapsulates an RSA private key used in PKI cryptography */
class cRsaPrivateKey
{
public:
/** Creates a new empty object, the key is not assigned */
cRsaPrivateKey(void);
/** Deep-copies the key from a_Other */
cRsaPrivateKey(const cRsaPrivateKey & a_Other);
~cRsaPrivateKey();
/** Generates a new key within this object, with the specified size in bits.
Returns true on success, false on failure. */
bool Generate(unsigned a_KeySizeBits = 1024);
/** Returns the public key part encoded in ASN1 DER encoding */
AString GetPubKeyDER(void);
/** Decrypts the data using RSAES-PKCS#1 algorithm.
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 RSAES-PKCS#1 algorithm.
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 PolarSSL key context */
rsa_context m_Rsa;
/** The random generator used for generating the key and encryption / decryption */
cCtrDrbgContext m_CtrDrbg;
} ;

View File

@ -0,0 +1,138 @@
// Sha1Checksum.cpp
// Declares the cSha1Checksum class representing the SHA-1 checksum calculator
#include "Globals.h"
#include "Sha1Checksum.h"
/*
// Self-test the hash formatting for known values:
// sha1(Notch) : 4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48
// sha1(jeb_) : -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1
// sha1(simon) : 88e16a1019277b15d58faf0541e11910eb756f6
static class Test
{
public:
Test(void)
{
AString DigestNotch, DigestJeb, DigestSimon;
Byte Digest[20];
cSha1Checksum Checksum;
Checksum.Update((const Byte *)"Notch", 5);
Checksum.Finalize(Digest);
cSha1Checksum::DigestToJava(Digest, DigestNotch);
Checksum.Restart();
Checksum.Update((const Byte *)"jeb_", 4);
Checksum.Finalize(Digest);
cSha1Checksum::DigestToJava(Digest, DigestJeb);
Checksum.Restart();
Checksum.Update((const Byte *)"simon", 5);
Checksum.Finalize(Digest);
cSha1Checksum::DigestToJava(Digest, DigestSimon);
printf("Notch: \"%s\"\n", DigestNotch.c_str());
printf("jeb_: \"%s\"\n", DigestJeb.c_str());
printf("simon: \"%s\"\n", DigestSimon.c_str());
assert(DigestNotch == "4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48");
assert(DigestJeb == "-7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1");
assert(DigestSimon == "88e16a1019277b15d58faf0541e11910eb756f6");
}
} test;
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cSha1Checksum:
cSha1Checksum::cSha1Checksum(void) :
m_DoesAcceptInput(true)
{
sha1_starts(&m_Sha1);
}
void cSha1Checksum::Update(const Byte * a_Data, size_t a_Length)
{
ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
sha1_update(&m_Sha1, a_Data, a_Length);
}
void cSha1Checksum::Finalize(cSha1Checksum::Checksum & a_Output)
{
ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
sha1_finish(&m_Sha1, a_Output);
m_DoesAcceptInput = false;
}
void cSha1Checksum::DigestToJava(const Checksum & a_Digest, AString & a_Out)
{
Checksum Digest;
memcpy(Digest, a_Digest, sizeof(Digest));
bool IsNegative = (Digest[0] >= 0x80);
if (IsNegative)
{
// Two's complement:
bool carry = true; // Add one to the whole number
for (int i = 19; i >= 0; i--)
{
Digest[i] = ~Digest[i];
if (carry)
{
carry = (Digest[i] == 0xff);
Digest[i]++;
}
}
}
a_Out.clear();
a_Out.reserve(40);
for (int i = 0; i < 20; i++)
{
AppendPrintf(a_Out, "%02x", Digest[i]);
}
while ((a_Out.length() > 0) && (a_Out[0] == '0'))
{
a_Out.erase(0, 1);
}
if (IsNegative)
{
a_Out.insert(0, "-");
}
}
void cSha1Checksum::Restart(void)
{
sha1_starts(&m_Sha1);
m_DoesAcceptInput = true;
}

View File

@ -0,0 +1,52 @@
// Sha1Checksum.h
// Declares the cSha1Checksum class representing the SHA-1 checksum calculator
#pragma once
#include "polarssl/sha1.h"
/** Calculates a SHA1 checksum for data stream */
class cSha1Checksum
{
public:
typedef Byte Checksum[20]; // The type used for storing the checksum
cSha1Checksum(void);
/** Adds the specified data to the checksum */
void Update(const Byte * a_Data, size_t a_Length);
/** Calculates and returns the final checksum */
void Finalize(Checksum & a_Output);
/** Returns true if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
bool DoesAcceptInput(void) const { return m_DoesAcceptInput; }
/** Converts a raw 160-bit SHA1 digest into a Java Hex representation
According to http://wiki.vg/wiki/index.php?title=Protocol_Encryption&oldid=2802
*/
static void DigestToJava(const Checksum & a_Digest, AString & a_JavaOut);
/** Clears the current context and start a new checksum calculation */
void Restart(void);
protected:
/** True if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
bool m_DoesAcceptInput;
sha1_context m_Sha1;
} ;

View File

@ -0,0 +1,243 @@
// SslContext.cpp
// Implements the cSslContext class that holds everything a single SSL context needs to function
#include "Globals.h"
#include "SslContext.h"
#include "EntropyContext.h"
#include "CtrDrbgContext.h"
cSslContext::cSslContext(void) :
m_IsValid(false),
m_HasHandshaken(false)
{
}
cSslContext::~cSslContext()
{
if (m_IsValid)
{
ssl_free(&m_Ssl);
}
}
int cSslContext::Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> & a_CtrDrbg)
{
// Check double-initialization:
if (m_IsValid)
{
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.
}
// Set the CtrDrbg context, create a new one if needed:
m_CtrDrbg = a_CtrDrbg;
if (m_CtrDrbg.get() == NULL)
{
m_CtrDrbg.reset(new cCtrDrbgContext);
m_CtrDrbg->Initialize("MCServer", 8);
}
// Initialize PolarSSL's structures:
memset(&m_Ssl, 0, sizeof(m_Ssl));
int res = ssl_init(&m_Ssl);
if (res != 0)
{
return res;
}
ssl_set_endpoint(&m_Ssl, a_IsClient ? SSL_IS_CLIENT : SSL_IS_SERVER);
ssl_set_authmode(&m_Ssl, SSL_VERIFY_OPTIONAL);
ssl_set_rng(&m_Ssl, ctr_drbg_random, &m_CtrDrbg->m_CtrDrbg);
ssl_set_bio(&m_Ssl, ReceiveEncrypted, this, SendEncrypted, this);
#ifdef _DEBUG
/*
// These functions allow us to debug SSL and certificate problems, but produce way too much output,
// so they're disabled until someone needs them
ssl_set_dbg(&m_Ssl, &SSLDebugMessage, this);
ssl_set_verify(&m_Ssl, &SSLVerifyCert, this);
*/
#endif
m_IsValid = true;
return 0;
}
void cSslContext::SetCACerts(const cX509CertPtr & a_CACert, const AString & a_ExpectedPeerName)
{
// 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:
m_ExpectedPeerName = a_ExpectedPeerName;
m_CACerts = a_CACert;
// Set the trusted CA root cert store:
ssl_set_authmode(&m_Ssl, SSL_VERIFY_REQUIRED);
ssl_set_ca_chain(&m_Ssl, m_CACerts->GetInternal(), NULL, m_ExpectedPeerName.empty() ? NULL : m_ExpectedPeerName.c_str());
}
int cSslContext::WritePlain(const void * a_Data, size_t a_NumBytes)
{
ASSERT(m_IsValid); // Need to call Initialize() first
if (!m_HasHandshaken)
{
int res = Handshake();
if (res != 0)
{
return res;
}
}
return ssl_write(&m_Ssl, (const unsigned char *)a_Data, a_NumBytes);
}
int cSslContext::ReadPlain(void * a_Data, size_t a_MaxBytes)
{
ASSERT(m_IsValid); // Need to call Initialize() first
if (!m_HasHandshaken)
{
int res = Handshake();
if (res != 0)
{
return res;
}
}
return ssl_read(&m_Ssl, (unsigned char *)a_Data, a_MaxBytes);
}
int cSslContext::Handshake(void)
{
ASSERT(m_IsValid); // Need to call Initialize() first
ASSERT(!m_HasHandshaken); // Must not call twice
int res = ssl_handshake(&m_Ssl);
if (res == 0)
{
m_HasHandshaken = true;
}
return res;
}
int cSslContext::NotifyClose(void)
{
return ssl_close_notify(&m_Ssl);
}
#ifdef _DEBUG
void cSslContext::SSLDebugMessage(void * a_UserParam, int a_Level, const char * a_Text)
{
if (a_Level > 3)
{
// Don't want the trace messages
return;
}
// Remove the terminating LF:
size_t len = strlen(a_Text) - 1;
while ((len > 0) && (a_Text[len] <= 32))
{
len--;
}
AString Text(a_Text, len + 1);
LOGD("SSL (%d): %s", a_Level, Text.c_str());
}
int cSslContext::SSLVerifyCert(void * a_This, x509_crt * a_Crt, int a_Depth, int * a_Flags)
{
char buf[1024];
UNUSED(a_This);
LOG("Verify requested for (Depth %d):", a_Depth);
x509_crt_info(buf, sizeof(buf) - 1, "", a_Crt);
LOG("%s", buf);
int Flags = *a_Flags;
if ((Flags & BADCERT_EXPIRED) != 0)
{
LOG(" ! server certificate has expired");
}
if ((Flags & BADCERT_REVOKED) != 0)
{
LOG(" ! server certificate has been revoked");
}
if ((Flags & BADCERT_CN_MISMATCH) != 0)
{
LOG(" ! CN mismatch");
}
if ((Flags & BADCERT_NOT_TRUSTED) != 0)
{
LOG(" ! self-signed or not signed by a trusted CA");
}
if ((Flags & BADCRL_NOT_TRUSTED) != 0)
{
LOG(" ! CRL not trusted");
}
if ((Flags & BADCRL_EXPIRED) != 0)
{
LOG(" ! CRL expired");
}
if ((Flags & BADCERT_OTHER) != 0)
{
LOG(" ! other (unknown) flag");
}
if (Flags == 0)
{
LOG(" This certificate has no flags");
}
return 0;
}
#endif // _DEBUG

137
src/PolarSSL++/SslContext.h Normal file
View File

@ -0,0 +1,137 @@
// SslContext.h
// Declares the cSslContext class that holds everything a single SSL context needs to function
#pragma once
#include "polarssl/ssl.h"
#include "../ByteBuffer.h"
#include "X509Cert.h"
// fwd:
class cCtrDrbgContext;
/**
Acts as a generic SSL encryptor / decryptor between the two endpoints. The "owner" of this class is expected
to create it, initialize it and then provide the means of reading and writing data through the SSL link.
This is an abstract base class, there are descendants that handle the specific aspects of how the SSL peer
data comes into the system:
- cBufferedSslContext uses a cByteBuffer to read and write the data
- cCallbackSslContext uses callbacks to provide the data
*/
class cSslContext abstract
{
public:
/** Creates a new uninitialized context */
cSslContext(void);
~cSslContext();
/** Initializes the context for use as a server or client.
Returns 0 on success, PolarSSL error on failure. */
int Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> & a_CtrDrbg = SharedPtr<cCtrDrbgContext>());
/** Returns true if the object has been initialized properly. */
bool IsValid(void) const { return m_IsValid; }
/** Sets a cert chain as the trusted cert store for this context.
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,
if it is different, the verification will fail. An empty string will disable the CN check. */
void SetCACerts(const cX509CertPtr & a_CACert, const AString & a_ExpectedPeerName);
/** Writes data to be encrypted and sent to the SSL peer. Will perform SSL handshake, if needed.
Returns the number of bytes actually written, or PolarSSL error code.
If the return value is POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE, the owner should send any
cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call
this function again with the same parameters. Note that this may repeat a few times before the data is
actually written, mainly due to initial handshake. */
int WritePlain(const void * a_Data, size_t a_NumBytes);
/** Reads data decrypted from the SSL stream. Will perform SSL handshake, if needed.
Returns the number of bytes actually read, or PolarSSL error code.
If the return value is POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE, the owner should send any
cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call
this function again with the same parameters. Note that this may repeat a few times before the data is
actually read, mainly due to initial handshake. */
int ReadPlain(void * a_Data, size_t a_MaxBytes);
/** Performs the SSL handshake.
Returns zero on success, PoladSSL error code on failure.
If the return value is POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE, the owner should send any
cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call
this function again. Note that this may repeat a few times before the handshake is completed. */
int Handshake(void);
/** Returns true if the SSL handshake has been completed. */
bool HasHandshaken(void) const { return m_HasHandshaken; }
/** Notifies the SSL peer that the connection is being closed.
Returns 0 on success, PolarSSL error code on failure. */
int NotifyClose(void);
protected:
/** True if the object has been initialized properly. */
bool m_IsValid;
/** The random generator to use */
SharedPtr<cCtrDrbgContext> m_CtrDrbg;
/** The SSL context that PolarSSL uses. */
ssl_context m_Ssl;
/** True if the SSL handshake has been completed. */
bool m_HasHandshaken;
/** A copy of the trusted CA root cert store that is passed to us in SetCACerts(), so that the pointer
stays valid even after the call, when PolarSSL finally uses it. */
cX509CertPtr m_CACerts;
/** Buffer for the expected peer name. We need to buffer it because the caller may free the string they
give us before PolarSSL consumes the raw pointer it gets to the CN. */
AString m_ExpectedPeerName;
/** The callback used by PolarSSL when it wants to read encrypted data. */
static int ReceiveEncrypted(void * a_This, unsigned char * a_Buffer, size_t a_NumBytes)
{
return ((cSslContext *)a_This)->ReceiveEncrypted(a_Buffer, a_NumBytes);
}
/** The callback used by PolarSSL when it wants to write encrypted data. */
static int SendEncrypted(void * a_This, const unsigned char * a_Buffer, size_t a_NumBytes)
{
return ((cSslContext *)a_This)->SendEncrypted(a_Buffer, a_NumBytes);
}
#ifdef _DEBUG
/** The callback used by PolarSSL to output debug messages */
static void SSLDebugMessage(void * a_UserParam, int a_Level, const char * a_Text);
/** The callback used by PolarSSL to log information on the cert chain */
static int SSLVerifyCert(void * a_This, x509_crt * a_Crt, int a_Depth, int * a_Flags);
#endif // _DEBUG
/** Called when PolarSSL wants to read encrypted data. */
virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) = 0;
/** Called when PolarSSL wants to write encrypted data. */
virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) = 0;
} ;

View File

@ -0,0 +1,38 @@
// X509Cert.cpp
// Implements the cX509Cert class representing a wrapper over X509 certs in PolarSSL
#include "Globals.h"
#include "X509Cert.h"
cX509Cert::cX509Cert(void)
{
x509_crt_init(&m_Cert);
}
cX509Cert::~cX509Cert()
{
x509_crt_free(&m_Cert);
}
int cX509Cert::Parse(const void * a_CertContents, size_t a_Size)
{
return x509_crt_parse(&m_Cert, (const unsigned char *)a_CertContents, a_Size);
}

41
src/PolarSSL++/X509Cert.h Normal file
View File

@ -0,0 +1,41 @@
// X509Cert.h
// Declares the cX509Cert class representing a wrapper over X509 certs in PolarSSL
#pragma once
#include "polarssl/x509_crt.h"
class cX509Cert
{
friend class cSslContext;
public:
cX509Cert(void);
~cX509Cert(void);
/** Parses the certificate chain data into the context.
Returns 0 on succes, or PolarSSL error code on failure. */
int Parse(const void * a_CertContents, size_t a_Size);
protected:
x509_crt m_Cert;
/** Returns the internal cert ptr. Only use in PolarSSL API calls. */
x509_crt * GetInternal(void) { return &m_Cert; }
} ;
typedef SharedPtr<cX509Cert> cX509CertPtr;

View File

@ -10,13 +10,7 @@
#include "inifile/iniFile.h"
#include "json/json.h"
#include "polarssl/config.h"
#include "polarssl/net.h"
#include "polarssl/ssl.h"
#include "polarssl/entropy.h"
#include "polarssl/ctr_drbg.h"
#include "polarssl/error.h"
#include "polarssl/certs.h"
#include "PolarSSL++/BlockingSslClientSocket.h"
#include <sstream>
#include <iomanip>
@ -148,92 +142,74 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
{
LOGD("Trying to auth user %s", a_UserName.c_str());
int ret, server_fd = -1;
int ret;
unsigned char buf[1024];
const char *pers = "cAuthenticator";
entropy_context entropy;
ctr_drbg_context ctr_drbg;
ssl_context ssl;
x509_crt cacert;
/* Initialize the RNG and the session data */
memset(&ssl, 0, sizeof(ssl_context));
x509_crt_init(&cacert);
entropy_init(&entropy);
if ((ret = ctr_drbg_init(&ctr_drbg, entropy_func, &entropy, (const unsigned char *)pers, strlen(pers))) != 0)
{
LOGWARNING("cAuthenticator: ctr_drbg_init returned %d", ret);
// Free all resources which have been initialized up to this line
x509_crt_free(&cacert);
entropy_free(&entropy);
return false;
}
/* Initialize certificates */
// TODO: Grab the sessionserver's root CA and any intermediates and hard-code them here, instead of test_ca_list
ret = x509_crt_parse(&cacert, (const unsigned char *)test_ca_list, strlen(test_ca_list));
// This is the data of the root certs for Starfield Technologies, the CA that signed sessionserver.mojang.com's cert:
// Downloaded from http://certs.starfieldtech.com/repository/
static const AString StarfieldCACert(
// G2 cert
"-----BEGIN CERTIFICATE-----\n"
"MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx\n"
"EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT\n"
"HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs\n"
"ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw\n"
"MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6\n"
"b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj\n"
"aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp\n"
"Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n"
"ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg\n"
"nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1\n"
"HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N\n"
"Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN\n"
"dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0\n"
"HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO\n"
"BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G\n"
"CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU\n"
"sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3\n"
"4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg\n"
"8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K\n"
"pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1\n"
"mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0\n"
"-----END CERTIFICATE-----\n\n"
// Original (G1) cert:
"-----BEGIN CERTIFICATE-----\n"
"MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl\n"
"MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp\n"
"U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw\n"
"NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE\n"
"ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp\n"
"ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3\n"
"DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf\n"
"8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN\n"
"+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0\n"
"X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa\n"
"K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA\n"
"1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G\n"
"A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR\n"
"zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0\n"
"YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD\n"
"bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w\n"
"DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3\n"
"L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D\n"
"eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl\n"
"xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp\n"
"VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY\n"
"WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=\n"
"-----END CERTIFICATE-----\n"
);
if (ret < 0)
// Connect the socket:
cBlockingSslClientSocket Socket;
Socket.SetTrustedRootCertsFromString(StarfieldCACert, m_Server);
if (!Socket.Connect(m_Server, 443))
{
LOGWARNING("cAuthenticator: x509_crt_parse returned -0x%x", -ret);
// Free all resources which have been initialized up to this line
x509_crt_free(&cacert);
entropy_free(&entropy);
LOGWARNING("cAuthenticator: Can't connect to %s: %s", m_Server.c_str(), Socket.GetLastErrorText().c_str());
return false;
}
/* Connect */
if ((ret = net_connect(&server_fd, m_Server.c_str(), 443)) != 0)
{
LOGWARNING("cAuthenticator: Can't connect to %s: %d", m_Server.c_str(), ret);
// Free all resources which have been initialized up to this line
x509_crt_free(&cacert);
entropy_free(&entropy);
return false;
}
/* Setup */
if ((ret = ssl_init(&ssl)) != 0)
{
LOGWARNING("cAuthenticator: ssl_init returned %d", ret);
// Free all resources which have been initialized up to this line
x509_crt_free(&cacert);
net_close(server_fd);
ssl_free(&ssl);
entropy_free(&entropy);
memset(&ssl, 0, sizeof(ssl));
return false;
}
ssl_set_endpoint(&ssl, SSL_IS_CLIENT);
ssl_set_authmode(&ssl, SSL_VERIFY_OPTIONAL);
ssl_set_ca_chain(&ssl, &cacert, NULL, "PolarSSL Server 1");
ssl_set_rng(&ssl, ctr_drbg_random, &ctr_drbg);
ssl_set_bio(&ssl, net_recv, &server_fd, net_send, &server_fd);
/* Handshake */
while ((ret = ssl_handshake(&ssl)) != 0)
{
if ((ret != POLARSSL_ERR_NET_WANT_READ) && (ret != POLARSSL_ERR_NET_WANT_WRITE))
{
LOGWARNING("cAuthenticator: ssl_handshake returned -0x%x", -ret);
// Free all resources which have been initialized up to this line
x509_crt_free(&cacert);
net_close(server_fd);
ssl_free(&ssl);
entropy_free(&entropy);
memset(&ssl, 0, sizeof(ssl));
return false;
}
}
/* Write the GET request */
// Create the GET request:
AString ActualAddress = m_Address;
ReplaceString(ActualAddress, "%USERNAME%", a_UserName);
ReplaceString(ActualAddress, "%SERVERID%", a_ServerId);
@ -245,30 +221,23 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
Request += "Connection: close\r\n";
Request += "\r\n";
ret = ssl_write(&ssl, (const unsigned char *)Request.c_str(), Request.size());
if (ret <= 0)
if (!Socket.Send(Request.c_str(), Request.size()))
{
LOGWARNING("cAuthenticator: ssl_write returned %d", ret);
// Free all resources which have been initialized up to this line
x509_crt_free(&cacert);
net_close(server_fd);
ssl_free(&ssl);
entropy_free(&entropy);
memset(&ssl, 0, sizeof(ssl));
LOGWARNING("cAuthenticator: Writing SSL data failed: %s", Socket.GetLastErrorText().c_str());
return false;
}
/* Read the HTTP response */
// Read the HTTP response:
std::string Response;
for (;;)
{
memset(buf, 0, sizeof(buf));
ret = ssl_read(&ssl, buf, sizeof(buf));
ret = Socket.Receive(buf, sizeof(buf));
if ((ret == POLARSSL_ERR_NET_WANT_READ) || (ret == POLARSSL_ERR_NET_WANT_WRITE))
{
continue;
// This value should never be returned, it is handled internally by cBlockingSslClientSocket
LOGWARNING("cAuthenticator: SSL reading failed internally.");
return false;
}
if (ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY)
{
@ -276,24 +245,18 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
}
if (ret < 0)
{
LOGWARNING("cAuthenticator: ssl_read returned %d", ret);
break;
LOGWARNING("cAuthenticator: SSL reading failed: -0x%x", -ret);
return false;
}
if (ret == 0)
{
LOGWARNING("cAuthenticator: EOF");
break;
}
Response.append((const char *)buf, ret);
}
Response.append((const char *)buf, (size_t)ret);
}
ssl_close_notify(&ssl);
x509_crt_free(&cacert);
net_close(server_fd);
ssl_free(&ssl);
entropy_free(&entropy);
memset(&ssl, 0, sizeof(ssl));
Socket.Disconnect();
// Check the HTTP status line:
AString prefix("HTTP/1.1 200 OK");

View File

@ -18,19 +18,7 @@
#include "../WorldStorage/FastNBT.h"
#include "../WorldStorage/EnchantmentSerializer.h"
#include "../StringCompression.h"
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4127)
#pragma warning(disable:4244)
#pragma warning(disable:4231)
#pragma warning(disable:4189)
#pragma warning(disable:4702)
#endif
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include "PolarSSL++/Sha1Checksum.h"
@ -819,7 +807,7 @@ void cProtocol132::SendEncryptionKeyRequest(void)
void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce)
{
// Decrypt EncNonce using privkey
cRSAPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
int res = rsaDecryptor.Decrypt((const Byte *)a_EncNonce.data(), a_EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce));
@ -876,7 +864,7 @@ void cProtocol132::StartEncryption(const Byte * a_Key)
m_IsEncrypted = true;
// Prepare the m_AuthServerID:
cSHA1Checksum Checksum;
cSha1Checksum Checksum;
cServer * Server = cRoot::Get()->GetServer();
AString ServerID = Server->GetServerID();
Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length());
@ -884,7 +872,7 @@ void cProtocol132::StartEncryption(const Byte * a_Key)
Checksum.Update((const Byte *)Server->GetPublicKeyDER().data(), Server->GetPublicKeyDER().size());
Byte Digest[20];
Checksum.Finalize(Digest);
cSHA1Checksum::DigestToJava(Digest, m_AuthServerID);
cSha1Checksum::DigestToJava(Digest, m_AuthServerID);
}

View File

@ -24,7 +24,8 @@
#pragma warning(pop)
#endif
#include "../Crypto.h"
#include "PolarSSL++/AesCfb128Decryptor.h"
#include "PolarSSL++/AesCfb128Encryptor.h"
@ -79,8 +80,8 @@ public:
protected:
bool m_IsEncrypted;
cAESCFBDecryptor m_Decryptor;
cAESCFBEncryptor m_Encryptor;
cAesCfb128Decryptor m_Decryptor;
cAesCfb128Encryptor m_Encryptor;
AString m_DataToSend;

View File

@ -33,6 +33,7 @@ Implements the 1.7.x protocol classes:
#include "../CompositeChat.h"
#include "../Entities/ArrowEntity.h"
#include "../Entities/FireworkEntity.h"
#include "PolarSSL++/Sha1Checksum.h"
@ -1690,7 +1691,7 @@ void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffe
}
// Decrypt EncNonce using privkey
cRSAPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
int res = rsaDecryptor.Decrypt((const Byte *)EncNonce.data(), EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce));
if (res != 4)
@ -2293,7 +2294,7 @@ void cProtocol172::StartEncryption(const Byte * a_Key)
m_IsEncrypted = true;
// Prepare the m_AuthServerID:
cSHA1Checksum Checksum;
cSha1Checksum Checksum;
cServer * Server = cRoot::Get()->GetServer();
const AString & ServerID = Server->GetServerID();
Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length());
@ -2301,7 +2302,7 @@ void cProtocol172::StartEncryption(const Byte * a_Key)
Checksum.Update((const Byte *)Server->GetPublicKeyDER().data(), Server->GetPublicKeyDER().size());
Byte Digest[20];
Checksum.Finalize(Digest);
cSHA1Checksum::DigestToJava(Digest, m_AuthServerID);
cSha1Checksum::DigestToJava(Digest, m_AuthServerID);
}

View File

@ -30,7 +30,8 @@ Declares the 1.7.x protocol classes:
#pragma warning(pop)
#endif
#include "../Crypto.h"
#include "PolarSSL++/AesCfb128Decryptor.h"
#include "PolarSSL++/AesCfb128Encryptor.h"
@ -236,8 +237,8 @@ protected:
bool m_IsEncrypted;
cAESCFBDecryptor m_Decryptor;
cAESCFBEncryptor m_Encryptor;
cAesCfb128Decryptor m_Decryptor;
cAesCfb128Decryptor m_Encryptor;
/** The logfile where the comm is logged, when g_ShouldLogComm is true */
cFile m_CommLogFile;

View File

@ -23,7 +23,7 @@
#pragma warning(disable:4702)
#endif
#include "Crypto.h"
#include "PolarSSL++/RsaPrivateKey.h"
#ifdef _MSC_VER
#pragma warning(pop)
@ -109,7 +109,7 @@ public: // tolua_export
/** Returns base64 encoded favicon data (obtained from favicon.png) */
const AString & GetFaviconData(void) const { return m_FaviconData; }
cRSAPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
cRsaPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
const AString & GetPublicKeyDER(void) const { return m_PublicKeyDER; }
bool ShouldAuthenticate(void) const { return m_ShouldAuthenticate; }
@ -182,7 +182,7 @@ private:
bool m_bRestarting;
/** The private key used for the assymetric encryption start in the protocols */
cRSAPrivateKey m_PrivateKey;
cRsaPrivateKey m_PrivateKey;
/** Public key for m_PrivateKey, ASN1-DER-encoded */
AString m_PublicKeyDER;