From e6786074d58d81a230a6d5d01a5d89fa2f5ab16e Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 1 May 2014 00:27:42 +0200 Subject: Added cBufferedSslContext implementation. --- src/ByteBuffer.h | 40 +++++++++++++++++------------------ src/PolarSSL++/BufferedSslContext.cpp | 31 +++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h index 7656a5b13..c5ff05922 100644 --- a/src/ByteBuffer.h +++ b/src/ByteBuffer.h @@ -30,25 +30,25 @@ public: cByteBuffer(size_t a_BufferSize); ~cByteBuffer(); - /// Writes the bytes specified to the ringbuffer. Returns true if successful, false if not + /** Writes the bytes specified to the ringbuffer. Returns true if successful, false if not */ bool Write(const void * a_Bytes, size_t a_Count); - /// Returns the number of bytes that can be successfully written to the ringbuffer + /** Returns the number of bytes that can be successfully written to the ringbuffer */ size_t GetFreeSpace(void) const; - /// Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes() + /** Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes() */ size_t GetUsedSpace(void) const; - /// Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already) + /** Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already) */ size_t GetReadableSpace(void) const; - /// Returns the current data start index. For debugging purposes. + /** Returns the current data start index. For debugging purposes. */ size_t GetDataStart(void) const { return m_DataStart; } - /// Returns true if the specified amount of bytes are available for reading + /** Returns true if the specified amount of bytes are available for reading */ bool CanReadBytes(size_t a_Count) const; - /// Returns true if the specified amount of bytes are available for writing + /** Returns true if the specified amount of bytes are available for writing */ bool CanWriteBytes(size_t a_Count) const; // Read the specified datatype and advance the read pointer; return true if successfully read: @@ -65,7 +65,7 @@ public: bool ReadVarUTF8String (AString & a_Value); // string length as VarInt, then string as UTF-8 bool ReadLEInt (int & a_Value); - /// Reads VarInt, assigns it to anything that can be assigned from an UInt32 (unsigned short, char, Byte, double, ...) + /** Reads VarInt, assigns it to anything that can be assigned from an UInt32 (unsigned short, char, Byte, double, ...) */ template bool ReadVarInt(T & a_Value) { UInt32 v; @@ -91,37 +91,37 @@ public: bool WriteVarUTF8String (const AString & a_Value); // string length as VarInt, then string as UTF-8 bool WriteLEInt (int a_Value); - /// Reads a_Count bytes into a_Buffer; returns true if successful + /** Reads a_Count bytes into a_Buffer; returns true if successful */ bool ReadBuf(void * a_Buffer, size_t a_Count); - /// Writes a_Count bytes into a_Buffer; returns true if successful + /** Writes a_Count bytes into a_Buffer; returns true if successful */ bool WriteBuf(const void * a_Buffer, size_t a_Count); - /// Reads a_Count bytes into a_String; returns true if successful + /** Reads a_Count bytes into a_String; returns true if successful */ bool ReadString(AString & a_String, size_t a_Count); - /// Reads 2 * a_NumChars bytes and interprets it as a UTF16-BE string, converting it into UTF8 string a_String + /** Reads 2 * a_NumChars bytes and interprets it as a UTF16-BE string, converting it into UTF8 string a_String */ bool ReadUTF16String(AString & a_String, int a_NumChars); - /// Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer + /** Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer */ bool SkipRead(size_t a_Count); - /// Reads all available data into a_Data + /** Reads all available data into a_Data */ void ReadAll(AString & a_Data); - /// Reads the specified number of bytes and writes it into the destinatio bytebuffer. Returns true on success. + /** Reads the specified number of bytes and writes it into the destinatio bytebuffer. Returns true on success. */ bool ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes); - /// Removes the bytes that have been read from the ringbuffer + /** Removes the bytes that have been read from the ringbuffer */ void CommitRead(void); - /// Restarts next reading operation at the start of the ringbuffer + /** Restarts next reading operation at the start of the ringbuffer */ void ResetRead(void); - /// Re-reads the data that has been read since the last commit to the current readpos. Used by ProtoProxy to duplicate communication + /** Re-reads the data that has been read since the last commit to the current readpos. Used by ProtoProxy to duplicate communication */ void ReadAgain(AString & a_Out); - /// Checks if the internal state is valid (read and write positions in the correct bounds) using ASSERTs + /** Checks if the internal state is valid (read and write positions in the correct bounds) using ASSERTs */ void CheckValid(void) const; protected: @@ -136,7 +136,7 @@ protected: size_t m_WritePos; // Where the data ends in the ringbuffer size_t m_ReadPos; // Where the next read will start in the ringbuffer - /// Advances the m_ReadPos by a_Count bytes + /** Advances the m_ReadPos by a_Count bytes */ void AdvanceReadPos(size_t a_Count); } ; diff --git a/src/PolarSSL++/BufferedSslContext.cpp b/src/PolarSSL++/BufferedSslContext.cpp index 885b30c68..2455d5781 100644 --- a/src/PolarSSL++/BufferedSslContext.cpp +++ b/src/PolarSSL++/BufferedSslContext.cpp @@ -20,6 +20,37 @@ cBufferedSslContext::cBufferedSslContext(size_t a_BufferSize): +size_t cBufferedSslContext::WriteIncoming(const void * a_Data, size_t a_NumBytes) +{ + size_t NumBytes = std::min(m_IncomingData.GetFreeSpace(), a_NumBytes); + if (NumBytes > 0) + { + m_IncomingData.Write(a_Data, NumBytes); + return a_NumBytes - NumBytes; + } + return 0; +} + + + + + +size_t cBufferedSslContext::ReadOutgoing(void * a_Data, size_t a_DataMaxSize) +{ + size_t NumBytes = std::min(m_OutgoingData.GetReadableSpace(), a_DataMaxSize); + if (NumBytes > 0) + { + m_OutgoingData.ReadBuf(a_Data, NumBytes); + m_OutgoingData.CommitRead(); + return a_DataMaxSize - NumBytes; + } + return 0; +} + + + + + int cBufferedSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) { // Called when PolarSSL wants to read encrypted data from the SSL peer -- cgit v1.2.3 From 47feb91e57f83c81722188ec3025c3109758dd33 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 1 May 2014 00:28:27 +0200 Subject: cSslContext supports setting own cert / privkey. --- src/PolarSSL++/PublicKey.cpp | 82 ++++++++++++++++++++++++++++++++++++++++-- src/PolarSSL++/PublicKey.h | 32 +++++++++++++++-- src/PolarSSL++/RsaPrivateKey.h | 8 +++++ src/PolarSSL++/SslContext.cpp | 50 +++++++++++++++++++++++++- src/PolarSSL++/SslContext.h | 22 +++++++++++- 5 files changed, 187 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/PolarSSL++/PublicKey.cpp b/src/PolarSSL++/PublicKey.cpp index 49794a0c8..dae026082 100644 --- a/src/PolarSSL++/PublicKey.cpp +++ b/src/PolarSSL++/PublicKey.cpp @@ -10,15 +10,44 @@ -cPublicKey::cPublicKey(const AString & a_PublicKeyDER) +cPublicKey::cPublicKey(void) { pk_init(&m_Pk); - if (pk_parse_public_key(&m_Pk, (const Byte *)a_PublicKeyDER.data(), a_PublicKeyDER.size()) != 0) + m_CtrDrbg.Initialize("rsa_pubkey", 10); +} + + + + + +cPublicKey::cPublicKey(const AString & a_PublicKeyData) +{ + pk_init(&m_Pk); + m_CtrDrbg.Initialize("rsa_pubkey", 10); + int res = ParsePublic(a_PublicKeyData.data(), a_PublicKeyData.size()); + if (res != 0) { + LOGWARNING("Failed to parse public key: -0x%x", res); + ASSERT(!"Cannot parse PubKey"); + return; + } +} + + + + + +cPublicKey::cPublicKey(const AString & a_PrivateKeyData, const AString & a_Password) +{ + pk_init(&m_Pk); + m_CtrDrbg.Initialize("rsa_privkey", 11); + int res = ParsePrivate(a_PrivateKeyData.data(), a_PrivateKeyData.size(), a_Password); + if (res != 0) + { + LOGWARNING("Failed to parse private key: -0x%x", res); ASSERT(!"Cannot parse PubKey"); return; } - m_CtrDrbg.Initialize("rsa_pubkey", 10); } @@ -36,6 +65,8 @@ cPublicKey::~cPublicKey() int cPublicKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength) { + ASSERT(IsValid()); + size_t DecryptedLen = a_DecryptedMaxLength; int res = pk_decrypt(&m_Pk, a_EncryptedData, a_EncryptedLength, @@ -55,6 +86,8 @@ int cPublicKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, int cPublicKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength) { + ASSERT(IsValid()); + size_t EncryptedLength = a_EncryptedMaxLength; int res = pk_encrypt(&m_Pk, a_PlainData, a_PlainLength, a_EncryptedData, &EncryptedLength, a_EncryptedMaxLength, @@ -71,3 +104,46 @@ int cPublicKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a + +int cPublicKey::ParsePublic(const void * a_Data, size_t a_NumBytes) +{ + ASSERT(!IsValid()); // Cannot parse a second key + + return pk_parse_public_key(&m_Pk, (const unsigned char *)a_Data, a_NumBytes); +} + + + + + + +int cPublicKey::ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password) +{ + ASSERT(!IsValid()); // Cannot parse a second key + + if (a_Password.empty()) + { + return pk_parse_key(&m_Pk, (const unsigned char *)a_Data, a_NumBytes, NULL, 0); + } + else + { + return pk_parse_key( + &m_Pk, + (const unsigned char *)a_Data, a_NumBytes, + (const unsigned char *)a_Password.c_str(), a_Password.size() + ); + } +} + + + + + +bool cPublicKey::IsValid(void) const +{ + return (pk_get_type(&m_Pk) != POLARSSL_PK_NONE); +} + + + + diff --git a/src/PolarSSL++/PublicKey.h b/src/PolarSSL++/PublicKey.h index 5a0a57147..df52a4143 100644 --- a/src/PolarSSL++/PublicKey.h +++ b/src/PolarSSL++/PublicKey.h @@ -18,9 +18,18 @@ class cPublicKey { + friend class cSslContext; + public: - /** Constructs the public key out of the DER-encoded pubkey data */ - cPublicKey(const AString & a_PublicKeyDER); + /** Constructs an empty key instance. Before use, it needs to be filled by ParsePublic() or ParsePrivate() */ + cPublicKey(void); + + /** Constructs the public key out of the DER- or PEM-encoded pubkey data */ + cPublicKey(const AString & a_PublicKeyData); + + /** Constructs the private key out of the DER- or PEM-encoded privkey data, with the specified password. + If a_Password is empty, no password is assumed. */ + cPublicKey(const AString & a_PrivateKeyData, const AString & a_Password); ~cPublicKey(); @@ -33,6 +42,20 @@ public: Both a_EncryptedData and a_DecryptedData must be at least bytes large. Returns the number of bytes decrypted, or negative number for error. */ int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength); + + /** Parses the specified data into a public key representation. + The key can be DER- or PEM-encoded. + Returns 0 on success, PolarSSL error code on failure. */ + int ParsePublic(const void * a_Data, size_t a_NumBytes); + + /** Parses the specified data into a private key representation. + If a_Password is empty, no password is assumed. + The key can be DER- or PEM-encoded. + Returns 0 on success, PolarSSL error code on failure. */ + int ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password); + + /** Returns true if the contained key is valid. */ + bool IsValid(void) const; protected: /** The public key PolarSSL representation */ @@ -40,8 +63,13 @@ protected: /** The random generator used in encryption and decryption */ cCtrDrbgContext m_CtrDrbg; + + + /** Returns the internal context ptr. Only use in PolarSSL API calls. */ + pk_context * GetInternal(void) { return &m_Pk; } } ; +typedef SharedPtr cPublicKeyPtr; diff --git a/src/PolarSSL++/RsaPrivateKey.h b/src/PolarSSL++/RsaPrivateKey.h index ffacde11b..4d03f27df 100644 --- a/src/PolarSSL++/RsaPrivateKey.h +++ b/src/PolarSSL++/RsaPrivateKey.h @@ -19,6 +19,8 @@ /** Encapsulates an RSA private key used in PKI cryptography */ class cRsaPrivateKey { + friend class cSslContext; + public: /** Creates a new empty object, the key is not assigned */ cRsaPrivateKey(void); @@ -51,8 +53,14 @@ protected: /** The random generator used for generating the key and encryption / decryption */ cCtrDrbgContext m_CtrDrbg; + + + /** Returns the internal context ptr. Only use in PolarSSL API calls. */ + rsa_context * GetInternal(void) { return &m_Rsa; } } ; +typedef SharedPtr cRsaPrivateKeyPtr; + diff --git a/src/PolarSSL++/SslContext.cpp b/src/PolarSSL++/SslContext.cpp index 1994cf844..3d2b8cef7 100644 --- a/src/PolarSSL++/SslContext.cpp +++ b/src/PolarSSL++/SslContext.cpp @@ -40,7 +40,7 @@ int cSslContext::Initialize(bool a_IsClient, const SharedPtr & 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. + return POLARSSL_ERR_SSL_BAD_INPUT_DATA; // There is no return value well-suited for this, reuse this one. } // Set the CtrDrbg context, create a new one if needed: @@ -80,8 +80,56 @@ int cSslContext::Initialize(bool a_IsClient, const SharedPtr & +void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cRsaPrivateKeyPtr & a_OwnCertPrivKey) +{ + ASSERT(m_IsValid); // Call Initialize() first + + // Check that both the cert and the key is valid: + if ((a_OwnCert.get() == NULL) || (a_OwnCertPrivKey.get() == NULL)) + { + LOGWARNING("SSL: Own certificate is not valid, skipping the set."); + return; + } + + // Make sure we have the cert stored for later, PolarSSL only uses the cert later on + m_OwnCert = a_OwnCert; + m_OwnCertPrivKey = a_OwnCertPrivKey; + + // Set into the context: + ssl_set_own_cert_rsa(&m_Ssl, m_OwnCert->GetInternal(), m_OwnCertPrivKey->GetInternal()); +} + + + + + +void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cPublicKeyPtr & a_OwnCertPrivKey) +{ + ASSERT(m_IsValid); // Call Initialize() first + + // Check that both the cert and the key is valid: + if ((a_OwnCert.get() == NULL) || (a_OwnCertPrivKey.get() == NULL)) + { + LOGWARNING("SSL: Own certificate is not valid, skipping the set."); + return; + } + + // Make sure we have the cert stored for later, PolarSSL only uses the cert later on + m_OwnCert = a_OwnCert; + m_OwnCertPrivKey2 = a_OwnCertPrivKey; + + // Set into the context: + ssl_set_own_cert(&m_Ssl, m_OwnCert->GetInternal(), m_OwnCertPrivKey2->GetInternal()); +} + + + + + void cSslContext::SetCACerts(const cX509CertPtr & a_CACert, const AString & a_ExpectedPeerName) { + ASSERT(m_IsValid); // Call Initialize() first + // 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; diff --git a/src/PolarSSL++/SslContext.h b/src/PolarSSL++/SslContext.h index 85add5f8b..273939b9f 100644 --- a/src/PolarSSL++/SslContext.h +++ b/src/PolarSSL++/SslContext.h @@ -11,6 +11,8 @@ #include "polarssl/ssl.h" #include "../ByteBuffer.h" +#include "PublicKey.h" +#include "RsaPrivateKey.h" #include "X509Cert.h" @@ -47,7 +49,16 @@ public: /** 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. + /** Sets the certificate to use as our own. Must be used when representing a server, optional when client. + Must be called after Initialize(). */ + void SetOwnCert(const cX509CertPtr & a_OwnCert, const cRsaPrivateKeyPtr & a_OwnCertPrivKey); + + /** Sets the certificate to use as our own. Must be used when representing a server, optional when client. + Must be called after Initialize(). + Despite the class name, a_OwnCertPrivKey is a PRIVATE key. */ + void SetOwnCert(const cX509CertPtr & a_OwnCert, const cPublicKeyPtr & a_OwnCertPrivKey); + + /** Sets a cert chain as the trusted cert store for this context. Must be called after Initialize(). Calling this will switch the context into strict cert verification mode. 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. */ @@ -93,6 +104,15 @@ protected: /** The SSL context that PolarSSL uses. */ ssl_context m_Ssl; + /** The certificate that we present to the peer. */ + cX509CertPtr m_OwnCert; + + /** Private key for m_OwnCert, if initialized from a cRsaPrivateKey */ + cRsaPrivateKeyPtr m_OwnCertPrivKey; + + /** Private key for m_OwnCert, if initialized from a cPublicKey. Despite the class name, this is a PRIVATE key. */ + cPublicKeyPtr m_OwnCertPrivKey2; + /** True if the SSL handshake has been completed. */ bool m_HasHandshaken; -- cgit v1.2.3 From e2bf3783e8c8f7855532e04203bb1b46b976cfee Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 1 May 2014 11:32:25 +0200 Subject: Fixed BufferedSslContext's buffer reading and writing. --- src/PolarSSL++/BufferedSslContext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/PolarSSL++/BufferedSslContext.cpp b/src/PolarSSL++/BufferedSslContext.cpp index 2455d5781..9f7caeb8a 100644 --- a/src/PolarSSL++/BufferedSslContext.cpp +++ b/src/PolarSSL++/BufferedSslContext.cpp @@ -26,7 +26,7 @@ size_t cBufferedSslContext::WriteIncoming(const void * a_Data, size_t a_NumBytes if (NumBytes > 0) { m_IncomingData.Write(a_Data, NumBytes); - return a_NumBytes - NumBytes; + return NumBytes; } return 0; } @@ -42,7 +42,7 @@ size_t cBufferedSslContext::ReadOutgoing(void * a_Data, size_t a_DataMaxSize) { m_OutgoingData.ReadBuf(a_Data, NumBytes); m_OutgoingData.CommitRead(); - return a_DataMaxSize - NumBytes; + return NumBytes; } return 0; } -- cgit v1.2.3 From e1b6a169457b267c3e11bbdb9e58e9ab7b3f0136 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 1 May 2014 11:33:29 +0200 Subject: Added a (disabled) test of low-security ciphersuites. Enabling this allows the connection to be sniffed and decoded using Wireshark, when given the SSL private key. --- src/PolarSSL++/SslContext.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src') diff --git a/src/PolarSSL++/SslContext.cpp b/src/PolarSSL++/SslContext.cpp index 3d2b8cef7..df0219610 100644 --- a/src/PolarSSL++/SslContext.cpp +++ b/src/PolarSSL++/SslContext.cpp @@ -70,6 +70,18 @@ int cSslContext::Initialize(bool a_IsClient, const SharedPtr & ssl_set_dbg(&m_Ssl, &SSLDebugMessage, this); ssl_set_verify(&m_Ssl, &SSLVerifyCert, this); */ + + /* + // Set ciphersuite to the easiest one to decode, so that the connection can be wireshark-decoded: + static const int CipherSuites[] = + { + TLS_RSA_WITH_RC4_128_MD5, + TLS_RSA_WITH_RC4_128_SHA, + TLS_RSA_WITH_AES_128_CBC_SHA, + 0, // Must be 0-terminated! + }; + ssl_set_ciphersuites(&m_Ssl, CipherSuites); + */ #endif m_IsValid = true; -- cgit v1.2.3 From a04cb6d146dfb8f04b0a8943c1e185fc25bf2829 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 1 May 2014 11:34:15 +0200 Subject: Fixed HTTP message parsing, prepared for SSL. --- src/HTTPServer/HTTPConnection.cpp | 5 +++-- src/HTTPServer/HTTPMessage.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/HTTPServer/HTTPConnection.cpp b/src/HTTPServer/HTTPConnection.cpp index da4df0e34..8e95eff2d 100644 --- a/src/HTTPServer/HTTPConnection.cpp +++ b/src/HTTPServer/HTTPConnection.cpp @@ -26,6 +26,7 @@ cHTTPConnection::cHTTPConnection(cHTTPServer & a_HTTPServer) : cHTTPConnection::~cHTTPConnection() { + // LOGD("HTTP: Connection deleting: %p", this); delete m_CurrentRequest; } @@ -183,11 +184,11 @@ void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) // Process the rest of the incoming data into the request body: if (a_Size > BytesConsumed) { - DataReceived(a_Data + BytesConsumed, a_Size - BytesConsumed); + cHTTPConnection::DataReceived(a_Data + BytesConsumed, a_Size - BytesConsumed); } else { - DataReceived("", 0); // If the request has zero body length, let it be processed right-away + cHTTPConnection::DataReceived("", 0); // If the request has zero body length, let it be processed right-away } break; } diff --git a/src/HTTPServer/HTTPMessage.cpp b/src/HTTPServer/HTTPMessage.cpp index 4a3611050..44feda469 100644 --- a/src/HTTPServer/HTTPMessage.cpp +++ b/src/HTTPServer/HTTPMessage.cpp @@ -201,7 +201,7 @@ size_t cHTTPRequest::ParseRequestLine(const char * a_Data, size_t a_Size) return AString::npos; } // Check that there's HTTP/version at the end - if (strncmp(a_Data + URLEnd + 1, "HTTP/1.", 7) != 0) + if (strncmp(m_IncomingHeaderData.c_str() + URLEnd + 1, "HTTP/1.", 7) != 0) { m_IsValid = false; return AString::npos; -- cgit v1.2.3 From 272c232efb645c9f7d75556aeb047e13b244c9ed Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 1 May 2014 11:48:03 +0200 Subject: Implemented SSL connection for WebAdmin. Fixes FS-319. --- src/HTTPServer/HTTPServer.cpp | 35 +++++++++++- src/HTTPServer/HTTPServer.h | 10 ++++ src/HTTPServer/SslHTTPConnection.cpp | 103 +++++++++++++++++++++++++++++++++++ src/HTTPServer/SslHTTPConnection.h | 45 +++++++++++++++ 4 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 src/HTTPServer/SslHTTPConnection.cpp create mode 100644 src/HTTPServer/SslHTTPConnection.h (limited to 'src') diff --git a/src/HTTPServer/HTTPServer.cpp b/src/HTTPServer/HTTPServer.cpp index eaf8405a3..9e3e0a17b 100644 --- a/src/HTTPServer/HTTPServer.cpp +++ b/src/HTTPServer/HTTPServer.cpp @@ -8,6 +8,7 @@ #include "HTTPMessage.h" #include "HTTPConnection.h" #include "HTTPFormParser.h" +#include "SslHTTPConnection.h" @@ -123,8 +124,30 @@ class cDebugCallbacks : cHTTPServer::cHTTPServer(void) : m_ListenThreadIPv4(*this, cSocket::IPv4, "WebServer IPv4"), m_ListenThreadIPv6(*this, cSocket::IPv6, "WebServer IPv6"), - m_Callbacks(NULL) + m_Callbacks(NULL), + m_Cert(new cX509Cert), + m_CertPrivKey(new cPublicKey) { + AString CertFile = cFile::ReadWholeFile("webadmin/httpscert.crt"); + AString KeyFile = cFile::ReadWholeFile("webadmin/httpskey.pem"); + if (!CertFile.empty() && !KeyFile.empty()) + { + int res = m_Cert->Parse(CertFile.data(), CertFile.size()); + if (res == 0) + { + int res2 = m_CertPrivKey->ParsePrivate(KeyFile.data(), KeyFile.size(), ""); + if (res2 != 0) + { + // Reading the private key failed, reset the cert: + LOGWARNING("WebAdmin: Cannot read HTTPS certificate private key: -0x%x", -res2); + m_Cert.reset(); + } + } + else + { + LOGWARNING("WebAdmin: Cannot read HTTPS certificate: -0x%x", -res); + } + } } @@ -195,7 +218,15 @@ void cHTTPServer::Stop(void) void cHTTPServer::OnConnectionAccepted(cSocket & a_Socket) { - cHTTPConnection * Connection = new cHTTPConnection(*this); + cHTTPConnection * Connection; + if (m_Cert.get() != NULL) + { + Connection = new cSslHTTPConnection(*this, m_Cert, m_CertPrivKey); + } + else + { + Connection = new cHTTPConnection(*this); + } m_SocketThreads.AddClient(a_Socket, Connection); cCSLock Lock(m_CSConnections); m_Connections.push_back(Connection); diff --git a/src/HTTPServer/HTTPServer.h b/src/HTTPServer/HTTPServer.h index 8eff7d879..eb91dd5a3 100644 --- a/src/HTTPServer/HTTPServer.h +++ b/src/HTTPServer/HTTPServer.h @@ -12,6 +12,9 @@ #include "../OSSupport/ListenThread.h" #include "../OSSupport/SocketThreads.h" #include "inifile/iniFile.h" +#include "PolarSSL++/RsaPrivateKey.h" +#include "PolarSSL++/PublicKey.h" +#include "PolarSSL++/X509Cert.h" @@ -66,6 +69,7 @@ public: protected: friend class cHTTPConnection; + friend class cSslHTTPConnection; cListenThread m_ListenThreadIPv4; cListenThread m_ListenThreadIPv6; @@ -78,6 +82,12 @@ protected: /// The callbacks to call for various events cCallbacks * m_Callbacks; + /** The server certificate to use for the SSL connections */ + cX509CertPtr m_Cert; + + /** The private key for m_Cert. Despite the class name, this is the PRIVATE key. */ + cPublicKeyPtr m_CertPrivKey; + // cListenThread::cCallback overrides: virtual void OnConnectionAccepted(cSocket & a_Socket) override; diff --git a/src/HTTPServer/SslHTTPConnection.cpp b/src/HTTPServer/SslHTTPConnection.cpp new file mode 100644 index 000000000..fff96bb2e --- /dev/null +++ b/src/HTTPServer/SslHTTPConnection.cpp @@ -0,0 +1,103 @@ + +// SslHTTPConnection.cpp + +// Implements the cSslHTTPConnection class representing a HTTP connection made over a SSL link + +#include "Globals.h" +#include "SslHTTPConnection.h" +#include "HTTPServer.h" + + + + + +cSslHTTPConnection::cSslHTTPConnection(cHTTPServer & a_HTTPServer, const cX509CertPtr & a_Cert, const cPublicKeyPtr & a_PrivateKey) : + super(a_HTTPServer), + m_Ssl(64000), + m_Cert(a_Cert), + m_PrivateKey(a_PrivateKey) +{ + m_Ssl.Initialize(false); + m_Ssl.SetOwnCert(a_Cert, a_PrivateKey); +} + + + + + +void cSslHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) +{ + // If there is outgoing data in the queue, notify the server that it should write it out: + if (!m_OutgoingData.empty()) + { + m_HTTPServer.NotifyConnectionWrite(*this); + } + + // Process the received data: + const char * Data = a_Data; + size_t Size = a_Size; + for (;;) + { + // Try to write as many bytes into Ssl's "incoming" buffer as possible: + size_t BytesWritten = 0; + if (Size > 0) + { + BytesWritten = m_Ssl.WriteIncoming(Data, Size); + Data += BytesWritten; + Size -= BytesWritten; + } + + // Try to read as many bytes from SSL's decryption as possible: + char Buffer[32000]; + int NumRead = m_Ssl.ReadPlain(Buffer, sizeof(Buffer)); + if (NumRead > 0) + { + super::DataReceived(Buffer, (size_t)NumRead); + } + + // If both failed, bail out: + if ((BytesWritten == 0) && (NumRead <= 0)) + { + return; + } + } +} + + + + + +void cSslHTTPConnection::GetOutgoingData(AString & a_Data) +{ + for (;;) + { + // Write as many bytes from our buffer to SSL's encryption as possible: + int NumWritten = 0; + if (!m_OutgoingData.empty()) + { + NumWritten = m_Ssl.WritePlain(m_OutgoingData.data(), m_OutgoingData.size()); + if (NumWritten > 0) + { + m_OutgoingData.erase(0, (size_t)NumWritten); + } + } + + // Read as many bytes from SSL's "outgoing" buffer as possible: + char Buffer[32000]; + size_t NumBytes = m_Ssl.ReadOutgoing(Buffer, sizeof(Buffer)); + if (NumBytes > 0) + { + a_Data.append(Buffer, NumBytes); + } + + // If both failed, bail out: + if ((NumWritten <= 0) && (NumBytes == 0)) + { + return; + } + } +} + + + + diff --git a/src/HTTPServer/SslHTTPConnection.h b/src/HTTPServer/SslHTTPConnection.h new file mode 100644 index 000000000..2a648e8c8 --- /dev/null +++ b/src/HTTPServer/SslHTTPConnection.h @@ -0,0 +1,45 @@ + +// SslHTTPConnection.h + +// Declared the cSslHTTPConnection class representing a HTTP connection made over a SSL link + + + + + +#pragma once + +#include "HTTPConnection.h" +#include "PolarSSL++/BufferedSslContext.h" + + + + + +class cSslHTTPConnection : + public cHTTPConnection +{ + typedef cHTTPConnection super; + +public: + /** Creates a new connection on the specified server; sends the specified cert as the server certificate, + uses the private key for decryption. a_Private key is, despite the class name, a PRIVATE key for the cert. */ + cSslHTTPConnection(cHTTPServer & a_HTTPServer, const cX509CertPtr & a_Cert, const cPublicKeyPtr & a_PrivateKey); + +protected: + cBufferedSslContext m_Ssl; + + /** The certificate to send to the client */ + cX509CertPtr m_Cert; + + /** The private key used for the certificate */ + cPublicKeyPtr m_PrivateKey; + + // cHTTPConnection overrides: + virtual void DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client + virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client +} ; + + + + -- cgit v1.2.3 From 60850fe3e8da936d5b24460f33a1bf8f4d321ace Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 1 May 2014 15:08:15 +0200 Subject: Fixed crashes in the SSL HTTP connection. --- src/ClientHandle.cpp | 3 ++- src/ClientHandle.h | 2 +- src/HTTPServer/HTTPConnection.cpp | 14 +++++++------- src/HTTPServer/HTTPConnection.h | 12 +++++++++--- src/HTTPServer/SslHTTPConnection.cpp | 10 +++++++--- src/HTTPServer/SslHTTPConnection.h | 2 +- src/OSSupport/SocketThreads.h | 6 ++++-- src/RCONServer.cpp | 8 ++++---- src/RCONServer.h | 2 +- 9 files changed, 36 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 2362abe1e..a2bfdd381 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -2649,12 +2649,13 @@ void cClientHandle::PacketError(unsigned char a_PacketType) -void cClientHandle::DataReceived(const char * a_Data, size_t a_Size) +bool cClientHandle::DataReceived(const char * a_Data, size_t a_Size) { // Data is received from the client, store it in the buffer to be processed by the Tick thread: m_TimeSinceLastPacket = 0; cCSLock Lock(m_CSIncomingData); m_IncomingData.append(a_Data, a_Size); + return false; } diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 9f8d44129..ac44e43dc 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -387,7 +387,7 @@ private: void HandleCommandBlockMessage(const char * a_Data, unsigned int a_Length); // cSocketThreads::cCallback overrides: - virtual void DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client + virtual bool DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client virtual void SocketClosed (void) override; // The socket has been closed for any reason }; // tolua_export diff --git a/src/HTTPServer/HTTPConnection.cpp b/src/HTTPServer/HTTPConnection.cpp index 8e95eff2d..b127e7091 100644 --- a/src/HTTPServer/HTTPConnection.cpp +++ b/src/HTTPServer/HTTPConnection.cpp @@ -145,7 +145,7 @@ void cHTTPConnection::Terminate(void) -void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) +bool cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) { switch (m_State) { @@ -163,12 +163,12 @@ void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) m_CurrentRequest = NULL; m_State = wcsInvalid; m_HTTPServer.CloseConnection(*this); - return; + return true; } if (m_CurrentRequest->IsInHeaders()) { // The request headers are not yet complete - return; + return false; } // The request has finished parsing its headers successfully, notify of it: @@ -184,13 +184,12 @@ void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) // Process the rest of the incoming data into the request body: if (a_Size > BytesConsumed) { - cHTTPConnection::DataReceived(a_Data + BytesConsumed, a_Size - BytesConsumed); + return cHTTPConnection::DataReceived(a_Data + BytesConsumed, a_Size - BytesConsumed); } else { - cHTTPConnection::DataReceived("", 0); // If the request has zero body length, let it be processed right-away + return cHTTPConnection::DataReceived("", 0); // If the request has zero body length, let it be processed right-away } - break; } case wcsRecvBody: @@ -210,7 +209,7 @@ void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) { m_State = wcsInvalid; m_HTTPServer.CloseConnection(*this); - return; + return true; } delete m_CurrentRequest; m_CurrentRequest = NULL; @@ -224,6 +223,7 @@ void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) break; } } + return false; } diff --git a/src/HTTPServer/HTTPConnection.h b/src/HTTPServer/HTTPConnection.h index fc11f1ba6..6ea8a1ae8 100644 --- a/src/HTTPServer/HTTPConnection.h +++ b/src/HTTPServer/HTTPConnection.h @@ -91,9 +91,15 @@ protected: // cSocketThreads::cCallback overrides: - virtual void DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client - virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client - virtual void SocketClosed (void) override; // The socket has been closed for any reason + /** Data is received from the client. + Returns true if the connection has been closed as the result of parsing the data. */ + virtual bool DataReceived(const char * a_Data, size_t a_Size) override; + + /** Data can be sent to client */ + virtual void GetOutgoingData(AString & a_Data) override; + + /** The socket has been closed for any reason */ + virtual void SocketClosed(void) override; } ; typedef std::vector cHTTPConnections; diff --git a/src/HTTPServer/SslHTTPConnection.cpp b/src/HTTPServer/SslHTTPConnection.cpp index fff96bb2e..b6b222b47 100644 --- a/src/HTTPServer/SslHTTPConnection.cpp +++ b/src/HTTPServer/SslHTTPConnection.cpp @@ -25,7 +25,7 @@ cSslHTTPConnection::cSslHTTPConnection(cHTTPServer & a_HTTPServer, const cX509Ce -void cSslHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) +bool cSslHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) { // If there is outgoing data in the queue, notify the server that it should write it out: if (!m_OutgoingData.empty()) @@ -52,13 +52,17 @@ void cSslHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) int NumRead = m_Ssl.ReadPlain(Buffer, sizeof(Buffer)); if (NumRead > 0) { - super::DataReceived(Buffer, (size_t)NumRead); + if (super::DataReceived(Buffer, (size_t)NumRead)) + { + // The socket has been closed, and the object is already deleted. Bail out. + return true; + } } // If both failed, bail out: if ((BytesWritten == 0) && (NumRead <= 0)) { - return; + return false; } } } diff --git a/src/HTTPServer/SslHTTPConnection.h b/src/HTTPServer/SslHTTPConnection.h index 2a648e8c8..653acbfce 100644 --- a/src/HTTPServer/SslHTTPConnection.h +++ b/src/HTTPServer/SslHTTPConnection.h @@ -36,7 +36,7 @@ protected: cPublicKeyPtr m_PrivateKey; // cHTTPConnection overrides: - virtual void DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client + virtual bool DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client } ; diff --git a/src/OSSupport/SocketThreads.h b/src/OSSupport/SocketThreads.h index 679e374e1..944f5f3bc 100644 --- a/src/OSSupport/SocketThreads.h +++ b/src/OSSupport/SocketThreads.h @@ -63,8 +63,10 @@ public: // Force a virtual destructor in all subclasses: virtual ~cCallback() {} - /** Called when data is received from the remote party */ - virtual void DataReceived(const char * a_Data, size_t a_Size) = 0; + /** Called when data is received from the remote party. + SocketThreads does not care about the return value, others can use it for their specific purpose - + for example HTTPServer uses it to signal if the connection was terminated as a result of the data received. */ + virtual bool DataReceived(const char * a_Data, size_t a_Size) = 0; /** Called when data can be sent to remote party The function is supposed to *set* outgoing data to a_Data (overwrite) */ diff --git a/src/RCONServer.cpp b/src/RCONServer.cpp index d7083ff2b..fd4b26cab 100644 --- a/src/RCONServer.cpp +++ b/src/RCONServer.cpp @@ -169,7 +169,7 @@ cRCONServer::cConnection::cConnection(cRCONServer & a_RCONServer, cSocket & a_So -void cRCONServer::cConnection::DataReceived(const char * a_Data, size_t a_Size) +bool cRCONServer::cConnection::DataReceived(const char * a_Data, size_t a_Size) { // Append data to the buffer: m_Buffer.append(a_Data, a_Size); @@ -187,12 +187,12 @@ void cRCONServer::cConnection::DataReceived(const char * a_Data, size_t a_Size) m_RCONServer.m_SocketThreads.RemoveClient(this); m_Socket.CloseSocket(); delete this; - return; + return false; } if (Length > (int)(m_Buffer.size() + 4)) { // Incomplete packet yet, wait for more data to come - return; + return false; } int RequestID = IntFromBuffer(m_Buffer.data() + 4); @@ -202,7 +202,7 @@ void cRCONServer::cConnection::DataReceived(const char * a_Data, size_t a_Size) m_RCONServer.m_SocketThreads.RemoveClient(this); m_Socket.CloseSocket(); delete this; - return; + return false; } m_Buffer.erase(0, Length + 4); } // while (m_Buffer.size() >= 14) diff --git a/src/RCONServer.h b/src/RCONServer.h index b964852ab..47c746736 100644 --- a/src/RCONServer.h +++ b/src/RCONServer.h @@ -65,7 +65,7 @@ protected: // cSocketThreads::cCallback overrides: - virtual void DataReceived(const char * a_Data, size_t a_Size) override; + virtual bool DataReceived(const char * a_Data, size_t a_Size) override; virtual void GetOutgoingData(AString & a_Data) override; virtual void SocketClosed(void) override; -- cgit v1.2.3 From 1587b21edded56dbfb88150500336c2853b460c6 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 1 May 2014 15:21:41 +0200 Subject: Renamed cPublicKey to cCryptoKey. The class can hold both the private key and the public key, bad naming on PolarSSL's part. Also somewhat fixed the cert and key loading in cHTTPServer. --- src/HTTPServer/HTTPServer.cpp | 6 +- src/HTTPServer/HTTPServer.h | 6 +- src/HTTPServer/SslHTTPConnection.cpp | 2 +- src/HTTPServer/SslHTTPConnection.h | 8 +- src/PolarSSL++/CryptoKey.cpp | 149 +++++++++++++++++++++++++++++++++++ src/PolarSSL++/CryptoKey.h | 76 ++++++++++++++++++ src/PolarSSL++/CtrDrbgContext.h | 2 +- src/PolarSSL++/PublicKey.cpp | 149 ----------------------------------- src/PolarSSL++/PublicKey.h | 76 ------------------ src/PolarSSL++/SslContext.cpp | 2 +- src/PolarSSL++/SslContext.h | 13 ++- 11 files changed, 244 insertions(+), 245 deletions(-) create mode 100644 src/PolarSSL++/CryptoKey.cpp create mode 100644 src/PolarSSL++/CryptoKey.h delete mode 100644 src/PolarSSL++/PublicKey.cpp delete mode 100644 src/PolarSSL++/PublicKey.h (limited to 'src') diff --git a/src/HTTPServer/HTTPServer.cpp b/src/HTTPServer/HTTPServer.cpp index 9e3e0a17b..c45044c66 100644 --- a/src/HTTPServer/HTTPServer.cpp +++ b/src/HTTPServer/HTTPServer.cpp @@ -124,17 +124,17 @@ class cDebugCallbacks : cHTTPServer::cHTTPServer(void) : m_ListenThreadIPv4(*this, cSocket::IPv4, "WebServer IPv4"), m_ListenThreadIPv6(*this, cSocket::IPv6, "WebServer IPv6"), - m_Callbacks(NULL), - m_Cert(new cX509Cert), - m_CertPrivKey(new cPublicKey) + m_Callbacks(NULL) { AString CertFile = cFile::ReadWholeFile("webadmin/httpscert.crt"); AString KeyFile = cFile::ReadWholeFile("webadmin/httpskey.pem"); if (!CertFile.empty() && !KeyFile.empty()) { + m_Cert.reset(new cX509Cert); int res = m_Cert->Parse(CertFile.data(), CertFile.size()); if (res == 0) { + m_CertPrivKey.reset(new cCryptoKey); int res2 = m_CertPrivKey->ParsePrivate(KeyFile.data(), KeyFile.size(), ""); if (res2 != 0) { diff --git a/src/HTTPServer/HTTPServer.h b/src/HTTPServer/HTTPServer.h index eb91dd5a3..522b7da62 100644 --- a/src/HTTPServer/HTTPServer.h +++ b/src/HTTPServer/HTTPServer.h @@ -13,7 +13,7 @@ #include "../OSSupport/SocketThreads.h" #include "inifile/iniFile.h" #include "PolarSSL++/RsaPrivateKey.h" -#include "PolarSSL++/PublicKey.h" +#include "PolarSSL++/CryptoKey.h" #include "PolarSSL++/X509Cert.h" @@ -85,8 +85,8 @@ protected: /** The server certificate to use for the SSL connections */ cX509CertPtr m_Cert; - /** The private key for m_Cert. Despite the class name, this is the PRIVATE key. */ - cPublicKeyPtr m_CertPrivKey; + /** The private key for m_Cert. */ + cCryptoKeyPtr m_CertPrivKey; // cListenThread::cCallback overrides: diff --git a/src/HTTPServer/SslHTTPConnection.cpp b/src/HTTPServer/SslHTTPConnection.cpp index b6b222b47..d237089d9 100644 --- a/src/HTTPServer/SslHTTPConnection.cpp +++ b/src/HTTPServer/SslHTTPConnection.cpp @@ -11,7 +11,7 @@ -cSslHTTPConnection::cSslHTTPConnection(cHTTPServer & a_HTTPServer, const cX509CertPtr & a_Cert, const cPublicKeyPtr & a_PrivateKey) : +cSslHTTPConnection::cSslHTTPConnection(cHTTPServer & a_HTTPServer, const cX509CertPtr & a_Cert, const cCryptoKeyPtr & a_PrivateKey) : super(a_HTTPServer), m_Ssl(64000), m_Cert(a_Cert), diff --git a/src/HTTPServer/SslHTTPConnection.h b/src/HTTPServer/SslHTTPConnection.h index 653acbfce..c2c1585cd 100644 --- a/src/HTTPServer/SslHTTPConnection.h +++ b/src/HTTPServer/SslHTTPConnection.h @@ -22,9 +22,9 @@ class cSslHTTPConnection : typedef cHTTPConnection super; public: - /** Creates a new connection on the specified server; sends the specified cert as the server certificate, - uses the private key for decryption. a_Private key is, despite the class name, a PRIVATE key for the cert. */ - cSslHTTPConnection(cHTTPServer & a_HTTPServer, const cX509CertPtr & a_Cert, const cPublicKeyPtr & a_PrivateKey); + /** Creates a new connection on the specified server. + Sends the specified cert as the server certificate, uses the private key for decryption. */ + cSslHTTPConnection(cHTTPServer & a_HTTPServer, const cX509CertPtr & a_Cert, const cCryptoKeyPtr & a_PrivateKey); protected: cBufferedSslContext m_Ssl; @@ -33,7 +33,7 @@ protected: cX509CertPtr m_Cert; /** The private key used for the certificate */ - cPublicKeyPtr m_PrivateKey; + cCryptoKeyPtr m_PrivateKey; // cHTTPConnection overrides: virtual bool DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client diff --git a/src/PolarSSL++/CryptoKey.cpp b/src/PolarSSL++/CryptoKey.cpp new file mode 100644 index 000000000..0763c387b --- /dev/null +++ b/src/PolarSSL++/CryptoKey.cpp @@ -0,0 +1,149 @@ + +// CryptoKey.cpp + +// Implements the cCryptoKey class representing a RSA public key in PolarSSL + +#include "Globals.h" +#include "CryptoKey.h" + + + + + +cCryptoKey::cCryptoKey(void) +{ + pk_init(&m_Pk); + m_CtrDrbg.Initialize("rsa_pubkey", 10); +} + + + + + +cCryptoKey::cCryptoKey(const AString & a_PublicKeyData) +{ + pk_init(&m_Pk); + m_CtrDrbg.Initialize("rsa_pubkey", 10); + int res = ParsePublic(a_PublicKeyData.data(), a_PublicKeyData.size()); + if (res != 0) + { + LOGWARNING("Failed to parse public key: -0x%x", res); + ASSERT(!"Cannot parse PubKey"); + return; + } +} + + + + + +cCryptoKey::cCryptoKey(const AString & a_PrivateKeyData, const AString & a_Password) +{ + pk_init(&m_Pk); + m_CtrDrbg.Initialize("rsa_privkey", 11); + int res = ParsePrivate(a_PrivateKeyData.data(), a_PrivateKeyData.size(), a_Password); + if (res != 0) + { + LOGWARNING("Failed to parse private key: -0x%x", res); + ASSERT(!"Cannot parse PubKey"); + return; + } +} + + + + + +cCryptoKey::~cCryptoKey() +{ + pk_free(&m_Pk); +} + + + + + +int cCryptoKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength) +{ + ASSERT(IsValid()); + + size_t DecryptedLen = a_DecryptedMaxLength; + int res = pk_decrypt(&m_Pk, + a_EncryptedData, a_EncryptedLength, + a_DecryptedData, &DecryptedLen, a_DecryptedMaxLength, + ctr_drbg_random, m_CtrDrbg.GetInternal() + ); + if (res != 0) + { + return res; + } + return (int)DecryptedLen; +} + + + + + +int cCryptoKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength) +{ + ASSERT(IsValid()); + + size_t EncryptedLength = a_EncryptedMaxLength; + int res = pk_encrypt(&m_Pk, + a_PlainData, a_PlainLength, a_EncryptedData, &EncryptedLength, a_EncryptedMaxLength, + ctr_drbg_random, m_CtrDrbg.GetInternal() + ); + if (res != 0) + { + return res; + } + return (int)EncryptedLength; +} + + + + + + +int cCryptoKey::ParsePublic(const void * a_Data, size_t a_NumBytes) +{ + ASSERT(!IsValid()); // Cannot parse a second key + + return pk_parse_public_key(&m_Pk, (const unsigned char *)a_Data, a_NumBytes); +} + + + + + + +int cCryptoKey::ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password) +{ + ASSERT(!IsValid()); // Cannot parse a second key + + if (a_Password.empty()) + { + return pk_parse_key(&m_Pk, (const unsigned char *)a_Data, a_NumBytes, NULL, 0); + } + else + { + return pk_parse_key( + &m_Pk, + (const unsigned char *)a_Data, a_NumBytes, + (const unsigned char *)a_Password.c_str(), a_Password.size() + ); + } +} + + + + + +bool cCryptoKey::IsValid(void) const +{ + return (pk_get_type(&m_Pk) != POLARSSL_PK_NONE); +} + + + + diff --git a/src/PolarSSL++/CryptoKey.h b/src/PolarSSL++/CryptoKey.h new file mode 100644 index 000000000..9c298e501 --- /dev/null +++ b/src/PolarSSL++/CryptoKey.h @@ -0,0 +1,76 @@ + +// CryptoKey.h + +// Declares the cCryptoKey class representing a RSA public key in PolarSSL + + + + + +#pragma once + +#include "CtrDrbgContext.h" +#include "polarssl/pk.h" + + + + + +class cCryptoKey +{ + friend class cSslContext; + +public: + /** Constructs an empty key instance. Before use, it needs to be filled by ParsePublic() or ParsePrivate() */ + cCryptoKey(void); + + /** Constructs the public key out of the DER- or PEM-encoded pubkey data */ + cCryptoKey(const AString & a_PublicKeyData); + + /** Constructs the private key out of the DER- or PEM-encoded privkey data, with the specified password. + If a_Password is empty, no password is assumed. */ + cCryptoKey(const AString & a_PrivateKeyData, const AString & a_Password); + + ~cCryptoKey(); + + /** Decrypts the data using the stored public key + Both a_EncryptedData and a_DecryptedData must be at least bytes large. + Returns the number of bytes decrypted, or negative number for error. */ + int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength); + + /** Encrypts the data using the stored public key + Both a_EncryptedData and a_DecryptedData must be at least bytes large. + Returns the number of bytes decrypted, or negative number for error. */ + int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength); + + /** Parses the specified data into a public key representation. + The key can be DER- or PEM-encoded. + Returns 0 on success, PolarSSL error code on failure. */ + int ParsePublic(const void * a_Data, size_t a_NumBytes); + + /** Parses the specified data into a private key representation. + If a_Password is empty, no password is assumed. + The key can be DER- or PEM-encoded. + Returns 0 on success, PolarSSL error code on failure. */ + int ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password); + + /** Returns true if the contained key is valid. */ + bool IsValid(void) const; + +protected: + /** The PolarSSL representation of the key data */ + pk_context m_Pk; + + /** The random generator used in encryption and decryption */ + cCtrDrbgContext m_CtrDrbg; + + + /** Returns the internal context ptr. Only use in PolarSSL API calls. */ + pk_context * GetInternal(void) { return &m_Pk; } +} ; + +typedef SharedPtr cCryptoKeyPtr; + + + + diff --git a/src/PolarSSL++/CtrDrbgContext.h b/src/PolarSSL++/CtrDrbgContext.h index 65e9a2374..230db8753 100644 --- a/src/PolarSSL++/CtrDrbgContext.h +++ b/src/PolarSSL++/CtrDrbgContext.h @@ -26,7 +26,7 @@ class cCtrDrbgContext { friend class cSslContext; friend class cRsaPrivateKey; - friend class cPublicKey; + friend class cCryptoKey; public: /** Constructs the context with a new entropy context. */ diff --git a/src/PolarSSL++/PublicKey.cpp b/src/PolarSSL++/PublicKey.cpp deleted file mode 100644 index dae026082..000000000 --- a/src/PolarSSL++/PublicKey.cpp +++ /dev/null @@ -1,149 +0,0 @@ - -// PublicKey.cpp - -// Implements the cPublicKey class representing a RSA public key in PolarSSL - -#include "Globals.h" -#include "PublicKey.h" - - - - - -cPublicKey::cPublicKey(void) -{ - pk_init(&m_Pk); - m_CtrDrbg.Initialize("rsa_pubkey", 10); -} - - - - - -cPublicKey::cPublicKey(const AString & a_PublicKeyData) -{ - pk_init(&m_Pk); - m_CtrDrbg.Initialize("rsa_pubkey", 10); - int res = ParsePublic(a_PublicKeyData.data(), a_PublicKeyData.size()); - if (res != 0) - { - LOGWARNING("Failed to parse public key: -0x%x", res); - ASSERT(!"Cannot parse PubKey"); - return; - } -} - - - - - -cPublicKey::cPublicKey(const AString & a_PrivateKeyData, const AString & a_Password) -{ - pk_init(&m_Pk); - m_CtrDrbg.Initialize("rsa_privkey", 11); - int res = ParsePrivate(a_PrivateKeyData.data(), a_PrivateKeyData.size(), a_Password); - if (res != 0) - { - LOGWARNING("Failed to parse private key: -0x%x", res); - ASSERT(!"Cannot parse PubKey"); - return; - } -} - - - - - -cPublicKey::~cPublicKey() -{ - pk_free(&m_Pk); -} - - - - - -int cPublicKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength) -{ - ASSERT(IsValid()); - - size_t DecryptedLen = a_DecryptedMaxLength; - int res = pk_decrypt(&m_Pk, - a_EncryptedData, a_EncryptedLength, - a_DecryptedData, &DecryptedLen, a_DecryptedMaxLength, - ctr_drbg_random, m_CtrDrbg.GetInternal() - ); - if (res != 0) - { - return res; - } - return (int)DecryptedLen; -} - - - - - -int cPublicKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength) -{ - ASSERT(IsValid()); - - size_t EncryptedLength = a_EncryptedMaxLength; - int res = pk_encrypt(&m_Pk, - a_PlainData, a_PlainLength, a_EncryptedData, &EncryptedLength, a_EncryptedMaxLength, - ctr_drbg_random, m_CtrDrbg.GetInternal() - ); - if (res != 0) - { - return res; - } - return (int)EncryptedLength; -} - - - - - - -int cPublicKey::ParsePublic(const void * a_Data, size_t a_NumBytes) -{ - ASSERT(!IsValid()); // Cannot parse a second key - - return pk_parse_public_key(&m_Pk, (const unsigned char *)a_Data, a_NumBytes); -} - - - - - - -int cPublicKey::ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password) -{ - ASSERT(!IsValid()); // Cannot parse a second key - - if (a_Password.empty()) - { - return pk_parse_key(&m_Pk, (const unsigned char *)a_Data, a_NumBytes, NULL, 0); - } - else - { - return pk_parse_key( - &m_Pk, - (const unsigned char *)a_Data, a_NumBytes, - (const unsigned char *)a_Password.c_str(), a_Password.size() - ); - } -} - - - - - -bool cPublicKey::IsValid(void) const -{ - return (pk_get_type(&m_Pk) != POLARSSL_PK_NONE); -} - - - - diff --git a/src/PolarSSL++/PublicKey.h b/src/PolarSSL++/PublicKey.h deleted file mode 100644 index df52a4143..000000000 --- a/src/PolarSSL++/PublicKey.h +++ /dev/null @@ -1,76 +0,0 @@ - -// PublicKey.h - -// Declares the cPublicKey class representing a RSA public key in PolarSSL - - - - - -#pragma once - -#include "CtrDrbgContext.h" -#include "polarssl/pk.h" - - - - - -class cPublicKey -{ - friend class cSslContext; - -public: - /** Constructs an empty key instance. Before use, it needs to be filled by ParsePublic() or ParsePrivate() */ - cPublicKey(void); - - /** Constructs the public key out of the DER- or PEM-encoded pubkey data */ - cPublicKey(const AString & a_PublicKeyData); - - /** Constructs the private key out of the DER- or PEM-encoded privkey data, with the specified password. - If a_Password is empty, no password is assumed. */ - cPublicKey(const AString & a_PrivateKeyData, const AString & a_Password); - - ~cPublicKey(); - - /** Decrypts the data using the stored public key - Both a_EncryptedData and a_DecryptedData must be at least bytes large. - Returns the number of bytes decrypted, or negative number for error. */ - int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength); - - /** Encrypts the data using the stored public key - Both a_EncryptedData and a_DecryptedData must be at least bytes large. - Returns the number of bytes decrypted, or negative number for error. */ - int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength); - - /** Parses the specified data into a public key representation. - The key can be DER- or PEM-encoded. - Returns 0 on success, PolarSSL error code on failure. */ - int ParsePublic(const void * a_Data, size_t a_NumBytes); - - /** Parses the specified data into a private key representation. - If a_Password is empty, no password is assumed. - The key can be DER- or PEM-encoded. - Returns 0 on success, PolarSSL error code on failure. */ - int ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password); - - /** Returns true if the contained key is valid. */ - bool IsValid(void) const; - -protected: - /** The public key PolarSSL representation */ - pk_context m_Pk; - - /** The random generator used in encryption and decryption */ - cCtrDrbgContext m_CtrDrbg; - - - /** Returns the internal context ptr. Only use in PolarSSL API calls. */ - pk_context * GetInternal(void) { return &m_Pk; } -} ; - -typedef SharedPtr cPublicKeyPtr; - - - - diff --git a/src/PolarSSL++/SslContext.cpp b/src/PolarSSL++/SslContext.cpp index df0219610..bc397b655 100644 --- a/src/PolarSSL++/SslContext.cpp +++ b/src/PolarSSL++/SslContext.cpp @@ -115,7 +115,7 @@ void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cRsaPrivateKe -void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cPublicKeyPtr & a_OwnCertPrivKey) +void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cCryptoKeyPtr & a_OwnCertPrivKey) { ASSERT(m_IsValid); // Call Initialize() first diff --git a/src/PolarSSL++/SslContext.h b/src/PolarSSL++/SslContext.h index 273939b9f..a4ad1a345 100644 --- a/src/PolarSSL++/SslContext.h +++ b/src/PolarSSL++/SslContext.h @@ -11,7 +11,7 @@ #include "polarssl/ssl.h" #include "../ByteBuffer.h" -#include "PublicKey.h" +#include "CryptoKey.h" #include "RsaPrivateKey.h" #include "X509Cert.h" @@ -54,9 +54,8 @@ public: void SetOwnCert(const cX509CertPtr & a_OwnCert, const cRsaPrivateKeyPtr & a_OwnCertPrivKey); /** Sets the certificate to use as our own. Must be used when representing a server, optional when client. - Must be called after Initialize(). - Despite the class name, a_OwnCertPrivKey is a PRIVATE key. */ - void SetOwnCert(const cX509CertPtr & a_OwnCert, const cPublicKeyPtr & a_OwnCertPrivKey); + Must be called after Initialize(). */ + void SetOwnCert(const cX509CertPtr & a_OwnCert, const cCryptoKeyPtr & a_OwnCertPrivKey); /** Sets a cert chain as the trusted cert store for this context. Must be called after Initialize(). Calling this will switch the context into strict cert verification mode. @@ -107,11 +106,11 @@ protected: /** The certificate that we present to the peer. */ cX509CertPtr m_OwnCert; - /** Private key for m_OwnCert, if initialized from a cRsaPrivateKey */ + /** Private key for m_OwnCert, if initialized from a cRsaPrivateKey. */ cRsaPrivateKeyPtr m_OwnCertPrivKey; - /** Private key for m_OwnCert, if initialized from a cPublicKey. Despite the class name, this is a PRIVATE key. */ - cPublicKeyPtr m_OwnCertPrivKey2; + /** Private key for m_OwnCert, if initialized from a cCryptoKey. */ + cCryptoKeyPtr m_OwnCertPrivKey2; /** True if the SSL handshake has been completed. */ bool m_HasHandshaken; -- cgit v1.2.3 From d9e5dbf16526aa102abdc818d3515928663a973c Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 1 May 2014 18:06:23 +0200 Subject: Renamed PublicKey to CryptoKey in CMakeLists.txt --- src/PolarSSL++/CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/PolarSSL++/CMakeLists.txt b/src/PolarSSL++/CMakeLists.txt index b0a592760..9a59cdb2c 100644 --- a/src/PolarSSL++/CMakeLists.txt +++ b/src/PolarSSL++/CMakeLists.txt @@ -1,4 +1,3 @@ - cmake_minimum_required (VERSION 2.6) project (MCServer) @@ -11,8 +10,8 @@ set(SOURCES BufferedSslContext.cpp CallbackSslContext.cpp CtrDrbgContext.cpp + CryptoKey.cpp EntropyContext.cpp - PublicKey.cpp RsaPrivateKey.cpp Sha1Checksum.cpp SslContext.cpp @@ -26,8 +25,8 @@ set(HEADERS BufferedSslContext.h CallbackSslContext.h CtrDrbgContext.h + CryptoKey.h EntropyContext.h - PublicKey.h RsaPrivateKey.h SslContext.h Sha1Checksum.h -- cgit v1.2.3 From 9221b458989512e41f8502b56ed738d143599093 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 1 May 2014 21:23:37 +0200 Subject: cSslContext has virtual destructor now. --- src/PolarSSL++/SslContext.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/PolarSSL++/SslContext.h b/src/PolarSSL++/SslContext.h index a4ad1a345..6b4f2c1e7 100644 --- a/src/PolarSSL++/SslContext.h +++ b/src/PolarSSL++/SslContext.h @@ -40,7 +40,7 @@ public: /** Creates a new uninitialized context */ cSslContext(void); - ~cSslContext(); + virtual ~cSslContext(); /** Initializes the context for use as a server or client. Returns 0 on success, PolarSSL error on failure. */ -- cgit v1.2.3 From 30e81156eb6de46d7a374c044e26b35d83af4244 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 1 May 2014 22:02:45 +0200 Subject: Added a missing return statement. --- src/RCONServer.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/RCONServer.cpp b/src/RCONServer.cpp index fd4b26cab..cd5292ac3 100644 --- a/src/RCONServer.cpp +++ b/src/RCONServer.cpp @@ -206,6 +206,7 @@ bool cRCONServer::cConnection::DataReceived(const char * a_Data, size_t a_Size) } m_Buffer.erase(0, Length + 4); } // while (m_Buffer.size() >= 14) + return false; } -- cgit v1.2.3 From 3942ebdcb6e62d8b2fb85fad9144a993a78477a6 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 2 May 2014 23:46:06 +0200 Subject: WebAdmin outputs a log message about HTTP / HTTPS status. --- src/HTTPServer/HTTPServer.cpp | 49 +++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/HTTPServer/HTTPServer.cpp b/src/HTTPServer/HTTPServer.cpp index c45044c66..b78a538a2 100644 --- a/src/HTTPServer/HTTPServer.cpp +++ b/src/HTTPServer/HTTPServer.cpp @@ -126,6 +126,24 @@ cHTTPServer::cHTTPServer(void) : m_ListenThreadIPv6(*this, cSocket::IPv6, "WebServer IPv6"), m_Callbacks(NULL) { +} + + + + + +cHTTPServer::~cHTTPServer() +{ + Stop(); +} + + + + + +bool cHTTPServer::Initialize(const AString & a_PortsIPv4, const AString & a_PortsIPv6) +{ + // Read the HTTPS cert + key: AString CertFile = cFile::ReadWholeFile("webadmin/httpscert.crt"); AString KeyFile = cFile::ReadWholeFile("webadmin/httpskey.pem"); if (!CertFile.empty() && !KeyFile.empty()) @@ -139,32 +157,27 @@ cHTTPServer::cHTTPServer(void) : if (res2 != 0) { // Reading the private key failed, reset the cert: - LOGWARNING("WebAdmin: Cannot read HTTPS certificate private key: -0x%x", -res2); + LOGWARNING("WebServer: Cannot read HTTPS certificate private key: -0x%x", -res2); m_Cert.reset(); } } else { - LOGWARNING("WebAdmin: Cannot read HTTPS certificate: -0x%x", -res); + LOGWARNING("WebServer: Cannot read HTTPS certificate: -0x%x", -res); } } -} - - - - -cHTTPServer::~cHTTPServer() -{ - Stop(); -} - - - - - -bool cHTTPServer::Initialize(const AString & a_PortsIPv4, const AString & a_PortsIPv6) -{ + // Notify the admin about the HTTPS / HTTP status + if (m_Cert.get() == NULL) + { + LOGWARNING("WebServer: The server is running in unsecure HTTP mode."); + } + else + { + LOGINFO("WebServer: The server is running in secure HTTPS mode."); + } + + // Open up requested ports: bool HasAnyPort; HasAnyPort = m_ListenThreadIPv4.Initialize(a_PortsIPv4); HasAnyPort = m_ListenThreadIPv6.Initialize(a_PortsIPv6) || HasAnyPort; -- cgit v1.2.3 From ac1c3ba5d9ee407110700e2c5e9ce1d87e191e29 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Tue, 6 May 2014 21:43:31 +0200 Subject: Fixed an extra space. --- src/HTTPServer/HTTPServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/HTTPServer/HTTPServer.cpp b/src/HTTPServer/HTTPServer.cpp index b78a538a2..d288c83c9 100644 --- a/src/HTTPServer/HTTPServer.cpp +++ b/src/HTTPServer/HTTPServer.cpp @@ -150,7 +150,7 @@ bool cHTTPServer::Initialize(const AString & a_PortsIPv4, const AString & a_Port { m_Cert.reset(new cX509Cert); int res = m_Cert->Parse(CertFile.data(), CertFile.size()); - if (res == 0) + if (res == 0) { m_CertPrivKey.reset(new cCryptoKey); int res2 = m_CertPrivKey->ParsePrivate(KeyFile.data(), KeyFile.size(), ""); -- cgit v1.2.3 From 683b839e2b3e634dd1a0a5b85327efe4ffa968fd Mon Sep 17 00:00:00 2001 From: Mattes D Date: Sat, 10 May 2014 09:21:29 +0200 Subject: Client cert is not requested. --- src/PolarSSL++/SslContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/PolarSSL++/SslContext.cpp b/src/PolarSSL++/SslContext.cpp index bc397b655..c3074f197 100644 --- a/src/PolarSSL++/SslContext.cpp +++ b/src/PolarSSL++/SslContext.cpp @@ -59,7 +59,7 @@ int cSslContext::Initialize(bool a_IsClient, const SharedPtr & 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_authmode(&m_Ssl, a_IsClient ? SSL_VERIFY_OPTIONAL : SSL_VERIFY_NONE); // Clients ask for server's cert but don't verify strictly; servers don't ask clients for certs by default ssl_set_rng(&m_Ssl, ctr_drbg_random, &m_CtrDrbg->m_CtrDrbg); ssl_set_bio(&m_Ssl, ReceiveEncrypted, this, SendEncrypted, this); -- cgit v1.2.3