diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ByteBuffer.cpp | 9 | ||||
-rw-r--r-- | src/ByteBuffer.h | 2 | ||||
-rw-r--r-- | src/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/Globals.h | 18 | ||||
-rw-r--r-- | src/OSSupport/Socket.cpp | 10 | ||||
-rw-r--r-- | src/PolarSSL++/BlockingSslClientSocket.cpp | 195 | ||||
-rw-r--r-- | src/PolarSSL++/BlockingSslClientSocket.h | 80 | ||||
-rw-r--r-- | src/PolarSSL++/BufferedSslContext.cpp | 62 | ||||
-rw-r--r-- | src/PolarSSL++/BufferedSslContext.h | 52 | ||||
-rw-r--r-- | src/PolarSSL++/CMakeLists.txt | 31 | ||||
-rw-r--r-- | src/PolarSSL++/CallbackSslContext.cpp | 59 | ||||
-rw-r--r-- | src/PolarSSL++/CallbackSslContext.h | 61 | ||||
-rw-r--r-- | src/PolarSSL++/CtrDrbgContext.cpp | 49 | ||||
-rw-r--r-- | src/PolarSSL++/CtrDrbgContext.h | 60 | ||||
-rw-r--r-- | src/PolarSSL++/EntropyContext.cpp | 29 | ||||
-rw-r--r-- | src/PolarSSL++/EntropyContext.h | 31 | ||||
-rw-r--r-- | src/PolarSSL++/SslContext.cpp | 243 | ||||
-rw-r--r-- | src/PolarSSL++/SslContext.h | 137 | ||||
-rw-r--r-- | src/PolarSSL++/X509Cert.cpp | 38 | ||||
-rw-r--r-- | src/PolarSSL++/X509Cert.h | 41 | ||||
-rw-r--r-- | src/Protocol/Authenticator.cpp | 181 |
21 files changed, 1275 insertions, 117 deletions
diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp index 24f91b195..c27bc4cad 100644 --- a/src/ByteBuffer.cpp +++ b/src/ByteBuffer.cpp @@ -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; } diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h index 44f43e17f..7656a5b13 100644 --- a/src/ByteBuffer.h +++ b/src/ByteBuffer.h @@ -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; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9fbaed926..900577526 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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) diff --git a/src/Globals.h b/src/Globals.h index 26a0d87a9..a09819ce9 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -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 diff --git a/src/OSSupport/Socket.cpp b/src/OSSupport/Socket.cpp index c29e495c3..98f694a79 100644 --- a/src/OSSupport/Socket.cpp +++ b/src/OSSupport/Socket.cpp @@ -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; diff --git a/src/PolarSSL++/BlockingSslClientSocket.cpp b/src/PolarSSL++/BlockingSslClientSocket.cpp new file mode 100644 index 000000000..699bc57ee --- /dev/null +++ b/src/PolarSSL++/BlockingSslClientSocket.cpp @@ -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; +} + + + + diff --git a/src/PolarSSL++/BlockingSslClientSocket.h b/src/PolarSSL++/BlockingSslClientSocket.h new file mode 100644 index 000000000..7af897582 --- /dev/null +++ b/src/PolarSSL++/BlockingSslClientSocket.h @@ -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; +} ; + + + + diff --git a/src/PolarSSL++/BufferedSslContext.cpp b/src/PolarSSL++/BufferedSslContext.cpp new file mode 100644 index 000000000..885b30c68 --- /dev/null +++ b/src/PolarSSL++/BufferedSslContext.cpp @@ -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; +} + + + + diff --git a/src/PolarSSL++/BufferedSslContext.h b/src/PolarSSL++/BufferedSslContext.h new file mode 100644 index 000000000..1b7e1af46 --- /dev/null +++ b/src/PolarSSL++/BufferedSslContext.h @@ -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; +} ; + + + + diff --git a/src/PolarSSL++/CMakeLists.txt b/src/PolarSSL++/CMakeLists.txt new file mode 100644 index 000000000..0493baba4 --- /dev/null +++ b/src/PolarSSL++/CMakeLists.txt @@ -0,0 +1,31 @@ + +cmake_minimum_required (VERSION 2.6) +project (MCServer) + +include_directories ("${PROJECT_SOURCE_DIR}/../") + +set(SOURCES + "BlockingSslClientSocket.cpp" + "BufferedSslContext.cpp" + "CallbackSslContext.cpp" + "CtrDrbgContext.cpp" + "EntropyContext.cpp" + "SslContext.cpp" + "X509Cert.cpp" +) + +set(HEADERS + "BlockingSslClientSocket.h" + "BufferedSslContext.h" + "CallbackSslContext.h" + "CtrDrbgContext.h" + "EntropyContext.h" + "SslContext.h" + "X509Cert.h" +) + +add_library(PolarSSL++ ${SOURCES} ${HEADERS}) + +if (UNIX) + target_link_libraries(PolarSSL++ polarssl) +endif() diff --git a/src/PolarSSL++/CallbackSslContext.cpp b/src/PolarSSL++/CallbackSslContext.cpp new file mode 100644 index 000000000..0cc88a14a --- /dev/null +++ b/src/PolarSSL++/CallbackSslContext.cpp @@ -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); +} + + + + + diff --git a/src/PolarSSL++/CallbackSslContext.h b/src/PolarSSL++/CallbackSslContext.h new file mode 100644 index 000000000..4e4c1ed7f --- /dev/null +++ b/src/PolarSSL++/CallbackSslContext.h @@ -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; +}; + + + + diff --git a/src/PolarSSL++/CtrDrbgContext.cpp b/src/PolarSSL++/CtrDrbgContext.cpp new file mode 100644 index 000000000..86e6d1ca5 --- /dev/null +++ b/src/PolarSSL++/CtrDrbgContext.cpp @@ -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; +} + + + + diff --git a/src/PolarSSL++/CtrDrbgContext.h b/src/PolarSSL++/CtrDrbgContext.h new file mode 100644 index 000000000..e9a1e17e2 --- /dev/null +++ b/src/PolarSSL++/CtrDrbgContext.h @@ -0,0 +1,60 @@ + +// 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; + +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; } + + /** Returns the internal context ptr. Only use in PolarSSL API calls. */ + OBSOLETE ctr_drbg_context * Get(void) { return &m_CtrDrbg; } + +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; +} ; + + + + diff --git a/src/PolarSSL++/EntropyContext.cpp b/src/PolarSSL++/EntropyContext.cpp new file mode 100644 index 000000000..9c59b3f11 --- /dev/null +++ b/src/PolarSSL++/EntropyContext.cpp @@ -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); +} + + + + diff --git a/src/PolarSSL++/EntropyContext.h b/src/PolarSSL++/EntropyContext.h new file mode 100644 index 000000000..bc7fff066 --- /dev/null +++ b/src/PolarSSL++/EntropyContext.h @@ -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; +} ; + + + + diff --git a/src/PolarSSL++/SslContext.cpp b/src/PolarSSL++/SslContext.cpp new file mode 100644 index 000000000..1994cf844 --- /dev/null +++ b/src/PolarSSL++/SslContext.cpp @@ -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 + + + + diff --git a/src/PolarSSL++/SslContext.h b/src/PolarSSL++/SslContext.h new file mode 100644 index 000000000..85add5f8b --- /dev/null +++ b/src/PolarSSL++/SslContext.h @@ -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; +} ; + + + + diff --git a/src/PolarSSL++/X509Cert.cpp b/src/PolarSSL++/X509Cert.cpp new file mode 100644 index 000000000..ecf664855 --- /dev/null +++ b/src/PolarSSL++/X509Cert.cpp @@ -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); +} + + + + diff --git a/src/PolarSSL++/X509Cert.h b/src/PolarSSL++/X509Cert.h new file mode 100644 index 000000000..991617d24 --- /dev/null +++ b/src/PolarSSL++/X509Cert.h @@ -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; + + + + diff --git a/src/Protocol/Authenticator.cpp b/src/Protocol/Authenticator.cpp index bbc656eda..f7008a5c4 100644 --- a/src/Protocol/Authenticator.cpp +++ b/src/Protocol/Authenticator.cpp @@ -13,10 +13,10 @@ #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 +148,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)); - - if (ret < 0) - { - 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); - return false; - } - - /* Connect */ - if ((ret = net_connect(&server_fd, m_Server.c_str(), 443)) != 0) + // 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" + ); + + // Connect the socket: + cBlockingSslClientSocket Socket; + Socket.SetTrustedRootCertsFromString(StarfieldCACert, m_Server); + if (!Socket.Connect(m_Server, 443)) { - 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); + LOGWARNING("cAuthenticator: Can't connect to %s: %s", m_Server.c_str(), Socket.GetLastErrorText().c_str()); 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 +227,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 +251,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"); |