diff --git a/include/znc/znc.h b/include/znc/znc.h index 0355fe73..08d12f33 100644 --- a/include/znc/znc.h +++ b/include/znc/znc.h @@ -128,6 +128,7 @@ public: unsigned int GetConnectDelay() const { return m_uiConnectDelay; } bool GetProtectWebSessions() const { return m_bProtectWebSessions; } CString GetSSLCiphers() const { return m_sSSLCiphers; } + Csock::EDisableProtocol GetDisabledSSLProtocols() const { return static_cast(m_uDisabledSSLProtocols); } // !Getters // Static allocator @@ -211,6 +212,7 @@ protected: CString m_sPidFile; CString m_sSSLCertFile; CString m_sSSLCiphers; + CString m_sSSLProtocols; VCString m_vsBindHosts; VCString m_vsTrustedProxies; VCString m_vsMotd; @@ -218,6 +220,7 @@ protected: unsigned int m_uiConnectDelay; unsigned int m_uiAnonIPLimit; unsigned int m_uiMaxBufferSize; + unsigned int m_uDisabledSSLProtocols; CModules* m_pModules; unsigned long long m_uBytesRead; unsigned long long m_uBytesWritten; diff --git a/src/Socket.cpp b/src/Socket.cpp index 57f89422..c31f51d9 100644 --- a/src/Socket.cpp +++ b/src/Socket.cpp @@ -22,7 +22,7 @@ CZNCSock::CZNCSock(int timeout) : Csock(timeout) { #ifdef HAVE_LIBSSL DisableSSLCompression(); - DisableSSLProtocols(EDP_SSL); + DisableSSLProtocols(CZNC::Get().GetDisabledSSLProtocols()); CString sCipher = CZNC::Get().GetSSLCiphers(); if (!sCipher.empty()) { SetCipher(sCipher); @@ -33,7 +33,7 @@ CZNCSock::CZNCSock(int timeout) : Csock(timeout) { CZNCSock::CZNCSock(const CString& sHost, u_short port, int timeout) : Csock(sHost, port, timeout) { #ifdef HAVE_LIBSSL DisableSSLCompression(); - DisableSSLProtocols(EDP_SSL); + DisableSSLProtocols(CZNC::Get().GetDisabledSSLProtocols()); CString sCipher = CZNC::Get().GetSSLCiphers(); if (!sCipher.empty()) { SetCipher(sCipher); diff --git a/src/znc.cpp b/src/znc.cpp index 19b730f2..e2c8c5ba 100644 --- a/src/znc.cpp +++ b/src/znc.cpp @@ -55,6 +55,8 @@ CZNC::CZNC() { m_sConnectThrottle.SetTTL(30000); m_pLockFile = NULL; m_bProtectWebSessions = true; + m_uDisabledSSLProtocols = Csock::EDP_SSL; + m_sSSLProtocols = ""; } CZNC::~CZNC() { @@ -479,6 +481,10 @@ bool CZNC::WriteConfig() { config.AddKeyValuePair("SSLCiphers", CString(m_sSSLCiphers)); } + if (!m_sSSLProtocols.empty()) { + config.AddKeyValuePair("SSLProtocols", m_sSSLProtocols); + } + for (unsigned int m = 0; m < m_vsMotd.size(); m++) { config.AddKeyValuePair("Motd", m_vsMotd[m].FirstLine()); } @@ -1094,6 +1100,45 @@ bool CZNC::DoRehash(CString& sError) if (config.FindStringEntry("protectwebsessions", sVal)) m_bProtectWebSessions = sVal.ToBool(); + if (config.FindStringEntry("sslprotocols", m_sSSLProtocols)) { + VCString vsProtocols; + m_sSSLProtocols.Split(" ", vsProtocols, false, "", "", true, true); + + for (CString& sProtocol : vsProtocols) { + + unsigned int uFlag = 0; + bool bEnable = sProtocol.TrimPrefix("+"); + bool bDisable = sProtocol.TrimPrefix("-"); + + if (sProtocol.Equals("All")) { + uFlag = ~0; + } else if (sProtocol.Equals("SSLv2")) { + uFlag = Csock::EDP_SSLv2; + } else if (sProtocol.Equals("SSLv3")) { + uFlag = Csock::EDP_SSLv3; + } else if (sProtocol.Equals("TLSv1")) { + uFlag = Csock::EDP_TLSv1; + } else if (sProtocol.Equals("TLSv1.1")) { + uFlag = Csock::EDP_TLSv1_1; + } else if (sProtocol.Equals("TLSv1.2")) { + uFlag = Csock::EDP_TLSv1_2; + } else { + CUtils::PrintError("Invalid SSLProtocols value [" + sProtocol + "]"); + CUtils::PrintError("The syntax is [SSLProtocols = [+|-] ...]"); + CUtils::PrintError("Available protocols are [SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2]"); + return false; + } + + if (bEnable) { + m_uDisabledSSLProtocols &= ~uFlag; + } else if (bDisable) { + m_uDisabledSSLProtocols |= uFlag; + } else { + m_uDisabledSSLProtocols = ~uFlag; + } + } + } + // This has to be after SSLCertFile is handled since it uses that value const char *szListenerEntries[] = { "listen", "listen6", "listen4",