summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ByteBuffer.cpp9
-rw-r--r--src/ByteBuffer.h2
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/Globals.h18
-rw-r--r--src/OSSupport/Socket.cpp10
-rw-r--r--src/PolarSSL++/BlockingSslClientSocket.cpp195
-rw-r--r--src/PolarSSL++/BlockingSslClientSocket.h80
-rw-r--r--src/PolarSSL++/BufferedSslContext.cpp62
-rw-r--r--src/PolarSSL++/BufferedSslContext.h52
-rw-r--r--src/PolarSSL++/CMakeLists.txt31
-rw-r--r--src/PolarSSL++/CallbackSslContext.cpp59
-rw-r--r--src/PolarSSL++/CallbackSslContext.h61
-rw-r--r--src/PolarSSL++/CtrDrbgContext.cpp49
-rw-r--r--src/PolarSSL++/CtrDrbgContext.h60
-rw-r--r--src/PolarSSL++/EntropyContext.cpp29
-rw-r--r--src/PolarSSL++/EntropyContext.h31
-rw-r--r--src/PolarSSL++/SslContext.cpp243
-rw-r--r--src/PolarSSL++/SslContext.h137
-rw-r--r--src/PolarSSL++/X509Cert.cpp38
-rw-r--r--src/PolarSSL++/X509Cert.h41
-rw-r--r--src/Protocol/Authenticator.cpp181
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");