Support a trusted SHA1 fingerprint to be configured for each IRC server
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
<field name="username" type="string" length="1024" default=""/>
|
<field name="username" type="string" length="1024" default=""/>
|
||||||
<field name="realname" type="string" length="1024" default=""/>
|
<field name="realname" type="string" length="1024" default=""/>
|
||||||
<field name="verifyCert" type="boolean" default="true"/>
|
<field name="verifyCert" type="boolean" default="true"/>
|
||||||
|
<field name="trustedFingerprint" type="string"/>
|
||||||
|
|
||||||
<field name="encodingOut" type="string" default="ISO-8859-1"/>
|
<field name="encodingOut" type="string" default="ISO-8859-1"/>
|
||||||
<field name="encodingIn" type="string" default="ISO-8859-1"/>
|
<field name="encodingIn" type="string" default="ISO-8859-1"/>
|
||||||
|
|||||||
@@ -26,11 +26,17 @@ bool Basic_Credentials_Manager::certs_loaded = false;
|
|||||||
|
|
||||||
Basic_Credentials_Manager::Basic_Credentials_Manager(const TCPSocketHandler* const socket_handler):
|
Basic_Credentials_Manager::Basic_Credentials_Manager(const TCPSocketHandler* const socket_handler):
|
||||||
Botan::Credentials_Manager(),
|
Botan::Credentials_Manager(),
|
||||||
socket_handler(socket_handler)
|
socket_handler(socket_handler),
|
||||||
|
trusted_fingerprint{}
|
||||||
{
|
{
|
||||||
this->load_certs();
|
this->load_certs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Basic_Credentials_Manager::set_trusted_fingerprint(const std::string& fingerprint)
|
||||||
|
{
|
||||||
|
this->trusted_fingerprint = fingerprint;
|
||||||
|
}
|
||||||
|
|
||||||
void Basic_Credentials_Manager::verify_certificate_chain(const std::string& type,
|
void Basic_Credentials_Manager::verify_certificate_chain(const std::string& type,
|
||||||
const std::string& purported_hostname,
|
const std::string& purported_hostname,
|
||||||
const std::vector<Botan::X509_Certificate>& certs)
|
const std::vector<Botan::X509_Certificate>& certs)
|
||||||
@@ -44,6 +50,13 @@ void Basic_Credentials_Manager::verify_certificate_chain(const std::string& type
|
|||||||
catch (const std::exception& tls_exception)
|
catch (const std::exception& tls_exception)
|
||||||
{
|
{
|
||||||
log_warning("TLS certificate check failed: " << tls_exception.what());
|
log_warning("TLS certificate check failed: " << tls_exception.what());
|
||||||
|
if (!this->trusted_fingerprint.empty() && !certs.empty() &&
|
||||||
|
this->trusted_fingerprint == certs[0].fingerprint() &&
|
||||||
|
certs[0].matches_dns_name(purported_hostname))
|
||||||
|
// We trust the certificate, based on the trusted fingerprint and
|
||||||
|
// the fact that the hostname matches
|
||||||
|
return;
|
||||||
|
|
||||||
if (this->socket_handler->abort_on_invalid_cert())
|
if (this->socket_handler->abort_on_invalid_cert())
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ public:
|
|||||||
const std::vector<Botan::X509_Certificate>&) override final;
|
const std::vector<Botan::X509_Certificate>&) override final;
|
||||||
std::vector<Botan::Certificate_Store*> trusted_certificate_authorities(const std::string& type,
|
std::vector<Botan::Certificate_Store*> trusted_certificate_authorities(const std::string& type,
|
||||||
const std::string& context) override final;
|
const std::string& context) override final;
|
||||||
|
void set_trusted_fingerprint(const std::string& fingerprint);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const TCPSocketHandler* const socket_handler;
|
const TCPSocketHandler* const socket_handler;
|
||||||
@@ -26,6 +27,7 @@ private:
|
|||||||
static void load_certs();
|
static void load_certs();
|
||||||
static Botan::Certificate_Store_In_Memory certificate_store;
|
static Botan::Certificate_Store_In_Memory certificate_store;
|
||||||
static bool certs_loaded;
|
static bool certs_loaded;
|
||||||
|
std::string trusted_fingerprint;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //BOTAN_FOUND
|
#endif //BOTAN_FOUND
|
||||||
|
|||||||
@@ -248,7 +248,9 @@ private:
|
|||||||
static Botan::AutoSeeded_RNG rng;
|
static Botan::AutoSeeded_RNG rng;
|
||||||
static Botan::TLS::Policy policy;
|
static Botan::TLS::Policy policy;
|
||||||
static Botan::TLS::Session_Manager_In_Memory session_manager;
|
static Botan::TLS::Session_Manager_In_Memory session_manager;
|
||||||
|
protected:
|
||||||
Basic_Credentials_Manager credential_manager;
|
Basic_Credentials_Manager credential_manager;
|
||||||
|
private:
|
||||||
/**
|
/**
|
||||||
* We use a unique_ptr because we may not want to create the object at
|
* We use a unique_ptr because we may not want to create the object at
|
||||||
* all. The Botan::TLS::Client object generates a handshake message and
|
* all. The Botan::TLS::Client object generates a handshake message and
|
||||||
|
|||||||
@@ -89,6 +89,13 @@ void IrcClient::start()
|
|||||||
|
|
||||||
this->bind_addr = Config::get("outgoing_bind", "");
|
this->bind_addr = Config::get("outgoing_bind", "");
|
||||||
|
|
||||||
|
#ifdef BOTAN_FOUND
|
||||||
|
# ifdef USE_DATABASE
|
||||||
|
auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(),
|
||||||
|
this->get_hostname());
|
||||||
|
this->credential_manager.set_trusted_fingerprint(options.trustedFingerprint);
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
this->connect(this->hostname, port, tls);
|
this->connect(this->hostname, port, tls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -175,6 +175,19 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com
|
|||||||
verify_cert_value.set_inner("false");
|
verify_cert_value.set_inner("false");
|
||||||
verify_cert.add_child(std::move(verify_cert_value));
|
verify_cert.add_child(std::move(verify_cert_value));
|
||||||
x.add_child(std::move(verify_cert));
|
x.add_child(std::move(verify_cert));
|
||||||
|
|
||||||
|
XmlNode fingerprint("field");
|
||||||
|
fingerprint["var"] = "fingerprint";
|
||||||
|
fingerprint["type"] = "text-single";
|
||||||
|
fingerprint["label"] = "SHA-1 fingerprint of the TLS certificate to trust.";
|
||||||
|
if (!options.trustedFingerprint.value().empty())
|
||||||
|
{
|
||||||
|
XmlNode fingerprint_value("value");
|
||||||
|
fingerprint_value.set_inner(options.trustedFingerprint.value());
|
||||||
|
fingerprint.add_child(std::move(fingerprint_value));
|
||||||
|
}
|
||||||
|
fingerprint.add_child(required);
|
||||||
|
x.add_child(std::move(fingerprint));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
XmlNode pass("field");
|
XmlNode pass("field");
|
||||||
@@ -301,6 +314,13 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com
|
|||||||
auto val = to_bool(value->get_inner());
|
auto val = to_bool(value->get_inner());
|
||||||
options.verifyCert = val;
|
options.verifyCert = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (field->get_tag("var") == "fingerprint" && value &&
|
||||||
|
!value->get_inner().empty())
|
||||||
|
{
|
||||||
|
options.trustedFingerprint = value->get_inner();
|
||||||
|
}
|
||||||
|
|
||||||
#endif // BOTAN_FOUND
|
#endif // BOTAN_FOUND
|
||||||
|
|
||||||
else if (field->get_tag("var") == "pass" &&
|
else if (field->get_tag("var") == "pass" &&
|
||||||
|
|||||||
Reference in New Issue
Block a user