summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--louloulibs/network/credentials_manager.cpp35
-rw-r--r--louloulibs/network/credentials_manager.hpp11
-rw-r--r--louloulibs/network/tcp_socket_handler.cpp6
-rw-r--r--louloulibs/network/tcp_socket_handler.hpp12
-rw-r--r--src/irc/irc_client.cpp11
-rw-r--r--src/irc/irc_client.hpp3
-rw-r--r--src/xmpp/biboumi_adhoc_commands.cpp20
7 files changed, 87 insertions, 11 deletions
diff --git a/louloulibs/network/credentials_manager.cpp b/louloulibs/network/credentials_manager.cpp
index 7c13319..b9a9af8 100644
--- a/louloulibs/network/credentials_manager.cpp
+++ b/louloulibs/network/credentials_manager.cpp
@@ -1,25 +1,48 @@
#include "louloulibs.h"
#ifdef BOTAN_FOUND
+#include <network/tcp_socket_handler.hpp>
#include <network/credentials_manager.hpp>
#include <logger/logger.hpp>
#include <botan/tls_exceptn.h>
-Basic_Credentials_Manager::Basic_Credentials_Manager():
- Botan::Credentials_Manager()
+#ifdef USE_DATABASE
+# include <database/database.hpp>
+#endif
+
+Botan::Certificate_Store_In_Memory Basic_Credentials_Manager::certificate_store;
+bool Basic_Credentials_Manager::certs_loaded = false;
+
+Basic_Credentials_Manager::Basic_Credentials_Manager(const TCPSocketHandler* const socket_handler):
+ Botan::Credentials_Manager(),
+ socket_handler(socket_handler)
{
this->load_certs();
}
+
void Basic_Credentials_Manager::verify_certificate_chain(const std::string& type,
const std::string& purported_hostname,
const std::vector<Botan::X509_Certificate>& certs)
{
log_debug("Checking remote certificate (" << type << ") for hostname " << purported_hostname);
- Botan::Credentials_Manager::verify_certificate_chain(type, purported_hostname, certs);
- log_debug("Certificate is valid");
+ try
+ {
+ Botan::Credentials_Manager::verify_certificate_chain(type, purported_hostname, certs);
+ log_debug("Certificate is valid");
+ }
+ catch (const std::exception& tls_exception)
+ {
+ log_warning("TLS certificate check failed: " << tls_exception.what());
+ if (this->socket_handler->abort_on_invalid_cert())
+ throw;
+ }
}
+
void Basic_Credentials_Manager::load_certs()
{
+ // Only load the certificates the first time
+ if (Basic_Credentials_Manager::certs_loaded)
+ return;
const std::vector<std::string> paths = {"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem"};
for (const auto& path: paths)
{
@@ -27,10 +50,12 @@ void Basic_Credentials_Manager::load_certs()
while (!bundle.end_of_data() && bundle.check_available(27))
{
const Botan::X509_Certificate cert(bundle);
- this->certificate_store.add_certificate(cert);
+ Basic_Credentials_Manager::certificate_store.add_certificate(cert);
}
}
+ Basic_Credentials_Manager::certs_loaded = true;
}
+
std::vector<Botan::Certificate_Store*> Basic_Credentials_Manager::trusted_certificate_authorities(const std::string&, const std::string&)
{
return {&this->certificate_store};
diff --git a/louloulibs/network/credentials_manager.hpp b/louloulibs/network/credentials_manager.hpp
index 8641f1d..e292321 100644
--- a/louloulibs/network/credentials_manager.hpp
+++ b/louloulibs/network/credentials_manager.hpp
@@ -8,10 +8,12 @@
#include <botan/botan.h>
#include <botan/tls_client.h>
+class TCPSocketHandler;
+
class Basic_Credentials_Manager: public Botan::Credentials_Manager
{
public:
- Basic_Credentials_Manager();
+ Basic_Credentials_Manager(const TCPSocketHandler* const socket_handler);
void verify_certificate_chain(const std::string& type,
const std::string& purported_hostname,
const std::vector<Botan::X509_Certificate>&) override final;
@@ -19,8 +21,11 @@ public:
const std::string& context) override final;
private:
- void load_certs();
- Botan::Certificate_Store_In_Memory certificate_store;
+ const TCPSocketHandler* const socket_handler;
+
+ static void load_certs();
+ static Botan::Certificate_Store_In_Memory certificate_store;
+ static bool certs_loaded;
};
#endif //BOTAN_FOUND
diff --git a/louloulibs/network/tcp_socket_handler.cpp b/louloulibs/network/tcp_socket_handler.cpp
index 81a36ef..0ed74a2 100644
--- a/louloulibs/network/tcp_socket_handler.cpp
+++ b/louloulibs/network/tcp_socket_handler.cpp
@@ -19,7 +19,6 @@
# include <botan/tls_exceptn.h>
Botan::AutoSeeded_RNG TCPSocketHandler::rng;
-Basic_Credentials_Manager TCPSocketHandler::credential_manager;
Botan::TLS::Policy TCPSocketHandler::policy;
Botan::TLS::Session_Manager_In_Memory TCPSocketHandler::session_manager(TCPSocketHandler::rng);
@@ -40,6 +39,9 @@ TCPSocketHandler::TCPSocketHandler(std::shared_ptr<Poller> poller):
connected(false),
connecting(false),
hostname_resolution_failed(false)
+#ifdef BOTAN_FOUND
+ ,credential_manager(this)
+#endif
{}
void TCPSocketHandler::init_socket(const struct addrinfo* rp)
@@ -369,7 +371,7 @@ void TCPSocketHandler::start_tls()
std::bind(&TCPSocketHandler::tls_data_cb, this, ph::_1, ph::_2),
std::bind(&TCPSocketHandler::tls_alert_cb, this, ph::_1, ph::_2, ph::_3),
std::bind(&TCPSocketHandler::tls_handshake_cb, this, ph::_1),
- session_manager, credential_manager, policy,
+ session_manager, this->credential_manager, policy,
rng, server_info, Botan::TLS::Protocol_Version::latest_tls_version());
}
diff --git a/louloulibs/network/tcp_socket_handler.hpp b/louloulibs/network/tcp_socket_handler.hpp
index d173c1f..213e286 100644
--- a/louloulibs/network/tcp_socket_handler.hpp
+++ b/louloulibs/network/tcp_socket_handler.hpp
@@ -90,6 +90,16 @@ public:
* The size argument is the size of the last chunk of data that was added to the buffer.
*/
virtual void parse_in_buffer(const size_t size) = 0;
+#ifdef BOTAN_FOUND
+ /**
+ * Tell whether the credential manager should cancel the connection when the
+ * certificate is invalid.
+ */
+ virtual bool abort_on_invalid_cert() const
+ {
+ return true;
+ }
+#endif
bool is_connected() const override final;
bool is_connecting() const;
@@ -230,9 +240,9 @@ private:
* Botan stuff to manipulate a TLS session.
*/
static Botan::AutoSeeded_RNG rng;
- static Basic_Credentials_Manager credential_manager;
static Botan::TLS::Policy policy;
static Botan::TLS::Session_Manager_In_Memory session_manager;
+ Basic_Credentials_Manager credential_manager;
/**
* 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
diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp
index 7caf443..93ea2ae 100644
--- a/src/irc/irc_client.cpp
+++ b/src/irc/irc_client.cpp
@@ -962,3 +962,14 @@ void IrcClient::leave_dummy_channel(const std::string& exit_message)
this->dummy_channel.remove_all_users();
this->bridge->send_muc_leave(Iid("%"s + this->hostname), std::string(this->current_nick), exit_message, true);
}
+
+#ifdef BOTAN_FOUND
+bool IrcClient::abort_on_invalid_cert() const
+{
+#ifdef USE_DATABASE
+ auto options = Database::get_irc_server_options(this->bridge->get_bare_jid(), this->hostname);
+ return options.verifyCert.value();
+#endif
+ return true;
+}
+#endif
diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp
index cdae0aa..733fc92 100644
--- a/src/irc/irc_client.hpp
+++ b/src/irc/irc_client.hpp
@@ -52,6 +52,9 @@ public:
* complete messages from it.
*/
void parse_in_buffer(const size_t) override final;
+#ifdef BOTAN_FOUND
+ virtual bool abort_on_invalid_cert() const override final;
+#endif
/**
* Return the channel with this name, create it if it does not yet exist
*/
diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp
index fa3a35c..ff0c8d4 100644
--- a/src/xmpp/biboumi_adhoc_commands.cpp
+++ b/src/xmpp/biboumi_adhoc_commands.cpp
@@ -162,6 +162,19 @@ void ConfigureIrcServerStep1(XmppComponent*, AdhocSession& session, XmlNode& com
}
tls_ports.add_child(required);
x.add_child(std::move(tls_ports));
+
+ XmlNode verify_cert("field");
+ verify_cert["var"] = "verify_cert";
+ verify_cert["type"] = "boolean";
+ verify_cert["label"] = "Verify certificate";
+ verify_cert["desc"] = "Whether or not to abort the connection if the server’s TLS certificate is invalid";
+ XmlNode verify_cert_value("value");
+ if (options.verifyCert.value())
+ verify_cert_value.set_inner("true");
+ else
+ verify_cert_value.set_inner("false");
+ verify_cert.add_child(std::move(verify_cert_value));
+ x.add_child(std::move(verify_cert));
#endif
XmlNode pass("field");
@@ -252,6 +265,13 @@ void ConfigureIrcServerStep2(XmppComponent*, AdhocSession& session, XmlNode& com
ports += val->get_inner() + ";";
options.tlsPorts = ports;
}
+
+ else if (field->get_tag("var") == "verify_cert" && value
+ && !value->get_inner().empty())
+ {
+ auto val = to_bool(value->get_inner());
+ options.verifyCert = val;
+ }
#endif // BOTAN_FOUND
else if (field->get_tag("var") == "pass" &&