From 641cb063bc71acc7f29d25b12c8713a8beb2018c Mon Sep 17 00:00:00 2001 From: Mattes D Date: Mon, 22 Aug 2016 19:53:34 +0200 Subject: cTCPLink supports TLS out of the box. --- src/Bindings/LuaTCPLink.cpp | 270 ++++---------------------------------------- src/Bindings/LuaTCPLink.h | 54 --------- 2 files changed, 25 insertions(+), 299 deletions(-) (limited to 'src/Bindings') diff --git a/src/Bindings/LuaTCPLink.cpp b/src/Bindings/LuaTCPLink.cpp index 466240a7d..905dfc5ac 100644 --- a/src/Bindings/LuaTCPLink.cpp +++ b/src/Bindings/LuaTCPLink.cpp @@ -6,6 +6,8 @@ #include "Globals.h" #include "LuaTCPLink.h" #include "LuaServerHandle.h" +#include "../PolarSSL++/X509Cert.h" +#include "../PolarSSL++/CryptoKey.h" @@ -48,13 +50,6 @@ cLuaTCPLink::~cLuaTCPLink() bool cLuaTCPLink::Send(const AString & a_Data) { - // If running in SSL mode, push the data into the SSL context instead: - if (m_SslContext != nullptr) - { - m_SslContext->Send(a_Data); - return true; - } - // Safely grab a copy of the link: auto link = m_Link; if (link == nullptr) @@ -144,12 +139,6 @@ void cLuaTCPLink::Shutdown(void) cTCPLinkPtr link = m_Link; if (link != nullptr) { - if (m_SslContext != nullptr) - { - m_SslContext->NotifyClose(); - m_SslContext->ResetSelf(); - m_SslContext.reset(); - } link->Shutdown(); } } @@ -164,12 +153,6 @@ void cLuaTCPLink::Close(void) cTCPLinkPtr link = m_Link; if (link != nullptr) { - if (m_SslContext != nullptr) - { - m_SslContext->NotifyClose(); - m_SslContext->ResetSelf(); - m_SslContext.reset(); - } link->Close(); } @@ -186,46 +169,31 @@ AString cLuaTCPLink::StartTLSClient( const AString & a_OwnPrivKeyPassword ) { - // Check preconditions: - if (m_SslContext != nullptr) - { - return "TLS is already active on this link"; - } - if ( - (a_OwnCertData.empty() && !a_OwnPrivKeyData.empty()) || - (!a_OwnCertData.empty() && a_OwnPrivKeyData.empty()) - ) - { - return "Either provide both the certificate and private key, or neither"; - } - - // Create the SSL context: - m_SslContext.reset(new cLinkSslContext(*this)); - m_SslContext->Initialize(true); - - // Create the peer cert, if required: - if (!a_OwnCertData.empty() && !a_OwnPrivKeyData.empty()) + auto link = m_Link; + if (link != nullptr) { - auto OwnCert = std::make_shared(); - int res = OwnCert->Parse(a_OwnCertData.data(), a_OwnCertData.size()); - if (res != 0) + cX509CertPtr ownCert; + if (!a_OwnCertData.empty()) { - m_SslContext.reset(); - return Printf("Cannot parse peer certificate: -0x%x", res); + ownCert = std::make_shared(); + auto res = ownCert->Parse(a_OwnCertData.data(), a_OwnCertData.size()); + if (res != 0) + { + return Printf("Cannot parse client certificate: -0x%x", res); + } } - auto OwnPrivKey = std::make_shared(); - res = OwnPrivKey->ParsePrivate(a_OwnPrivKeyData.data(), a_OwnPrivKeyData.size(), a_OwnPrivKeyPassword); - if (res != 0) + cCryptoKeyPtr ownPrivKey; + if (!a_OwnPrivKeyData.empty()) { - m_SslContext.reset(); - return Printf("Cannot parse peer private key: -0x%x", res); + ownPrivKey = std::make_shared(); + auto res = ownPrivKey->ParsePrivate(a_OwnPrivKeyData.data(), a_OwnPrivKeyData.size(), a_OwnPrivKeyPassword); + if (res != 0) + { + return Printf("Cannot parse client private key: -0x%x", res); + } } - m_SslContext->SetOwnCert(OwnCert, OwnPrivKey); + return link->StartTLSClient(ownCert, ownPrivKey); } - m_SslContext->SetSelf(cLinkSslContextWPtr(m_SslContext)); - - // Start the handshake: - m_SslContext->Handshake(); return ""; } @@ -240,43 +208,25 @@ AString cLuaTCPLink::StartTLSServer( const AString & a_StartTLSData ) { - // Check preconditions: - if (m_SslContext != nullptr) - { - return "TLS is already active on this link"; - } - if (a_OwnCertData.empty() || a_OwnPrivKeyData.empty()) + auto link = m_Link; + if (link != nullptr) { - return "Provide the server certificate and private key"; - } - - // Create the SSL context: - m_SslContext.reset(new cLinkSslContext(*this)); - m_SslContext->Initialize(false); - // Create the peer cert: auto OwnCert = std::make_shared(); int res = OwnCert->Parse(a_OwnCertData.data(), a_OwnCertData.size()); if (res != 0) { - m_SslContext.reset(); return Printf("Cannot parse server certificate: -0x%x", res); } auto OwnPrivKey = std::make_shared(); res = OwnPrivKey->ParsePrivate(a_OwnPrivKeyData.data(), a_OwnPrivKeyData.size(), a_OwnPrivKeyPassword); if (res != 0) { - m_SslContext.reset(); return Printf("Cannot parse server private key: -0x%x", res); } - m_SslContext->SetOwnCert(OwnCert, OwnPrivKey); - m_SslContext->SetSelf(cLinkSslContextWPtr(m_SslContext)); - // Push the initial data: - m_SslContext->StoreReceivedData(a_StartTLSData.data(), a_StartTLSData.size()); - - // Start the handshake: - m_SslContext->Handshake(); + return link->StartTLSServer(OwnCert, OwnPrivKey, a_StartTLSData); + } return ""; } @@ -308,9 +258,6 @@ void cLuaTCPLink::Terminated(void) m_Link.reset(); } } - - // If the SSL context still exists, free it: - m_SslContext.reset(); } @@ -362,14 +309,6 @@ void cLuaTCPLink::OnLinkCreated(cTCPLinkPtr a_Link) void cLuaTCPLink::OnReceivedData(const char * a_Data, size_t a_Length) { - // If we're running in SSL mode, put the data into the SSL decryptor: - auto sslContext = m_SslContext; - if (sslContext != nullptr) - { - sslContext->StoreReceivedData(a_Data, a_Length); - return; - } - // Call the callback: m_Callbacks->CallTableFn("OnReceivedData", this, AString(a_Data, a_Length)); } @@ -380,13 +319,6 @@ void cLuaTCPLink::OnReceivedData(const char * a_Data, size_t a_Length) void cLuaTCPLink::OnRemoteClosed(void) { - // If running in SSL mode and there's data left in the SSL contect, report it: - auto sslContext = m_SslContext; - if (sslContext != nullptr) - { - sslContext->FlushBuffers(); - } - // Call the callback: m_Callbacks->CallTableFn("OnRemoteClosed", this); @@ -398,155 +330,3 @@ void cLuaTCPLink::OnRemoteClosed(void) -//////////////////////////////////////////////////////////////////////////////// -// cLuaTCPLink::cLinkSslContext: - -cLuaTCPLink::cLinkSslContext::cLinkSslContext(cLuaTCPLink & a_Link): - m_Link(a_Link) -{ -} - - - - - -void cLuaTCPLink::cLinkSslContext::SetSelf(cLinkSslContextWPtr a_Self) -{ - m_Self = a_Self; -} - - - - - -void cLuaTCPLink::cLinkSslContext::ResetSelf(void) -{ - m_Self.reset(); -} - - - - - -void cLuaTCPLink::cLinkSslContext::StoreReceivedData(const char * a_Data, size_t a_NumBytes) -{ - // Hold self alive for the duration of this function - cLinkSslContextPtr Self(m_Self); - - m_EncryptedData.append(a_Data, a_NumBytes); - - // Try to finish a pending handshake: - TryFinishHandshaking(); - - // Flush any cleartext data that can be "received": - FlushBuffers(); -} - - - - - -void cLuaTCPLink::cLinkSslContext::FlushBuffers(void) -{ - // Hold self alive for the duration of this function - cLinkSslContextPtr Self(m_Self); - - // If the handshake didn't complete yet, bail out: - if (!HasHandshaken()) - { - return; - } - - char Buffer[1024]; - int NumBytes; - while ((NumBytes = ReadPlain(Buffer, sizeof(Buffer))) > 0) - { - m_Link.ReceivedCleartextData(Buffer, static_cast(NumBytes)); - if (m_Self.expired()) - { - // The callback closed the SSL context, bail out - return; - } - } -} - - - - - -void cLuaTCPLink::cLinkSslContext::TryFinishHandshaking(void) -{ - // Hold self alive for the duration of this function - cLinkSslContextPtr Self(m_Self); - - // If the handshake hasn't finished yet, retry: - if (!HasHandshaken()) - { - Handshake(); - } - - // If the handshake succeeded, write all the queued plaintext data: - if (HasHandshaken()) - { - WritePlain(m_CleartextData.data(), m_CleartextData.size()); - m_CleartextData.clear(); - } -} - - - - - -void cLuaTCPLink::cLinkSslContext::Send(const AString & a_Data) -{ - // Hold self alive for the duration of this function - cLinkSslContextPtr Self(m_Self); - - // If the handshake hasn't completed yet, queue the data: - if (!HasHandshaken()) - { - m_CleartextData.append(a_Data); - TryFinishHandshaking(); - return; - } - - // The connection is all set up, write the cleartext data into the SSL context: - WritePlain(a_Data.data(), a_Data.size()); - FlushBuffers(); -} - - - - - -int cLuaTCPLink::cLinkSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) -{ - // Hold self alive for the duration of this function - cLinkSslContextPtr Self(m_Self); - - // If there's nothing queued in the buffer, report empty buffer: - if (m_EncryptedData.empty()) - { - return POLARSSL_ERR_NET_WANT_READ; - } - - // Copy as much data as possible to the provided buffer: - size_t BytesToCopy = std::min(a_NumBytes, m_EncryptedData.size()); - memcpy(a_Buffer, m_EncryptedData.data(), BytesToCopy); - m_EncryptedData.erase(0, BytesToCopy); - return static_cast(BytesToCopy); -} - - - - - -int cLuaTCPLink::cLinkSslContext::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) -{ - m_Link.m_Link->Send(a_Buffer, a_NumBytes); - return static_cast(a_NumBytes); -} - - - - diff --git a/src/Bindings/LuaTCPLink.h b/src/Bindings/LuaTCPLink.h index b8c886ef8..f4ca67018 100644 --- a/src/Bindings/LuaTCPLink.h +++ b/src/Bindings/LuaTCPLink.h @@ -10,7 +10,6 @@ #pragma once #include "../OSSupport/Network.h" -#include "../PolarSSL++/SslContext.h" #include "LuaState.h" @@ -90,54 +89,6 @@ public: ); protected: - // fwd: - class cLinkSslContext; - typedef SharedPtr cLinkSslContextPtr; - typedef WeakPtr cLinkSslContextWPtr; - - /** Wrapper around cSslContext that is used when this link is being encrypted by SSL. */ - class cLinkSslContext : - public cSslContext - { - cLuaTCPLink & m_Link; - - /** Buffer for storing the incoming encrypted data until it is requested by the SSL decryptor. */ - AString m_EncryptedData; - - /** Buffer for storing the outgoing cleartext data until the link has finished handshaking. */ - AString m_CleartextData; - - /** Shared ownership of self, so that this object can keep itself alive for as long as it needs. */ - cLinkSslContextWPtr m_Self; - - public: - cLinkSslContext(cLuaTCPLink & a_Link); - - /** Shares ownership of self, so that this object can keep itself alive for as long as it needs. */ - void SetSelf(cLinkSslContextWPtr a_Self); - - /** Removes the self ownership so that we can detect the SSL closure. */ - void ResetSelf(void); - - /** Stores the specified block of data into the buffer of the data to be decrypted (incoming from remote). - Also flushes the SSL buffers by attempting to read any data through the SSL context. */ - void StoreReceivedData(const char * a_Data, size_t a_NumBytes); - - /** Tries to read any cleartext data available through the SSL, reports it in the link. */ - void FlushBuffers(void); - - /** Tries to finish handshaking the SSL. */ - void TryFinishHandshaking(void); - - /** Sends the specified cleartext data over the SSL to the remote peer. - If the handshake hasn't been completed yet, queues the data for sending when it completes. */ - void Send(const AString & a_Data); - - // 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; - }; - /** The Lua table that holds the callbacks to be invoked. */ cLuaState::cTableRefPtr m_Callbacks; @@ -149,11 +100,6 @@ protected: /** The server that is responsible for this link, if any. */ cLuaServerHandleWPtr m_Server; - /** The SSL context used for encryption, if this link uses SSL. - If valid, the link uses encryption through this context. */ - cLinkSslContextPtr m_SslContext; - - /** Common code called when the link is considered as terminated. Releases m_Link, m_Callbacks and this from m_Server, each when applicable. */ void Terminated(void); -- cgit v1.2.3