Commit 1f8333f2 authored by louiz’'s avatar louiz’

Support a trusted SHA1 fingerprint to be configured for each IRC server

parent a38b1769
...@@ -13,6 +13,7 @@ ...@@ -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; ...@@ -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 ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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() ...@@ -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 ...@@ -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");
...@@ -295,12 +308,19 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com ...@@ -295,12 +308,19 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com
options.tlsPorts = ports; options.tlsPorts = ports;
} }
else if (field->get_tag("var") == "verify_cert" && value else if (field->get_tag("var") == "verify_cert" && value
&& !value->get_inner().empty()) && !value->get_inner().empty())
{ {
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" &&
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment