Provide an adhoc option to let user pass the cert verif for some IRC servers
This commit is contained in:
@@ -1,25 +1,48 @@
|
|||||||
#include "louloulibs.h"
|
#include "louloulibs.h"
|
||||||
|
|
||||||
#ifdef BOTAN_FOUND
|
#ifdef BOTAN_FOUND
|
||||||
|
#include <network/tcp_socket_handler.hpp>
|
||||||
#include <network/credentials_manager.hpp>
|
#include <network/credentials_manager.hpp>
|
||||||
#include <logger/logger.hpp>
|
#include <logger/logger.hpp>
|
||||||
#include <botan/tls_exceptn.h>
|
#include <botan/tls_exceptn.h>
|
||||||
|
|
||||||
Basic_Credentials_Manager::Basic_Credentials_Manager():
|
#ifdef USE_DATABASE
|
||||||
Botan::Credentials_Manager()
|
# 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();
|
this->load_certs();
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
log_debug("Checking remote certificate (" << type << ") for hostname " << purported_hostname);
|
log_debug("Checking remote certificate (" << type << ") for hostname " << purported_hostname);
|
||||||
|
try
|
||||||
|
{
|
||||||
Botan::Credentials_Manager::verify_certificate_chain(type, purported_hostname, certs);
|
Botan::Credentials_Manager::verify_certificate_chain(type, purported_hostname, certs);
|
||||||
log_debug("Certificate is valid");
|
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()
|
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"};
|
const std::vector<std::string> paths = {"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem"};
|
||||||
for (const auto& path: paths)
|
for (const auto& path: paths)
|
||||||
{
|
{
|
||||||
@@ -27,10 +50,12 @@ void Basic_Credentials_Manager::load_certs()
|
|||||||
while (!bundle.end_of_data() && bundle.check_available(27))
|
while (!bundle.end_of_data() && bundle.check_available(27))
|
||||||
{
|
{
|
||||||
const Botan::X509_Certificate cert(bundle);
|
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&)
|
std::vector<Botan::Certificate_Store*> Basic_Credentials_Manager::trusted_certificate_authorities(const std::string&, const std::string&)
|
||||||
{
|
{
|
||||||
return {&this->certificate_store};
|
return {&this->certificate_store};
|
||||||
|
|||||||
@@ -8,10 +8,12 @@
|
|||||||
#include <botan/botan.h>
|
#include <botan/botan.h>
|
||||||
#include <botan/tls_client.h>
|
#include <botan/tls_client.h>
|
||||||
|
|
||||||
|
class TCPSocketHandler;
|
||||||
|
|
||||||
class Basic_Credentials_Manager: public Botan::Credentials_Manager
|
class Basic_Credentials_Manager: public Botan::Credentials_Manager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Basic_Credentials_Manager();
|
Basic_Credentials_Manager(const TCPSocketHandler* const socket_handler);
|
||||||
void verify_certificate_chain(const std::string& type,
|
void verify_certificate_chain(const std::string& type,
|
||||||
const std::string& purported_hostname,
|
const std::string& purported_hostname,
|
||||||
const std::vector<Botan::X509_Certificate>&) override final;
|
const std::vector<Botan::X509_Certificate>&) override final;
|
||||||
@@ -19,8 +21,11 @@ public:
|
|||||||
const std::string& context) override final;
|
const std::string& context) override final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void load_certs();
|
const TCPSocketHandler* const socket_handler;
|
||||||
Botan::Certificate_Store_In_Memory certificate_store;
|
|
||||||
|
static void load_certs();
|
||||||
|
static Botan::Certificate_Store_In_Memory certificate_store;
|
||||||
|
static bool certs_loaded;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //BOTAN_FOUND
|
#endif //BOTAN_FOUND
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
# include <botan/tls_exceptn.h>
|
# include <botan/tls_exceptn.h>
|
||||||
|
|
||||||
Botan::AutoSeeded_RNG TCPSocketHandler::rng;
|
Botan::AutoSeeded_RNG TCPSocketHandler::rng;
|
||||||
Basic_Credentials_Manager TCPSocketHandler::credential_manager;
|
|
||||||
Botan::TLS::Policy TCPSocketHandler::policy;
|
Botan::TLS::Policy TCPSocketHandler::policy;
|
||||||
Botan::TLS::Session_Manager_In_Memory TCPSocketHandler::session_manager(TCPSocketHandler::rng);
|
Botan::TLS::Session_Manager_In_Memory TCPSocketHandler::session_manager(TCPSocketHandler::rng);
|
||||||
|
|
||||||
@@ -40,6 +39,9 @@ TCPSocketHandler::TCPSocketHandler(std::shared_ptr<Poller> poller):
|
|||||||
connected(false),
|
connected(false),
|
||||||
connecting(false),
|
connecting(false),
|
||||||
hostname_resolution_failed(false)
|
hostname_resolution_failed(false)
|
||||||
|
#ifdef BOTAN_FOUND
|
||||||
|
,credential_manager(this)
|
||||||
|
#endif
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void TCPSocketHandler::init_socket(const struct addrinfo* rp)
|
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_data_cb, this, ph::_1, ph::_2),
|
||||||
std::bind(&TCPSocketHandler::tls_alert_cb, this, ph::_1, ph::_2, ph::_3),
|
std::bind(&TCPSocketHandler::tls_alert_cb, this, ph::_1, ph::_2, ph::_3),
|
||||||
std::bind(&TCPSocketHandler::tls_handshake_cb, this, ph::_1),
|
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());
|
rng, server_info, Botan::TLS::Protocol_Version::latest_tls_version());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,16 @@ public:
|
|||||||
* The size argument is the size of the last chunk of data that was added to the buffer.
|
* 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;
|
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_connected() const override final;
|
||||||
bool is_connecting() const;
|
bool is_connecting() const;
|
||||||
|
|
||||||
@@ -230,9 +240,9 @@ private:
|
|||||||
* Botan stuff to manipulate a TLS session.
|
* Botan stuff to manipulate a TLS session.
|
||||||
*/
|
*/
|
||||||
static Botan::AutoSeeded_RNG rng;
|
static Botan::AutoSeeded_RNG rng;
|
||||||
static Basic_Credentials_Manager credential_manager;
|
|
||||||
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;
|
||||||
|
Basic_Credentials_Manager credential_manager;
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
|
|||||||
@@ -962,3 +962,14 @@ void IrcClient::leave_dummy_channel(const std::string& exit_message)
|
|||||||
this->dummy_channel.remove_all_users();
|
this->dummy_channel.remove_all_users();
|
||||||
this->bridge->send_muc_leave(Iid("%"s + this->hostname), std::string(this->current_nick), exit_message, true);
|
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
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ public:
|
|||||||
* complete messages from it.
|
* complete messages from it.
|
||||||
*/
|
*/
|
||||||
void parse_in_buffer(const size_t) override final;
|
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
|
* Return the channel with this name, create it if it does not yet exist
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -162,6 +162,19 @@ void ConfigureIrcServerStep1(XmppComponent*, AdhocSession& session, XmlNode& com
|
|||||||
}
|
}
|
||||||
tls_ports.add_child(required);
|
tls_ports.add_child(required);
|
||||||
x.add_child(std::move(tls_ports));
|
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
|
#endif
|
||||||
|
|
||||||
XmlNode pass("field");
|
XmlNode pass("field");
|
||||||
@@ -252,6 +265,13 @@ void ConfigureIrcServerStep2(XmppComponent*, AdhocSession& session, XmlNode& com
|
|||||||
ports += val->get_inner() + ";";
|
ports += val->get_inner() + ";";
|
||||||
options.tlsPorts = ports;
|
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
|
#endif // BOTAN_FOUND
|
||||||
|
|
||||||
else if (field->get_tag("var") == "pass" &&
|
else if (field->get_tag("var") == "pass" &&
|
||||||
|
|||||||
Reference in New Issue
Block a user