summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.rst16
-rw-r--r--CMakeLists.txt2
-rw-r--r--louloulibs/cmake/Modules/FindBOTAN.cmake32
-rw-r--r--louloulibs/network/credentials_manager.cpp35
-rw-r--r--louloulibs/network/credentials_manager.hpp16
-rw-r--r--louloulibs/network/tcp_socket_handler.cpp45
-rw-r--r--louloulibs/network/tcp_socket_handler.hpp43
-rw-r--r--packaging/biboumi.spec.cmake10
-rw-r--r--src/irc/irc_client.cpp5
-rw-r--r--src/main.cpp15
10 files changed, 181 insertions, 38 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index a896e68..911dfa3 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -1,3 +1,19 @@
+Version 4.3 - 2017-05-02
+========================
+
+ - Fix a segmentation fault that occured when trying to connect to an IRC
+ server without any port configured.
+
+Version 4.2 - 2017-04-26
+========================
+
+ - Fix a build issue when LiteSQL is absent from the system
+
+Version 4.1 - 2017-03-21
+========================
+
+ - Works with botan 2.x, as well as botan 1.11.x
+
Version 4.0 - 2016-11-09
========================
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2301123..ca5aa97 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.0)
project(biboumi)
set(${PROJECT_NAME}_VERSION_MAJOR 4)
-set(${PROJECT_NAME}_VERSION_MINOR 0)
+set(${PROJECT_NAME}_VERSION_MINOR 3)
set(${PROJECT_NAME}_VERSION_SUFFIX "")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -pedantic -Wall -Wextra")
diff --git a/louloulibs/cmake/Modules/FindBOTAN.cmake b/louloulibs/cmake/Modules/FindBOTAN.cmake
index a12bd35..13d2de4 100644
--- a/louloulibs/cmake/Modules/FindBOTAN.cmake
+++ b/louloulibs/cmake/Modules/FindBOTAN.cmake
@@ -15,21 +15,29 @@
#
# This file is in the public domain
-find_path(BOTAN_INCLUDE_DIRS NAMES botan/botan.h
- PATH_SUFFIXES botan-1.11
- DOC "The botan include directory")
+include(FindPkgConfig)
-find_library(BOTAN_LIBRARIES NAMES botan botan-1.11
- DOC "The botan library")
+pkg_check_modules(BOTAN botan-2)
+pkg_check_modules(BOTAN botan-1.11)
-# Use some standard module to handle the QUIETLY and REQUIRED arguments, and
-# set BOTAN_FOUND to TRUE if these two variables are set.
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(BOTAN REQUIRED_VARS BOTAN_LIBRARIES BOTAN_INCLUDE_DIRS)
+if(NOT BOTAN_FOUND)
+ find_path(BOTAN_INCLUDE_DIRS NAMES botan/botan.h
+ PATH_SUFFIXES botan-2 botan-1.11
+ DOC "The botan include directory")
-if(BOTAN_FOUND)
- set(BOTAN_LIBRARY ${BOTAN_LIBRARIES})
- set(BOTAN_INCLUDE_DIR ${BOTAN_INCLUDE_DIRS})
+ find_library(BOTAN_LIBRARIES NAMES botan botan-2 botan-1.11
+ DOC "The botan library")
+
+ # Use some standard module to handle the QUIETLY and REQUIRED arguments, and
+ # set BOTAN_FOUND to TRUE if these two variables are set.
+ include(FindPackageHandleStandardArgs)
+ find_package_handle_standard_args(BOTAN REQUIRED_VARS BOTAN_LIBRARIES BOTAN_INCLUDE_DIRS)
+
+ if(BOTAN_FOUND)
+ set(BOTAN_LIBRARY ${BOTAN_LIBRARIES} CACHE INTERNAL "")
+ set(BOTAN_INCLUDE_DIR ${BOTAN_INCLUDE_DIRS} CACHE INTERNAL "")
+ set(BOTAN_FOUND ${BOTAN_FOUND} CACHE INTERNAL "")
+ endif()
endif()
mark_as_advanced(BOTAN_INCLUDE_DIRS BOTAN_LIBRARIES)
diff --git a/louloulibs/network/credentials_manager.cpp b/louloulibs/network/credentials_manager.cpp
index ed04d24..289307b 100644
--- a/louloulibs/network/credentials_manager.cpp
+++ b/louloulibs/network/credentials_manager.cpp
@@ -37,6 +37,28 @@ void BasicCredentialsManager::set_trusted_fingerprint(const std::string& fingerp
this->trusted_fingerprint = fingerprint;
}
+const std::string& BasicCredentialsManager::get_trusted_fingerprint() const
+{
+ return this->trusted_fingerprint;
+}
+
+void check_tls_certificate(const std::vector<Botan::X509_Certificate>& certs,
+ const std::string& hostname, const std::string& trusted_fingerprint,
+ std::exception_ptr exc)
+{
+
+ if (!trusted_fingerprint.empty() && !certs.empty() &&
+ trusted_fingerprint == certs[0].fingerprint() &&
+ certs[0].matches_dns_name(hostname))
+ // We trust the certificate, based on the trusted fingerprint and
+ // the fact that the hostname matches
+ return;
+
+ if (exc)
+ std::rethrow_exception(exc);
+}
+
+#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,34)
void BasicCredentialsManager::verify_certificate_chain(const std::string& type,
const std::string& purported_hostname,
const std::vector<Botan::X509_Certificate>& certs)
@@ -50,17 +72,14 @@ void BasicCredentialsManager::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;
-
+ std::exception_ptr exception_ptr{};
if (this->socket_handler->abort_on_invalid_cert())
- throw;
+ exception_ptr = std::current_exception();
+
+ check_tls_certificate(certs, purported_hostname, this->trusted_fingerprint, exception_ptr);
}
}
+#endif
bool BasicCredentialsManager::try_to_open_one_ca_bundle(const std::vector<std::string>& paths)
{
diff --git a/louloulibs/network/credentials_manager.hpp b/louloulibs/network/credentials_manager.hpp
index 7557372..9f42782 100644
--- a/louloulibs/network/credentials_manager.hpp
+++ b/louloulibs/network/credentials_manager.hpp
@@ -6,9 +6,22 @@
#include <botan/botan.h>
#include <botan/tls_client.h>
+#include <botan/version.h>
class TCPSocketHandler;
+/**
+ * If the given cert isn’t valid, based on the given hostname
+ * and fingerprint, then throws the exception if it’s non-empty.
+ *
+ * Must be called after the standard (from Botan) way of
+ * checking the certificate, if we want to also accept certificates based
+ * on a trusted fingerprint.
+ */
+void check_tls_certificate(const std::vector<Botan::X509_Certificate>& certs,
+ const std::string& hostname, const std::string& trusted_fingerprint,
+ std::exception_ptr exc);
+
class BasicCredentialsManager: public Botan::Credentials_Manager
{
public:
@@ -19,12 +32,15 @@ public:
BasicCredentialsManager& operator=(const BasicCredentialsManager&) = delete;
BasicCredentialsManager& operator=(BasicCredentialsManager&&) = delete;
+#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,34)
void verify_certificate_chain(const std::string& type,
const std::string& purported_hostname,
const std::vector<Botan::X509_Certificate>&) override final;
+#endif
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);
+ const std::string& get_trusted_fingerprint() const;
private:
const TCPSocketHandler* const socket_handler;
diff --git a/louloulibs/network/tcp_socket_handler.cpp b/louloulibs/network/tcp_socket_handler.cpp
index 1dddde5..d9ec226 100644
--- a/louloulibs/network/tcp_socket_handler.cpp
+++ b/louloulibs/network/tcp_socket_handler.cpp
@@ -419,10 +419,14 @@ void TCPSocketHandler::start_tls()
{
Botan::TLS::Server_Information server_info(this->address, "irc", std::stoul(this->port));
this->tls = std::make_unique<Botan::TLS::Client>(
- std::bind(&TCPSocketHandler::tls_output_fn, 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_handshake_cb, this, ph::_1),
+# if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,32)
+ *this,
+# else
+ [this](const Botan::byte* data, size_t size) { this->tls_emit_data(data, size); },
+ [this](const Botan::byte* data, size_t size) { this->tls_record_received(0, data, size); },
+ [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
session_manager, this->credential_manager, policy,
rng, server_info, Botan::TLS::Protocol_Version::latest_tls_version());
}
@@ -475,7 +479,7 @@ void TCPSocketHandler::tls_send(std::string&& data)
std::make_move_iterator(data.end()));
}
-void TCPSocketHandler::tls_data_cb(const Botan::byte* data, size_t size)
+void TCPSocketHandler::tls_record_received(uint64_t, const Botan::byte *data, size_t size)
{
this->in_buf += std::string(reinterpret_cast<const char*>(data),
size);
@@ -483,17 +487,17 @@ void TCPSocketHandler::tls_data_cb(const Botan::byte* data, size_t size)
this->parse_in_buffer(size);
}
-void TCPSocketHandler::tls_output_fn(const Botan::byte* data, size_t size)
+void TCPSocketHandler::tls_emit_data(const Botan::byte *data, size_t size)
{
this->raw_send(std::string(reinterpret_cast<const char*>(data), size));
}
-void TCPSocketHandler::tls_alert_cb(Botan::TLS::Alert alert, const Botan::byte*, size_t)
+void TCPSocketHandler::tls_alert(Botan::TLS::Alert alert)
{
log_debug("tls_alert: ", alert.type_string());
}
-bool TCPSocketHandler::tls_handshake_cb(const Botan::TLS::Session& session)
+bool TCPSocketHandler::tls_session_established(const Botan::TLS::Session& session)
{
log_debug("Handshake with ", session.server_info().hostname(), " complete.",
" Version: ", session.version().to_string(),
@@ -505,6 +509,31 @@ bool TCPSocketHandler::tls_handshake_cb(const Botan::TLS::Session& session)
return true;
}
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,34)
+void TCPSocketHandler::tls_verify_cert_chain(const std::vector<Botan::X509_Certificate>& cert_chain,
+ const std::vector<std::shared_ptr<const Botan::OCSP::Response>>& ocsp_responses,
+ const std::vector<Botan::Certificate_Store*>& trusted_roots,
+ Botan::Usage_Type usage, const std::string& hostname,
+ const Botan::TLS::Policy& policy)
+{
+ log_debug("Checking remote certificate for hostname ", hostname);
+ try
+ {
+ Botan::TLS::Callbacks::tls_verify_cert_chain(cert_chain, ocsp_responses, trusted_roots, usage, hostname, policy);
+ log_debug("Certificate is valid");
+ }
+ catch (const std::exception& tls_exception)
+ {
+ log_warning("TLS certificate check failed: ", tls_exception.what());
+ std::exception_ptr exception_ptr{};
+ if (this->abort_on_invalid_cert())
+ exception_ptr = std::current_exception();
+
+ check_tls_certificate(cert_chain, hostname, this->credential_manager.get_trusted_fingerprint(), exception_ptr);
+ }
+}
+#endif
+
void TCPSocketHandler::on_tls_activated()
{
this->send_data({});
diff --git a/louloulibs/network/tcp_socket_handler.hpp b/louloulibs/network/tcp_socket_handler.hpp
index 20a3e5a..c850f43 100644
--- a/louloulibs/network/tcp_socket_handler.hpp
+++ b/louloulibs/network/tcp_socket_handler.hpp
@@ -19,6 +19,27 @@
#include <string>
#include <list>
+#ifdef BOTAN_FOUND
+#include <botan/version.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;
+ }
+# endif
+};
+
+# if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,32)
+# define BOTAN_TLS_CALLBACKS_OVERRIDE override final
+# else
+# define BOTAN_TLS_CALLBACKS_OVERRIDE
+# endif
+#endif
+
/**
* An interface, with a series of callbacks that should be implemented in
* subclasses that deal with a socket. These callbacks are called on various events
@@ -26,6 +47,11 @@
* (select/poll/epoll etc)
*/
class TCPSocketHandler: public SocketHandler
+#ifdef BOTAN_FOUND
+# if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,32)
+ ,public Botan::TLS::Callbacks
+# endif
+#endif
{
protected:
~TCPSocketHandler();
@@ -158,22 +184,31 @@ private:
* Called by the tls object that some data has been decrypt. We call
* parse_in_buffer() to handle that unencrypted data.
*/
- void tls_data_cb(const Botan::byte* data, size_t size);
+ void tls_record_received(uint64_t rec_no, const Botan::byte* data, size_t size) BOTAN_TLS_CALLBACKS_OVERRIDE;
/**
* Called by the tls object to indicate that some data has been encrypted
* and is now ready to be sent on the socket as is.
*/
- void tls_output_fn(const Botan::byte* data, size_t size);
+ void tls_emit_data(const Botan::byte* data, size_t size) BOTAN_TLS_CALLBACKS_OVERRIDE;
/**
* Called by the tls object to indicate that a TLS alert has been
* received. We don’t use it, we just log some message, at the moment.
*/
- void tls_alert_cb(Botan::TLS::Alert alert, const Botan::byte*, size_t);
+ void tls_alert(Botan::TLS::Alert alert) BOTAN_TLS_CALLBACKS_OVERRIDE;
/**
* Called by the tls object at the end of the TLS handshake. We don't do
* anything here appart from logging the TLS session information.
*/
- bool tls_handshake_cb(const Botan::TLS::Session& session);
+ bool tls_session_established(const Botan::TLS::Session& session) BOTAN_TLS_CALLBACKS_OVERRIDE;
+
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,34)
+ void tls_verify_cert_chain(const std::vector<Botan::X509_Certificate>& cert_chain,
+ const std::vector<std::shared_ptr<const Botan::OCSP::Response>>& ocsp_responses,
+ const std::vector<Botan::Certificate_Store*>& trusted_roots,
+ Botan::Usage_Type usage,
+ const std::string& hostname,
+ const Botan::TLS::Policy& policy) BOTAN_TLS_CALLBACKS_OVERRIDE;
+#endif
/**
* Called whenever the tls session goes from inactive to active. This
* means that the handshake has just been successfully done, and we can
diff --git a/packaging/biboumi.spec.cmake b/packaging/biboumi.spec.cmake
index 0747d34..e4a1d3b 100644
--- a/packaging/biboumi.spec.cmake
+++ b/packaging/biboumi.spec.cmake
@@ -59,6 +59,16 @@ make check %{?_smp_mflags}
%changelog
+* Wed May 2 2017 Le Coz Florent <louiz@louiz.org> - 4.3-1
+- Fix a segmentation fault that occured when trying to connect
+ to an IRC server without any port configured.
+
+* Wed Apr 26 2017 Le Coz Florent <louiz@louiz.org> - 4.2-1
+- Fix a build issue when LiteSQL is absent from the system
+
+* Tue Mar 21 2017 Le Coz Florent <louiz@louiz.org> - 4.1-1
+- Update to 4.1 sources: compatibility with botan 2.0
+
* Wed Nov 9 2016 Le Coz Florent <louiz@louiz.org> - 4.0-1
- Update to 4.0 sources
diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp
index b0d3a47..de6b089 100644
--- a/src/irc/irc_client.cpp
+++ b/src/irc/irc_client.cpp
@@ -182,6 +182,11 @@ void IrcClient::start()
{
if (this->is_connecting() || this->is_connected())
return;
+ if (this->ports_to_try.empty())
+ {
+ this->bridge.send_xmpp_message(this->hostname, "", "Can not connect to IRC server: no port specified.");
+ return;
+ }
std::string port;
bool tls;
std::tie(port, tls) = this->ports_to_try.top();
diff --git a/src/main.cpp b/src/main.cpp
index 019dff0..488032d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -12,7 +12,9 @@
#include <atomic>
#include <signal.h>
-#include <litesql.hpp>
+#ifdef USE_DATABASE
+# include <litesql.hpp>
+#endif
// A flag set by the SIGINT signal handler.
static std::atomic<bool> stop(false);
@@ -83,11 +85,14 @@ int main(int ac, char** av)
if (hostname.empty())
return config_help("hostname");
+
+#ifdef USE_DATABASE
try {
- open_database();
- } catch (const litesql::DatabaseError&) {
- return 1;
- }
+ open_database();
+ } catch (const litesql::DatabaseError&) {
+ return 1;
+ }
+#endif
// Block the signals we want to manage. They will be unblocked only during
// the epoll_pwait or ppoll calls. This avoids some race conditions,