@@ -15,6 +15,8 @@ Version 5.0
|
||||
messages, instead of the whole archive.
|
||||
- Multiline topics are now properly handled
|
||||
- Configuration options can be overridden by values found in the process env.
|
||||
- Botan’s TLS policies can be customized by the administrator, for each
|
||||
IRC server, with simple text files.
|
||||
|
||||
Version 4.1 - 2017-03-21
|
||||
========================
|
||||
|
||||
@@ -336,6 +336,8 @@ install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin)
|
||||
install(FILES ${MAN_PAGE} DESTINATION share/man/man1 OPTIONAL COMPONENT documentation)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/biboumi.service DESTINATION lib/systemd/system COMPONENT init)
|
||||
install(FILES conf/biboumi.cfg DESTINATION /etc/biboumi COMPONENT configuration)
|
||||
file(GLOB policy_files conf/*policy.txt)
|
||||
install(FILES ${policy_files} DESTINATION /etc/biboumi COMPONENT configuration)
|
||||
|
||||
#
|
||||
## Dist target
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
require_cert_revocation_info = false
|
||||
@@ -0,0 +1 @@
|
||||
minimum_dh_group_size = 1024
|
||||
@@ -0,0 +1,2 @@
|
||||
require_cert_revocation_info = false
|
||||
use_ecc_point_compression = true
|
||||
@@ -163,6 +163,40 @@ identd_port
|
||||
|
||||
The TCP port on which to listen for identd queries. The default is the standard value: 113.
|
||||
|
||||
policy_directory
|
||||
----------------
|
||||
|
||||
A directory that should contain the policy files, used to customize
|
||||
Botan’s behaviour when negociating the TLS connections with the IRC
|
||||
servers. If not specified, the directory is the one where biboumi’s
|
||||
configuration file is located: for example if biboumi reads its
|
||||
configuration from /etc/biboumi/biboumi.cfg, the policy_directory value
|
||||
will be /etc/biboumi.
|
||||
|
||||
|
||||
TLS configuration
|
||||
=================
|
||||
|
||||
Various settings of the TLS connections can be customized using policy
|
||||
files. The files should be located in the directory specified by the
|
||||
configuration option `policy_directory`_. When attempting to connect to
|
||||
an IRC server using TLS, biboumi will use Botan’s default TLS policy, and
|
||||
then will try to load some policy files to override the values found in
|
||||
these files. For example, if policy_directory is /etc/biboumi, when
|
||||
trying to connect to irc.example.com, biboumi will try to read
|
||||
/etc/biboumi/policy.txt, use the values found to override the default
|
||||
values, then it will try to read /etc/biboumi/irc.example.com.policy.txt
|
||||
and re-override the policy with the values found in this file.
|
||||
|
||||
The policy.txt file applies to all the connections, and
|
||||
irc.example.policy.txt will only apply (in addition to policy.txt) when
|
||||
connecting to that specific server.
|
||||
|
||||
To see the list of possible options to configure, refer to `Botan’s TLS
|
||||
documentation <https://botan.randombit.net/manual/tls.html#tls-policies>`_.
|
||||
|
||||
By default, biboumi provides a few policy files, to work around some
|
||||
issues found with a few well-known IRC servers.
|
||||
|
||||
Usage
|
||||
=====
|
||||
@@ -628,3 +662,4 @@ protection against flood or any sort of abuse that your users may cause on
|
||||
the IRC servers. Some XMPP server however offer the possibility to restrict
|
||||
what JID can access a gateway. Use that feature if you wish to grant access
|
||||
to your biboumi instance only to a list of trusted users.
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#ifdef BOTAN_FOUND
|
||||
# include <botan/hex.h>
|
||||
# include <botan/tls_exceptn.h>
|
||||
# include <config/config.hpp>
|
||||
# include <utils/dirname.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -22,11 +24,6 @@ namespace
|
||||
static Botan::AutoSeeded_RNG rng{};
|
||||
return rng;
|
||||
}
|
||||
BiboumiTLSPolicy& get_policy()
|
||||
{
|
||||
static BiboumiTLSPolicy policy{};
|
||||
return policy;
|
||||
}
|
||||
Botan::TLS::Session_Manager_In_Memory& get_session_manager()
|
||||
{
|
||||
static Botan::TLS::Session_Manager_In_Memory session_manager{get_rng()};
|
||||
@@ -233,6 +230,11 @@ void TCPSocketHandler::consume_in_buffer(const std::size_t size)
|
||||
void TCPSocketHandler::start_tls(const std::string& address, const std::string& port)
|
||||
{
|
||||
Botan::TLS::Server_Information server_info(address, "irc", std::stoul(port));
|
||||
auto policy_directory = Config::get("policy_directory", utils::dirname(Config::get_filename()));
|
||||
if (!policy_directory.empty() && policy_directory[policy_directory.size()-1] != '/')
|
||||
policy_directory += '/';
|
||||
this->policy.load(policy_directory + "policy.txt");
|
||||
this->policy.load(policy_directory + address + ".policy.txt");
|
||||
this->tls = std::make_unique<Botan::TLS::Client>(
|
||||
# if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,32)
|
||||
*this,
|
||||
@@ -242,7 +244,7 @@ void TCPSocketHandler::start_tls(const std::string& address, const std::string&
|
||||
[this](Botan::TLS::Alert alert, const Botan::byte*, size_t) { this->tls_alert(alert); },
|
||||
[this](const Botan::TLS::Session& session) { return this->tls_session_established(session); },
|
||||
# endif
|
||||
get_session_manager(), this->credential_manager, get_policy(),
|
||||
get_session_manager(), this->credential_manager, this->policy,
|
||||
get_rng(), server_info, Botan::TLS::Protocol_Version::latest_tls_version());
|
||||
}
|
||||
|
||||
|
||||
@@ -23,21 +23,7 @@
|
||||
# include <botan/types.h>
|
||||
# include <botan/botan.h>
|
||||
# include <botan/tls_session_manager.h>
|
||||
|
||||
class BiboumiTLSPolicy: public Botan::TLS::Policy
|
||||
{
|
||||
public:
|
||||
# if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,33)
|
||||
bool use_ecc_point_compression() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool require_cert_revocation_info() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
# endif
|
||||
};
|
||||
# include <network/tls_policy.hpp>
|
||||
|
||||
# if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,32)
|
||||
# define BOTAN_TLS_CALLBACKS_OVERRIDE override final
|
||||
@@ -230,6 +216,7 @@ protected:
|
||||
protected:
|
||||
BasicCredentialsManager credential_manager;
|
||||
private:
|
||||
BiboumiTLSPolicy policy;
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#include "biboumi.h"
|
||||
|
||||
#ifdef BOTAN_FOUND
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include <utils/tolower.hpp>
|
||||
|
||||
#include <network/tls_policy.hpp>
|
||||
#include <logger/logger.hpp>
|
||||
|
||||
bool BiboumiTLSPolicy::load(const std::string& filename)
|
||||
{
|
||||
std::ifstream is(filename.data());
|
||||
if (is)
|
||||
{
|
||||
try {
|
||||
this->load(is);
|
||||
log_info("Successfully loaded policy file: ", filename);
|
||||
return true;
|
||||
} catch (const Botan::Exception& e) {
|
||||
log_error("Failed to parse policy_file ", filename, ": ", e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
log_info("Could not open policy file: ", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
void BiboumiTLSPolicy::load(std::istream& is)
|
||||
{
|
||||
const auto dict = Botan::read_cfg(is);
|
||||
for (const auto& pair: dict)
|
||||
{
|
||||
// Workaround for options that are not overridden in Botan::TLS::Text_Policy
|
||||
if (pair.first == "require_cert_revocation_info")
|
||||
this->req_cert_revocation_info = !(pair.second == "0" || utils::tolower(pair.second) == "false");
|
||||
else
|
||||
this->set(pair.first, pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
bool BiboumiTLSPolicy::require_cert_revocation_info() const
|
||||
{
|
||||
return this->req_cert_revocation_info;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "biboumi.h"
|
||||
|
||||
#ifdef BOTAN_FOUND
|
||||
|
||||
#include <botan/tls_policy.h>
|
||||
|
||||
class BiboumiTLSPolicy: public Botan::TLS::Text_Policy
|
||||
{
|
||||
public:
|
||||
BiboumiTLSPolicy():
|
||||
Botan::TLS::Text_Policy({})
|
||||
{}
|
||||
bool load(const std::string& filename);
|
||||
void load(std::istream& iss);
|
||||
|
||||
BiboumiTLSPolicy(const BiboumiTLSPolicy &) = delete;
|
||||
BiboumiTLSPolicy(BiboumiTLSPolicy &&) = delete;
|
||||
BiboumiTLSPolicy &operator=(const BiboumiTLSPolicy &) = delete;
|
||||
BiboumiTLSPolicy &operator=(BiboumiTLSPolicy &&) = delete;
|
||||
|
||||
bool require_cert_revocation_info() const override;
|
||||
protected:
|
||||
bool req_cert_revocation_info{true};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
#include <utils/dirname.hpp>
|
||||
|
||||
namespace utils
|
||||
{
|
||||
std::string dirname(const std::string filename)
|
||||
{
|
||||
if (filename.empty())
|
||||
return "./";
|
||||
if (filename == ".." || filename == ".")
|
||||
return filename;
|
||||
auto pos = filename.rfind('/');
|
||||
if (pos == std::string::npos)
|
||||
return "./";
|
||||
return filename.substr(0, pos + 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <string>
|
||||
|
||||
namespace utils
|
||||
{
|
||||
std::string dirname(const std::string filename);
|
||||
}
|
||||
@@ -10,5 +10,3 @@
|
||||
*/
|
||||
std::string xdg_config_path(const std::string& filename);
|
||||
std::string xdg_data_path(const std::string& filename);
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#include "catch.hpp"
|
||||
#include <network/tls_policy.hpp>
|
||||
|
||||
TEST_CASE("tls_policy")
|
||||
{
|
||||
BiboumiTLSPolicy policy;
|
||||
const auto default_minimum_signature_strength = policy.minimum_signature_strength();
|
||||
const auto default_session_ticket_lifetime = policy.session_ticket_lifetime();
|
||||
const auto default_minimum_rsa_bits = policy.minimum_rsa_bits();
|
||||
|
||||
policy.load("does not exist");
|
||||
WHEN("we fail to load the file")
|
||||
{
|
||||
THEN("all values are the default ones")
|
||||
{
|
||||
CHECK(policy.minimum_signature_strength() == default_minimum_signature_strength);
|
||||
CHECK(policy.minimum_rsa_bits() == default_minimum_rsa_bits);
|
||||
}
|
||||
AND_WHEN("we load a valid first file")
|
||||
{
|
||||
std::istringstream iss("minimum_signature_strength = 128\nminimum_rsa_bits=12\n");
|
||||
policy.load(iss);
|
||||
THEN("the specified values are updated, and the rest is still the default")
|
||||
{
|
||||
CHECK(policy.minimum_signature_strength() == 128);
|
||||
CHECK(policy.minimum_rsa_bits() == 12);
|
||||
CHECK(policy.session_ticket_lifetime() == default_session_ticket_lifetime);
|
||||
}
|
||||
AND_WHEN("we load a second file")
|
||||
{
|
||||
std::istringstream iss("minimum_signature_strength = 15");
|
||||
policy.load(iss);
|
||||
THEN("the specified values are updated, and the rest is untouched")
|
||||
{
|
||||
CHECK(policy.minimum_signature_strength() == 15);
|
||||
CHECK(policy.minimum_rsa_bits() == 12);
|
||||
CHECK(policy.session_ticket_lifetime() == default_session_ticket_lifetime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
-1
@@ -10,6 +10,7 @@
|
||||
#include <utils/time.hpp>
|
||||
#include <utils/system.hpp>
|
||||
#include <utils/scopeguard.hpp>
|
||||
#include <utils/dirname.hpp>
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
@@ -157,4 +158,16 @@ TEST_CASE("system_name")
|
||||
{
|
||||
CHECK(utils::get_system_name() != "Unknown");
|
||||
CHECK(!utils::get_system_name().empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("dirname")
|
||||
{
|
||||
CHECK(utils::dirname("/") == "/");
|
||||
CHECK(utils::dirname("coucou.txt") == "./");
|
||||
CHECK(utils::dirname("../coucou.txt") == "../");
|
||||
CHECK(utils::dirname("/etc/biboumi/coucou.txt") == "/etc/biboumi/");
|
||||
CHECK(utils::dirname("..") == "..");
|
||||
CHECK(utils::dirname("../") == "../");
|
||||
CHECK(utils::dirname(".") == ".");
|
||||
CHECK(utils::dirname("./") == "./");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user