From b759c688477a33b63dc0588bd64d34cd654be599 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 6 Nov 2014 20:39:00 +0100 Subject: [PATCH] Config option for SSL protocols (resolves #720) ZNC currently disables SSLv2 and SSLv3 by default. To keep the ZNC defaults (recommended, may change in the future versions) and for example disable TLSv1 in addition, specify in the global config section: SSLProtocols = -TLSv1 Available (case-insentive) values are: All, SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2 A non-prefixed "absolute" value overrides the ZNC defaults: SSLProtocols = TLSV1 +TLSv1.1 +TLSv1.2 --- include/znc/znc.h | 3 +++ src/Socket.cpp | 4 ++-- src/znc.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) 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",