Add network-specific config for cert validation

Added the following two network-specific configuration options that can
be changed via controlpanel or webadmin:

* TrustAllCerts: Will trust ALL certificates when enabled, effectively
  disabling TLS certificate validation.
  Default value: false
* TrustPKI: Whether or not to trust PKI-valid certificates. Setting this
  to false will make znc trust only trusted certificates added by the
  user.
  Default value: true

With default values, behavior is exactly the same as before.

This is based on the work of Roelf Wichertjes. See YourBNC/znc@5c747598.

See znc/znc#866.
This commit is contained in:
xnrand
2016-05-20 01:17:26 +02:00
parent c5db7793d3
commit 409ed4b6bc
8 changed files with 69 additions and 2 deletions
+6
View File
@@ -11,6 +11,12 @@
* it is not called during ZNC startup any more
* Fix build on Solaris 10
* Fix build with LibreSSL
* Added two network-specific config options to control TLS certificate
validation
* `TrustAllCerts`: Disables certificate validation. Will take precedence
over TrustPKI
* `TrustPKI`: Whether or not to trust PKI-valid Certificates. Setting this
to false will make znc trust only trusted certificates added by the user.
+8
View File
@@ -266,6 +266,12 @@ class CIRCNetwork {
m_uJoinDelay = uJoinDelay;
}
void SetTrustAllCerts(const bool bTrustAll = false) { m_bTrustAllCerts = bTrustAll; }
bool GetTrustAllCerts() const { return m_bTrustAllCerts; }
void SetTrustPKI(const bool bTrustPKI = true) { m_bTrustPKI = bTrustPKI; }
bool GetTrustPKI() const { return m_bTrustPKI; }
unsigned long long BytesRead() const { return m_uBytesRead; }
unsigned long long BytesWritten() const { return m_uBytesWritten; }
@@ -305,6 +311,8 @@ class CIRCNetwork {
CString m_sChanPrefixes;
bool m_bIRCConnectEnabled;
bool m_bTrustAllCerts;
bool m_bTrustPKI;
CString m_sIRCServer;
std::vector<CServer*> m_vServers;
size_t m_uServerIdx; ///< Index in m_vServers of our current server + 1
+8
View File
@@ -46,6 +46,12 @@ class CZNCSock : public Csock, public CCoreTranslationMixin {
m_ssTrustedFingerprints = ssFPs;
}
void SetTrustAllCerts(const bool bTrustAll = false) { m_bTrustAllCerts = bTrustAll; }
bool GetTrustAllCerts() const { return m_bTrustAllCerts; }
void SetTrustPKI(const bool bTrustPKI = true) { m_bTrustPKI = bTrustPKI; }
bool GetTrustPKI() const { return m_bTrustPKI; }
void SetEncoding(const CString&);
virtual CString GetRemoteIP() const { return Csock::GetRemoteIP(); }
@@ -60,6 +66,8 @@ class CZNCSock : public Csock, public CCoreTranslationMixin {
CString m_sHostToVerifySSL;
SCString m_ssTrustedFingerprints;
SCString m_ssCertVerificationErrors;
bool m_bTrustAllCerts;
bool m_bTrustPKI;
};
enum EAddrType { ADDR_IPV4ONLY, ADDR_IPV6ONLY, ADDR_ALL };
+14
View File
@@ -132,6 +132,8 @@ class CAdminMod : public CModule {
{"Encoding", str},
#endif
{"QuitMsg", str},
{"TrustAllCerts", boolean},
{"TrustPKI", boolean},
};
PrintVarsHelp(sVarFilter, nvars, ARRAY_SIZE(nvars),
"The following variables are available when using "
@@ -520,6 +522,10 @@ class CAdminMod : public CModule {
#endif
} else if (sVar.Equals("quitmsg")) {
PutModule("QuitMsg = " + pNetwork->GetQuitMsg());
} else if (sVar.Equals("trustallcerts")) {
PutModule("TrustAllCerts = " + CString(pNetwork->GetTrustAllCerts()));
} else if (sVar.Equals("trustpki")) {
PutModule("TrustPKI = " + CString(pNetwork->GetTrustPKI()));
} else {
PutModule("Error: Unknown variable");
}
@@ -596,6 +602,14 @@ class CAdminMod : public CModule {
} else if (sVar.Equals("quitmsg")) {
pNetwork->SetQuitMsg(sValue);
PutModule("QuitMsg = " + pNetwork->GetQuitMsg());
} else if (sVar.Equals("trustallcerts")) {
bool b = sValue.ToBool();
pNetwork->SetTrustAllCerts(b);
PutModule("TrustAllCerts = " + CString(b));
} else if (sVar.Equals("trustpki")) {
bool b = sValue.ToBool();
pNetwork->SetTrustPKI(b);
PutModule("TrustPKI = " + CString(b));
} else {
PutModule("Error: Unknown variable");
}
@@ -73,6 +73,18 @@
<label for="doconnect_checkbox"><? FORMAT "Connect to IRC &amp; automatically re-connect" ?></label></div>
</div>
<div class="subsection">
<div class="inputlabel"><? FORMAT "Trust all certs:" ?></div>
<div class="checkbox"><input type="checkbox" name="trustallcerts" id="trustallcerts_checkbox"<? IF TrustAllCerts ?> checked="checked"<? ENDIF ?> />
<label for="trustallcerts_checkbox"><? FORMAT "Disable certificate validation (takes precedence over TrustPKI). INSECURE!" ?></label></div>
</div>
<div class="subsection">
<div class="inputlabel"><? FORMAT "Trust the PKI:" ?></div>
<div class="checkbox"><input type="checkbox" name="trustpki" id="trustpki_checkbox"<? IF TrustPKI ?> checked="checked"<? ENDIF ?> />
<label for="trustpki_checkbox"><? FORMAT "Setting this to false will trust only certificates you added fingerprints for." ?></label></div>
</div>
<div class="subsection half" id="servers_plain">
<div class="inputlabel"><? FORMAT "Servers of this IRC network:" ?></div>
<div><textarea name="servers" cols="70" rows="5" id="servers_text"><? LOOP ServerLoop ?><? VAR Server ?>
+7
View File
@@ -937,6 +937,8 @@ class CWebAdminMod : public CModule {
Tmpl["IRCConnectEnabled"] =
CString(pNetwork->GetIRCConnectEnabled());
Tmpl["TrustAllCerts"] = CString(pNetwork->GetTrustAllCerts());
Tmpl["TrustPKI"] = CString(pNetwork->GetTrustPKI());
breadNet["Text"] = f("Edit Network [{1}]")(pNetwork->GetName());
@@ -985,6 +987,8 @@ class CWebAdminMod : public CModule {
Tmpl["Title"] =
f("Add Network for User [{1}]")(pUser->GetUserName());
Tmpl["IRCConnectEnabled"] = "true";
Tmpl["TrustAllCerts"] = "false";
Tmpl["TrustPKI"] = "true";
Tmpl["FloodProtection"] = "true";
Tmpl["FloodRate"] = "1.0";
Tmpl["FloodBurst"] = "4";
@@ -1076,6 +1080,9 @@ class CWebAdminMod : public CModule {
pNetwork->SetIRCConnectEnabled(WebSock.GetParam("doconnect").ToBool());
pNetwork->SetTrustAllCerts(WebSock.GetParam("trustallcerts").ToBool());
pNetwork->SetTrustPKI(WebSock.GetParam("trustpki").ToBool());
sArg = WebSock.GetParam("bindhost");
// To change BindHosts be admin or don't have DenySetBindHost
if (spSession->IsAdmin() || !spSession->GetUser()->DenySetBindHost()) {
+8
View File
@@ -140,6 +140,8 @@ CIRCNetwork::CIRCNetwork(CUser* pUser, const CString& sName)
m_vQueries(),
m_sChanPrefixes(""),
m_bIRCConnectEnabled(true),
m_bTrustAllCerts(false),
m_bTrustPKI(true),
m_sIRCServer(""),
m_vServers(),
m_uServerIdx(0),
@@ -377,6 +379,8 @@ bool CIRCNetwork::ParseConfig(CConfig* pConfig, CString& sError,
};
TOption<bool> BoolOptions[] = {
{"ircconnectenabled", &CIRCNetwork::SetIRCConnectEnabled},
{"trustallcerts", &CIRCNetwork::SetTrustAllCerts},
{"trustpki", &CIRCNetwork::SetTrustPKI},
};
TOption<double> DoubleOptions[] = {
{"floodrate", &CIRCNetwork::SetFloodRate},
@@ -545,6 +549,8 @@ CConfig CIRCNetwork::ToConfig() const {
config.AddKeyValuePair("IRCConnectEnabled",
CString(GetIRCConnectEnabled()));
config.AddKeyValuePair("TrustAllCerts", CString(GetTrustAllCerts()));
config.AddKeyValuePair("TrustPKI", CString(GetTrustPKI()));
config.AddKeyValuePair("FloodRate", CString(GetFloodRate()));
config.AddKeyValuePair("FloodBurst", CString(GetFloodBurst()));
config.AddKeyValuePair("JoinDelay", CString(GetJoinDelay()));
@@ -1272,6 +1278,8 @@ bool CIRCNetwork::Connect() {
CIRCSock* pIRCSock = new CIRCSock(this);
pIRCSock->SetPass(pServer->GetPass());
pIRCSock->SetSSLTrustedPeerFingerprints(m_ssTrustedFingerprints);
pIRCSock->SetTrustAllCerts(GetTrustAllCerts());
pIRCSock->SetTrustPKI(GetTrustPKI());
DEBUG("Connecting user/network [" << m_pUser->GetUserName() << "/"
<< m_sName << "]");
+6 -2
View File
@@ -123,13 +123,17 @@ void CZNCSock::SSLHandShakeFinished() {
Close();
return;
}
if (GetTrustAllCerts()) {
DEBUG(GetSockName() + ": Verification disabled, trusting all.");
return;
}
CString sHostVerifyError;
if (!ZNC_SSLVerifyHost(m_sHostToVerifySSL, pCert, sHostVerifyError)) {
m_ssCertVerificationErrors.insert(sHostVerifyError);
}
X509_free(pCert);
if (m_ssCertVerificationErrors.empty()) {
DEBUG(GetSockName() + ": Good cert");
if (GetTrustPKI() && m_ssCertVerificationErrors.empty()) {
DEBUG(GetSockName() + ": Good cert (PKI valid)");
return;
}
CString sFP = GetSSLPeerFingerprint();