~singpolyma/biboumi

e8386bd14e9783f0bef39bdf577545522e33e719 — Florent Le Coz 8 years ago 06db9b3
Provide an adhoc option to let user pass the cert verif for some IRC servers
M louloulibs/network/credentials_manager.cpp => louloulibs/network/credentials_manager.cpp +30 -5
@@ 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};

M louloulibs/network/credentials_manager.hpp => louloulibs/network/credentials_manager.hpp +8 -3
@@ 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

M louloulibs/network/tcp_socket_handler.cpp => louloulibs/network/tcp_socket_handler.cpp +4 -2
@@ 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());
}


M louloulibs/network/tcp_socket_handler.hpp => louloulibs/network/tcp_socket_handler.hpp +11 -1
@@ 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

M src/irc/irc_client.cpp => src/irc/irc_client.cpp +11 -0
@@ 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

M src/irc/irc_client.hpp => src/irc/irc_client.hpp +3 -0
@@ 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
   */

M src/xmpp/biboumi_adhoc_commands.cpp => src/xmpp/biboumi_adhoc_commands.cpp +20 -0
@@ 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" &&