~singpolyma/biboumi

1f8333f23f060750673d0b7c573f2e2d12142adf — Florent Le Coz 6 years ago a38b176
Support a trusted SHA1 fingerprint to be configured for each IRC server
M database/database.xml => database/database.xml +1 -0
@@ 13,6 13,7 @@
        <field name="username" type="string" length="1024" default=""/>
        <field name="realname" type="string" length="1024" default=""/>
        <field name="verifyCert" type="boolean" default="true"/>
        <field name="trustedFingerprint" type="string"/>

        <field name="encodingOut" type="string" default="ISO-8859-1"/>
        <field name="encodingIn"  type="string" default="ISO-8859-1"/>

M louloulibs/network/credentials_manager.cpp => louloulibs/network/credentials_manager.cpp +14 -1
@@ 26,11 26,17 @@ 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)
    socket_handler(socket_handler),
    trusted_fingerprint{}
{
  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,
                                                         const std::string& purported_hostname,
                                                         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)
    {
      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())
        throw;
    }

M louloulibs/network/credentials_manager.hpp => louloulibs/network/credentials_manager.hpp +2 -0
@@ 19,6 19,7 @@ public:
                                const std::vector<Botan::X509_Certificate>&) override final;
  std::vector<Botan::Certificate_Store*> trusted_certificate_authorities(const std::string& type,
                                                                         const std::string& context) override final;
  void set_trusted_fingerprint(const std::string& fingerprint);

private:
  const TCPSocketHandler* const socket_handler;


@@ 26,6 27,7 @@ private:
  static void load_certs();
  static Botan::Certificate_Store_In_Memory certificate_store;
  static bool certs_loaded;
  std::string trusted_fingerprint;
};

#endif //BOTAN_FOUND

M louloulibs/network/tcp_socket_handler.hpp => louloulibs/network/tcp_socket_handler.hpp +2 -0
@@ 248,7 248,9 @@ private:
  static Botan::AutoSeeded_RNG rng;
  static Botan::TLS::Policy policy;
  static Botan::TLS::Session_Manager_In_Memory session_manager;
protected:
  Basic_Credentials_Manager credential_manager;
private:
  /**
   * 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 +7 -0
@@ 89,6 89,13 @@ void IrcClient::start()

  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);
}


M src/xmpp/biboumi_adhoc_commands.cpp => src/xmpp/biboumi_adhoc_commands.cpp +21 -1
@@ 175,6 175,19 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com
    verify_cert_value.set_inner("false");
  verify_cert.add_child(std::move(verify_cert_value));
  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

  XmlNode pass("field");


@@ 295,12 308,19 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com
              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())
            {
              auto val = to_bool(value->get_inner());
              options.verifyCert = val;
            }

          else if (field->get_tag("var") == "fingerprint" && value &&
                   !value->get_inner().empty())
            {
              options.trustedFingerprint = value->get_inner();
            }

#endif // BOTAN_FOUND

          else if (field->get_tag("var") == "pass" &&