aboutsummaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.h18
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.inl44
-rw-r--r--contrib/epee/include/net/connection_basic.hpp54
-rw-r--r--contrib/epee/include/net/http_client.h25
-rw-r--r--contrib/epee/include/net/http_server_impl_base.h8
-rw-r--r--contrib/epee/include/net/net_helper.h50
-rw-r--r--contrib/epee/include/net/net_ssl.h99
-rw-r--r--contrib/epee/include/net/network_throttle-detail.hpp3
-rw-r--r--contrib/epee/include/net/network_throttle.hpp3
-rw-r--r--contrib/epee/include/span.h1
-rw-r--r--contrib/epee/include/storages/parserse_base_utils.h7
-rw-r--r--contrib/epee/include/storages/portable_storage_base.h1
-rw-r--r--contrib/epee/include/storages/portable_storage_val_converters.h2
-rw-r--r--contrib/epee/include/string_tools.h4
-rw-r--r--contrib/epee/src/connection_basic.cpp47
-rw-r--r--contrib/epee/src/net_ssl.cpp270
-rw-r--r--contrib/epee/src/network_throttle-detail.cpp10
17 files changed, 409 insertions, 237 deletions
diff --git a/contrib/epee/include/net/abstract_tcp_server2.h b/contrib/epee/include/net/abstract_tcp_server2.h
index ec08c0f4b..d0eabbba5 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.h
+++ b/contrib/epee/include/net/abstract_tcp_server2.h
@@ -90,10 +90,10 @@ namespace net_utils
public:
typedef typename t_protocol_handler::connection_context t_connection_context;
- struct shared_state : socket_stats
+ struct shared_state : connection_basic_shared_state
{
shared_state()
- : socket_stats(), pfilter(nullptr), config()
+ : connection_basic_shared_state(), pfilter(nullptr), config()
{}
i_connection_filter* pfilter;
@@ -104,14 +104,12 @@ namespace net_utils
explicit connection( boost::asio::io_service& io_service,
boost::shared_ptr<shared_state> state,
t_connection_type connection_type,
- epee::net_utils::ssl_support_t ssl_support,
- ssl_context_t &ssl_context);
+ epee::net_utils::ssl_support_t ssl_support);
explicit connection( boost::asio::ip::tcp::socket&& sock,
boost::shared_ptr<shared_state> state,
t_connection_type connection_type,
- epee::net_utils::ssl_support_t ssl_support,
- ssl_context_t &ssl_context);
+ epee::net_utils::ssl_support_t ssl_support);
@@ -228,8 +226,8 @@ namespace net_utils
std::map<std::string, t_connection_type> server_type_map;
void create_server_type_map();
- bool init_server(uint32_t port, const std::string address = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = std::make_pair(std::string(), std::string()), const std::list<std::string> &allowed_certificates = {}, const std::vector<std::vector<uint8_t>> &allowed_fingerprints = {}, bool allow_any_cert = false);
- bool init_server(const std::string port, const std::string& address = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = std::make_pair(std::string(), std::string()), const std::list<std::string> &allowed_certificates = {}, const std::vector<std::vector<uint8_t>> &allowed_fingerprints = {}, bool allow_any_cert = false);
+ bool init_server(uint32_t port, const std::string address = "0.0.0.0", ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect);
+ bool init_server(const std::string port, const std::string& address = "0.0.0.0", ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect);
/// Run the server's io_service loop.
bool run_server(size_t threads_count, bool wait = true, const boost::thread::attributes& attrs = boost::thread::attributes());
@@ -380,10 +378,6 @@ namespace net_utils
boost::mutex connections_mutex;
std::set<connection_ptr> connections_;
-
- ssl_context_t m_ssl_context;
- std::list<std::string> m_allowed_certificates;
-
}; // class <>boosted_tcp_server
diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl
index 67c63cca5..58f899a73 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.inl
+++ b/contrib/epee/include/net/abstract_tcp_server2.inl
@@ -80,10 +80,9 @@ PRAGMA_WARNING_DISABLE_VS(4355)
connection<t_protocol_handler>::connection( boost::asio::io_service& io_service,
boost::shared_ptr<shared_state> state,
t_connection_type connection_type,
- epee::net_utils::ssl_support_t ssl_support,
- ssl_context_t &ssl_context
+ ssl_support_t ssl_support
)
- : connection(boost::asio::ip::tcp::socket{io_service}, std::move(state), connection_type, ssl_support, ssl_context)
+ : connection(boost::asio::ip::tcp::socket{io_service}, std::move(state), connection_type, ssl_support)
{
}
@@ -91,11 +90,10 @@ PRAGMA_WARNING_DISABLE_VS(4355)
connection<t_protocol_handler>::connection( boost::asio::ip::tcp::socket&& sock,
boost::shared_ptr<shared_state> state,
t_connection_type connection_type,
- epee::net_utils::ssl_support_t ssl_support,
- ssl_context_t &ssl_context
+ ssl_support_t ssl_support
)
:
- connection_basic(std::move(sock), state, ssl_support, ssl_context),
+ connection_basic(std::move(sock), state, ssl_support),
m_protocol_handler(this, check_and_get(state).config, context),
m_connection_type( connection_type ),
m_throttle_speed_in("speed_in", "throttle_speed_in"),
@@ -176,9 +174,9 @@ PRAGMA_WARNING_DISABLE_VS(4355)
_dbg3("[sock " << socket_.native_handle() << "] new connection from " << print_connection_context_short(context) <<
" to " << local_ep.address().to_string() << ':' << local_ep.port() <<
- ", total sockets objects " << get_stats().sock_count);
+ ", total sockets objects " << get_state().sock_count);
- if(static_cast<shared_state&>(get_stats()).pfilter && !static_cast<shared_state&>(get_stats()).pfilter->is_remote_host_allowed(context.m_remote_address))
+ if(static_cast<shared_state&>(get_state()).pfilter && !static_cast<shared_state&>(get_state()).pfilter->is_remote_host_allowed(context.m_remote_address))
{
_dbg2("[sock " << socket().native_handle() << "] host denied " << context.m_remote_address.host_str() << ", shutdowning connection");
close();
@@ -901,8 +899,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
m_threads_count(0),
m_thread_index(0),
m_connection_type( connection_type ),
- new_connection_(),
- m_ssl_context({boost::asio::ssl::context(boost::asio::ssl::context::tlsv12), {}})
+ new_connection_()
{
create_server_type_map();
m_thread_name_prefix = "NET";
@@ -918,8 +915,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
m_threads_count(0),
m_thread_index(0),
m_connection_type(connection_type),
- new_connection_(),
- m_ssl_context({boost::asio::ssl::context(boost::asio::ssl::context::sslv23), {}})
+ new_connection_()
{
create_server_type_map();
m_thread_name_prefix = "NET";
@@ -941,14 +937,14 @@ PRAGMA_WARNING_DISABLE_VS(4355)
}
//---------------------------------------------------------------------------------
template<class t_protocol_handler>
- bool boosted_tcp_server<t_protocol_handler>::init_server(uint32_t port, const std::string address, epee::net_utils::ssl_support_t ssl_support, const std::pair<std::string, std::string> &private_key_and_certificate_path, const std::list<std::string> &allowed_certificates, const std::vector<std::vector<uint8_t>> &allowed_fingerprints, bool allow_any_cert)
+ bool boosted_tcp_server<t_protocol_handler>::init_server(uint32_t port, const std::string address, ssl_options_t ssl_options)
{
TRY_ENTRY();
m_stop_signal_sent = false;
m_port = port;
m_address = address;
- if (ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled)
- m_ssl_context = create_ssl_context(private_key_and_certificate_path, allowed_certificates, allowed_fingerprints, allow_any_cert);
+ if (ssl_options)
+ m_state->configure_ssl(std::move(ssl_options));
// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
boost::asio::ip::tcp::resolver resolver(io_service_);
boost::asio::ip::tcp::resolver::query query(address, boost::lexical_cast<std::string>(port), boost::asio::ip::tcp::resolver::query::canonical_name);
@@ -960,7 +956,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_.local_endpoint();
m_port = binded_endpoint.port();
MDEBUG("start accept");
- new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support, m_ssl_context));
+ new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, m_state->ssl_options().support));
acceptor_.async_accept(new_connection_->socket(),
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
boost::asio::placeholders::error));
@@ -982,7 +978,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
PUSH_WARNINGS
DISABLE_GCC_WARNING(maybe-uninitialized)
template<class t_protocol_handler>
- bool boosted_tcp_server<t_protocol_handler>::init_server(const std::string port, const std::string& address, epee::net_utils::ssl_support_t ssl_support, const std::pair<std::string, std::string> &private_key_and_certificate_path, const std::list<std::string> &allowed_certificates, const std::vector<std::vector<uint8_t>> &allowed_fingerprints, bool allow_any_cert)
+ bool boosted_tcp_server<t_protocol_handler>::init_server(const std::string port, const std::string& address, ssl_options_t ssl_options)
{
uint32_t p = 0;
@@ -990,7 +986,7 @@ DISABLE_GCC_WARNING(maybe-uninitialized)
MERROR("Failed to convert port no = " << port);
return false;
}
- return this->init_server(p, address, ssl_support, private_key_and_certificate_path, allowed_certificates, allowed_fingerprints, allow_any_cert);
+ return this->init_server(p, address, std::move(ssl_options));
}
POP_WARNINGS
//---------------------------------------------------------------------------------
@@ -1165,7 +1161,7 @@ POP_WARNINGS
new_connection_->setRpcStation(); // hopefully this is not needed actually
}
connection_ptr conn(std::move(new_connection_));
- new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, conn->get_ssl_support(), m_ssl_context));
+ new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, conn->get_ssl_support()));
acceptor_.async_accept(new_connection_->socket(),
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
boost::asio::placeholders::error));
@@ -1200,7 +1196,7 @@ POP_WARNINGS
assert(m_state != nullptr); // always set in constructor
_erro("Some problems at accept: " << e.message() << ", connections_count = " << m_state->sock_count);
misc_utils::sleep_no_w(100);
- new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, new_connection_->get_ssl_support(), m_ssl_context));
+ new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, new_connection_->get_ssl_support()));
acceptor_.async_accept(new_connection_->socket(),
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
boost::asio::placeholders::error));
@@ -1211,7 +1207,7 @@ POP_WARNINGS
{
if(std::addressof(get_io_service()) == std::addressof(GET_IO_SERVICE(sock)))
{
- connection_ptr conn(new connection<t_protocol_handler>(std::move(sock), m_state, m_connection_type, ssl_support, m_ssl_context));
+ connection_ptr conn(new connection<t_protocol_handler>(std::move(sock), m_state, m_connection_type, ssl_support));
if(conn->start(false, 1 < m_threads_count, std::move(real_remote)))
{
conn->get_context(out);
@@ -1298,7 +1294,7 @@ POP_WARNINGS
_dbg3("Connected success to " << adr << ':' << port);
- const epee::net_utils::ssl_support_t ssl_support = new_connection_l->get_ssl_support();
+ const ssl_support_t ssl_support = new_connection_l->get_ssl_support();
if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
{
// Handshake
@@ -1329,7 +1325,7 @@ POP_WARNINGS
{
TRY_ENTRY();
- connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support, m_ssl_context) );
+ connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support) );
connections_mutex.lock();
connections_.insert(new_connection_l);
MDEBUG("connections_ size now " << connections_.size());
@@ -1393,7 +1389,7 @@ POP_WARNINGS
bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeout, const t_callback &cb, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support)
{
TRY_ENTRY();
- connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support, m_ssl_context) );
+ connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support) );
connections_mutex.lock();
connections_.insert(new_connection_l);
MDEBUG("connections_ size now " << connections_.size());
diff --git a/contrib/epee/include/net/connection_basic.hpp b/contrib/epee/include/net/connection_basic.hpp
index feedc6895..d3f5f4f24 100644
--- a/contrib/epee/include/net/connection_basic.hpp
+++ b/contrib/epee/include/net/connection_basic.hpp
@@ -57,15 +57,30 @@ namespace epee
{
namespace net_utils
{
- struct socket_stats
- {
- socket_stats()
- : sock_count(0), sock_number(0)
- {}
-
- std::atomic<long> sock_count;
- std::atomic<long> sock_number;
- };
+
+ class connection_basic_shared_state
+ {
+ ssl_options_t ssl_options_;
+ public:
+ boost::asio::ssl::context ssl_context;
+ std::atomic<long> sock_count;
+ std::atomic<long> sock_number;
+
+ connection_basic_shared_state()
+ : ssl_options_(ssl_support_t::e_ssl_support_disabled),
+ ssl_context(boost::asio::ssl::context::tlsv12),
+ sock_count(0),
+ sock_number(0)
+ {}
+
+ void configure_ssl(ssl_options_t src)
+ {
+ ssl_options_ = std::move(src);
+ ssl_context = ssl_options_.create_context();
+ }
+
+ const ssl_options_t& ssl_options() const noexcept { return ssl_options_; }
+ };
/************************************************************************/
/* */
@@ -83,9 +98,10 @@ class connection_basic_pimpl; // PIMPL for this class
std::string to_string(t_connection_type type);
class connection_basic { // not-templated base class for rapid developmet of some code parts
- // beware of removing const, net_utils::connection is sketchily doing a cast to prevent storing ptr twice
- const boost::shared_ptr<socket_stats> m_stats;
+ // beware of removing const, net_utils::connection is sketchily doing a cast to prevent storing ptr twice
+ const boost::shared_ptr<connection_basic_shared_state> m_state;
public:
+
std::unique_ptr< connection_basic_pimpl > mI; // my Implementation
// moved here from orginal connecton<> - common member variables that do not depend on template in connection<>
@@ -97,20 +113,19 @@ class connection_basic { // not-templated base class for rapid developmet of som
/// Strand to ensure the connection's handlers are not called concurrently.
boost::asio::io_service::strand strand_;
/// Socket for the connection.
- ssl_context_t &m_ssl_context;
- ssl_support_t m_ssl_support;
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
+ ssl_support_t m_ssl_support;
public:
// first counter is the ++/-- count of current sockets, the other socket_number is only-increasing ++ number generator
- connection_basic(boost::asio::ip::tcp::socket&& socket, boost::shared_ptr<socket_stats> stats, ssl_support_t ssl_support, ssl_context_t &ssl_context);
- connection_basic(boost::asio::io_service &io_service, boost::shared_ptr<socket_stats> stats, ssl_support_t ssl_support, ssl_context_t &ssl_context);
+ connection_basic(boost::asio::ip::tcp::socket&& socket, boost::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support);
+ connection_basic(boost::asio::io_service &io_service, boost::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support);
virtual ~connection_basic() noexcept(false);
- //! \return `socket_stats` object passed in construction (ptr never changes).
- socket_stats& get_stats() noexcept { return *m_stats; /* verified in constructor */ }
- connection_basic(boost::asio::io_service& io_service, std::atomic<long> &ref_sock_count, std::atomic<long> &sock_number, ssl_support_t ssl, ssl_context_t &ssl_context);
+ //! \return `shared_state` object passed in construction (ptr never changes).
+ connection_basic_shared_state& get_state() noexcept { return *m_state; /* verified in constructor */ }
+ connection_basic(boost::asio::io_service& io_service, std::atomic<long> &ref_sock_count, std::atomic<long> &sock_number, ssl_support_t ssl);
boost::asio::ip::tcp::socket& socket() { return socket_.next_layer(); }
ssl_support_t get_ssl_support() const { return m_ssl_support; }
@@ -118,7 +133,8 @@ class connection_basic { // not-templated base class for rapid developmet of som
bool handshake(boost::asio::ssl::stream_base::handshake_type type)
{
- return ssl_handshake(socket_, type, m_ssl_context);
+ //m_state != nullptr verified in constructor
+ return m_state->ssl_options().handshake(socket_, type);
}
template<typename MutableBufferSequence, typename ReadHandler>
diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h
index f0425278d..a18a1d30a 100644
--- a/contrib/epee/include/net/http_client.h
+++ b/contrib/epee/include/net/http_client.h
@@ -275,11 +275,6 @@ namespace net_utils
chunked_state m_chunked_state;
std::string m_chunked_cache;
critical_section m_lock;
- epee::net_utils::ssl_support_t m_ssl_support;
- std::pair<std::string, std::string> m_ssl_private_key_and_certificate_path;
- std::list<std::string> m_ssl_allowed_certificates;
- std::vector<std::vector<uint8_t>> m_ssl_allowed_fingerprints;
- bool m_ssl_allow_any_cert;
public:
explicit http_simple_client_template()
@@ -297,34 +292,28 @@ namespace net_utils
, m_chunked_state()
, m_chunked_cache()
, m_lock()
- , m_ssl_support(epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
{}
const std::string &get_host() const { return m_host_buff; };
const std::string &get_port() const { return m_port; };
- bool set_server(const std::string& address, boost::optional<login> user, epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = {}, const std::list<std::string> &allowed_ssl_certificates = {}, const std::vector<std::vector<uint8_t>> &allowed_ssl_fingerprints = {}, bool allow_any_cert = false)
+ bool set_server(const std::string& address, boost::optional<login> user, ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect)
{
http::url_content parsed{};
const bool r = parse_url(address, parsed);
CHECK_AND_ASSERT_MES(r, false, "failed to parse url: " << address);
- set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user), ssl_support, private_key_and_certificate_path, allowed_ssl_certificates, allowed_ssl_fingerprints, allow_any_cert);
+ set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user), std::move(ssl_options));
return true;
}
- void set_server(std::string host, std::string port, boost::optional<login> user, epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = {}, const std::list<std::string> &allowed_ssl_certificates = {}, const std::vector<std::vector<uint8_t>> &allowed_ssl_fingerprints = {}, bool allow_any_cert = false)
+ void set_server(std::string host, std::string port, boost::optional<login> user, ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect)
{
CRITICAL_REGION_LOCAL(m_lock);
disconnect();
m_host_buff = std::move(host);
m_port = std::move(port);
m_auth = user ? http_client_auth{std::move(*user)} : http_client_auth{};
- m_ssl_support = ssl_support;
- m_ssl_private_key_and_certificate_path = private_key_and_certificate_path;
- m_ssl_allowed_certificates = allowed_ssl_certificates;
- m_ssl_allowed_fingerprints = allowed_ssl_fingerprints;
- m_ssl_allow_any_cert = allow_any_cert;
- m_net_client.set_ssl(m_ssl_support, m_ssl_private_key_and_certificate_path, m_ssl_allowed_certificates, m_ssl_allowed_fingerprints, m_ssl_allow_any_cert);
+ m_net_client.set_ssl(std::move(ssl_options));
}
template<typename F>
@@ -841,21 +830,21 @@ namespace net_utils
const char *ptr = m_header_cache.c_str();
CHECK_AND_ASSERT_MES(!memcmp(ptr, "HTTP/", 5), false, "Invalid first response line: " + m_header_cache);
ptr += 5;
- CHECK_AND_ASSERT_MES(isdigit(*ptr), false, "Invalid first response line: " + m_header_cache);
+ CHECK_AND_ASSERT_MES(epee::misc_utils::parse::isdigit(*ptr), false, "Invalid first response line: " + m_header_cache);
unsigned long ul;
char *end;
ul = strtoul(ptr, &end, 10);
CHECK_AND_ASSERT_MES(ul <= INT_MAX && *end =='.', false, "Invalid first response line: " + m_header_cache);
m_response_info.m_http_ver_hi = ul;
ptr = end + 1;
- CHECK_AND_ASSERT_MES(isdigit(*ptr), false, "Invalid first response line: " + m_header_cache + ", ptr: " << ptr);
+ CHECK_AND_ASSERT_MES(epee::misc_utils::parse::isdigit(*ptr), false, "Invalid first response line: " + m_header_cache + ", ptr: " << ptr);
ul = strtoul(ptr, &end, 10);
CHECK_AND_ASSERT_MES(ul <= INT_MAX && isblank(*end), false, "Invalid first response line: " + m_header_cache + ", ptr: " << ptr);
m_response_info.m_http_ver_lo = ul;
ptr = end + 1;
while (isblank(*ptr))
++ptr;
- CHECK_AND_ASSERT_MES(isdigit(*ptr), false, "Invalid first response line: " + m_header_cache);
+ CHECK_AND_ASSERT_MES(epee::misc_utils::parse::isdigit(*ptr), false, "Invalid first response line: " + m_header_cache);
ul = strtoul(ptr, &end, 10);
CHECK_AND_ASSERT_MES(ul >= 100 && ul <= 999 && isspace(*end), false, "Invalid first response line: " + m_header_cache);
m_response_info.m_response_code = ul;
diff --git a/contrib/epee/include/net/http_server_impl_base.h b/contrib/epee/include/net/http_server_impl_base.h
index 0922f21f2..fc2dcbf67 100644
--- a/contrib/epee/include/net/http_server_impl_base.h
+++ b/contrib/epee/include/net/http_server_impl_base.h
@@ -59,11 +59,7 @@ namespace epee
bool init(std::function<void(size_t, uint8_t*)> rng, const std::string& bind_port = "0", const std::string& bind_ip = "0.0.0.0",
std::vector<std::string> access_control_origins = std::vector<std::string>(),
boost::optional<net_utils::http::login> user = boost::none,
- epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect,
- const std::pair<std::string, std::string> &private_key_and_certificate_path = {},
- std::list<std::string> allowed_certificates = {},
- std::vector<std::vector<uint8_t>> allowed_fingerprints = {},
- bool allow_any_cert = false)
+ net_utils::ssl_options_t ssl_options = net_utils::ssl_support_t::e_ssl_support_autodetect)
{
//set self as callback handler
@@ -80,7 +76,7 @@ namespace epee
m_net_server.get_config_object().m_user = std::move(user);
MGINFO("Binding on " << bind_ip << ":" << bind_port);
- bool res = m_net_server.init_server(bind_port, bind_ip, ssl_support, private_key_and_certificate_path, std::move(allowed_certificates), std::move(allowed_fingerprints), allow_any_cert);
+ bool res = m_net_server.init_server(bind_port, bind_ip, std::move(ssl_options));
if(!res)
{
LOG_ERROR("Failed to bind server");
diff --git a/contrib/epee/include/net/net_helper.h b/contrib/epee/include/net/net_helper.h
index aa3df7160..66a307c97 100644
--- a/contrib/epee/include/net/net_helper.h
+++ b/contrib/epee/include/net/net_helper.h
@@ -101,10 +101,10 @@ namespace net_utils
inline
blocked_mode_client() :
m_io_service(),
- m_ctx({boost::asio::ssl::context(boost::asio::ssl::context::tlsv12), {}}),
+ m_ctx(boost::asio::ssl::context::tlsv12),
m_connector(direct_connect{}),
- m_ssl_socket(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_service, m_ctx.context)),
- m_ssl_support(epee::net_utils::ssl_support_t::e_ssl_support_autodetect),
+ m_ssl_socket(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_service, m_ctx)),
+ m_ssl_options(epee::net_utils::ssl_support_t::e_ssl_support_autodetect),
m_initialized(true),
m_connected(false),
m_deadline(m_io_service),
@@ -136,13 +136,13 @@ namespace net_utils
catch(...) { /* ignore */ }
}
- inline void set_ssl(epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = {}, std::list<std::string> allowed_certificates = {}, std::vector<std::vector<uint8_t>> allowed_fingerprints = {}, bool allow_any_cert = false)
+ inline void set_ssl(ssl_options_t ssl_options)
{
- if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_disabled)
- m_ctx = {boost::asio::ssl::context(boost::asio::ssl::context::tlsv12), {}, {}};
+ if (ssl_options)
+ m_ctx = ssl_options.create_context();
else
- m_ctx = create_ssl_context(private_key_and_certificate_path, std::move(allowed_certificates), std::move(allowed_fingerprints), allow_any_cert);
- m_ssl_support = ssl_support;
+ m_ctx = boost::asio::ssl::context(boost::asio::ssl::context::tlsv12);
+ m_ssl_options = std::move(ssl_options);
}
inline
@@ -174,7 +174,7 @@ namespace net_utils
// SSL Options
if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
{
- if (!ssl_handshake(*m_ssl_socket, boost::asio::ssl::stream_base::client, m_ctx))
+ if (!m_ssl_options.handshake(*m_ssl_socket, boost::asio::ssl::stream_base::client, addr))
{
if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
{
@@ -191,7 +191,7 @@ namespace net_utils
return CONNECT_FAILURE;
}
}
- m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
+ m_ssl_options.support = ssl_support_t::e_ssl_support_enabled;
}
return CONNECT_SUCCESS;
}else
@@ -212,23 +212,21 @@ namespace net_utils
// Set SSL options
// disable sslv2
- m_ctx.context.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2);
- m_ctx.context.set_default_verify_paths();
- m_ssl_socket.reset(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_service, m_ctx.context));
+ m_ssl_socket.reset(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_service, m_ctx));
// Get a list of endpoints corresponding to the server name.
- try_connect_result_t try_connect_result = try_connect(addr, port, timeout, m_ssl_support);
+ try_connect_result_t try_connect_result = try_connect(addr, port, timeout, m_ssl_options.support);
if (try_connect_result == CONNECT_FAILURE)
return false;
- if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
+ if (m_ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
{
- m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
+ m_ssl_options.support = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
if (try_connect_result == CONNECT_NO_SSL)
{
MERROR("SSL handshake failed on an autodetect connection, reconnecting without SSL");
- m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_disabled;
- if (try_connect(addr, port, timeout, m_ssl_support) != CONNECT_SUCCESS)
+ m_ssl_options.support = epee::net_utils::ssl_support_t::e_ssl_support_disabled;
+ if (try_connect(addr, port, timeout, m_ssl_options.support) != CONNECT_SUCCESS)
return false;
}
}
@@ -260,7 +258,7 @@ namespace net_utils
if(m_connected)
{
m_connected = false;
- if(m_ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled)
+ if(m_ssl_options)
shutdown_ssl();
m_ssl_socket->next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both);
}
@@ -394,7 +392,7 @@ namespace net_utils
if (!m_connected || !m_ssl_socket->next_layer().is_open())
return false;
if (ssl)
- *ssl = m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled;
+ *ssl = m_ssl_options.support == ssl_support_t::e_ssl_support_enabled;
return true;
}
@@ -558,7 +556,7 @@ namespace net_utils
{
m_deadline.cancel();
boost::system::error_code ec;
- if(m_ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled)
+ if(m_ssl_options.support != ssl_support_t::e_ssl_support_disabled)
shutdown_ssl();
m_ssl_socket->next_layer().cancel(ec);
if(ec)
@@ -635,7 +633,7 @@ namespace net_utils
bool write(const void* data, size_t sz, boost::system::error_code& ec)
{
bool success;
- if(m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
+ if(m_ssl_options.support == ssl_support_t::e_ssl_support_enabled)
success = boost::asio::write(*m_ssl_socket, boost::asio::buffer(data, sz), ec);
else
success = boost::asio::write(m_ssl_socket->next_layer(), boost::asio::buffer(data, sz), ec);
@@ -644,7 +642,7 @@ namespace net_utils
void async_write(const void* data, size_t sz, boost::system::error_code& ec)
{
- if(m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
+ if(m_ssl_options.support == ssl_support_t::e_ssl_support_enabled)
boost::asio::async_write(*m_ssl_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
else
boost::asio::async_write(m_ssl_socket->next_layer(), boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
@@ -652,7 +650,7 @@ namespace net_utils
void async_read(char* buff, size_t sz, boost::asio::detail::transfer_at_least_t transfer_at_least, handler_obj& hndlr)
{
- if(m_ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_enabled)
+ if(m_ssl_options.support != ssl_support_t::e_ssl_support_enabled)
boost::asio::async_read(m_ssl_socket->next_layer(), boost::asio::buffer(buff, sz), transfer_at_least, hndlr);
else
boost::asio::async_read(*m_ssl_socket, boost::asio::buffer(buff, sz), transfer_at_least, hndlr);
@@ -661,10 +659,10 @@ namespace net_utils
protected:
boost::asio::io_service m_io_service;
- epee::net_utils::ssl_context_t m_ctx;
+ boost::asio::ssl::context m_ctx;
std::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> m_ssl_socket;
std::function<connect_func> m_connector;
- epee::net_utils::ssl_support_t m_ssl_support;
+ ssl_options_t m_ssl_options;
bool m_initialized;
bool m_connected;
boost::asio::steady_timer m_deadline;
diff --git a/contrib/epee/include/net/net_ssl.h b/contrib/epee/include/net/net_ssl.h
index f7b102164..957903ff8 100644
--- a/contrib/epee/include/net/net_ssl.h
+++ b/contrib/epee/include/net/net_ssl.h
@@ -31,10 +31,11 @@
#include <stdint.h>
#include <string>
-#include <list>
+#include <vector>
#include <boost/utility/string_ref.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl.hpp>
+#include <boost/system/error_code.hpp>
namespace epee
{
@@ -45,23 +46,93 @@ namespace net_utils
e_ssl_support_enabled,
e_ssl_support_autodetect,
};
-
- struct ssl_context_t
- {
- boost::asio::ssl::context context;
- std::list<std::string> allowed_certificates;
- std::vector<std::vector<uint8_t>> allowed_fingerprints;
- bool allow_any_cert;
- };
+
+ enum class ssl_verification_t : uint8_t
+ {
+ none = 0, //!< Do not verify peer.
+ system_ca, //!< Verify peer via system ca only (do not inspect user certificates)
+ user_certificates,//!< Verify peer via specific (non-chain) certificate(s) only.
+ user_ca //!< Verify peer via specific (possibly chain) certificate(s) only.
+ };
+
+ struct ssl_authentication_t
+ {
+ std::string private_key_path; //!< Private key used for authentication
+ std::string certificate_path; //!< Certificate used for authentication to peer.
+
+ //! Load `private_key_path` and `certificate_path` into `ssl_context`.
+ void use_ssl_certificate(boost::asio::ssl::context &ssl_context) const;
+ };
+
+ /*!
+ \note `verification != disabled && support == disabled` is currently
+ "allowed" via public interface but obviously invalid configuation.
+ */
+ class ssl_options_t
+ {
+ // force sorted behavior in private
+ std::vector<std::vector<std::uint8_t>> fingerprints_;
+
+ public:
+ std::string ca_path;
+ ssl_authentication_t auth;
+ ssl_support_t support;
+ ssl_verification_t verification;
+
+ //! Verification is set to system ca unless SSL is disabled.
+ ssl_options_t(ssl_support_t support)
+ : fingerprints_(),
+ ca_path(),
+ auth(),
+ support(support),
+ verification(support == ssl_support_t::e_ssl_support_disabled ? ssl_verification_t::none : ssl_verification_t::system_ca)
+ {}
+
+ //! Provide user fingerprints and/or ca path. Enables SSL and user_certificate verification
+ ssl_options_t(std::vector<std::vector<std::uint8_t>> fingerprints, std::string ca_path);
+
+ ssl_options_t(const ssl_options_t&) = default;
+ ssl_options_t(ssl_options_t&&) = default;
+
+ ssl_options_t& operator=(const ssl_options_t&) = default;
+ ssl_options_t& operator=(ssl_options_t&&) = default;
+
+ //! \return False iff ssl is disabled, otherwise true.
+ explicit operator bool() const noexcept { return support != ssl_support_t::e_ssl_support_disabled; }
+
+ //! \retrurn True if `host` can be verified using `this` configuration WITHOUT system "root" CAs.
+ bool has_strong_verification(boost::string_ref host) const noexcept;
+
+ //! Search against internal fingerprints. Always false if `behavior() != user_certificate_check`.
+ bool has_fingerprint(boost::asio::ssl::verify_context &ctx) const;
+
+ boost::asio::ssl::context create_context() const;
+
+ /*! \note If `this->support == autodetect && this->verification != none`,
+ then the handshake will not fail when peer verification fails. The
+ assumption is that a re-connect will be attempted, so a warning is
+ logged instead of failure.
+
+ \note It is strongly encouraged that clients using `system_ca`
+ verification provide a non-empty `host` for rfc2818 verification.
+
+ \param socket Used in SSL handshake and verification
+ \param type Client or server
+ \param host This parameter is only used when
+ `type == client && !host.empty()`. The value is sent to the server for
+ situations where multiple hostnames are being handled by a server. If
+ `verification == system_ca` the client also does a rfc2818 check to
+ ensure that the server certificate is to the provided hostname.
+
+ \return True if the SSL handshake completes with peer verification
+ settings. */
+ bool handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket, boost::asio::ssl::stream_base::handshake_type type, const std::string& host = {}) const;
+ };
// https://security.stackexchange.com/questions/34780/checking-client-hello-for-https-classification
constexpr size_t get_ssl_magic_size() { return 9; }
bool is_ssl(const unsigned char *data, size_t len);
- ssl_context_t create_ssl_context(const std::pair<std::string, std::string> &private_key_and_certificate_path, std::list<std::string> allowed_certificates, std::vector<std::vector<uint8_t>> allowed_fingerprints, bool allow_any_cert);
- void use_ssl_certificate(ssl_context_t &ssl_context, const std::pair<std::string, std::string> &private_key_and_certificate_path);
- bool is_certificate_allowed(boost::asio::ssl::verify_context &ctx, const ssl_context_t &ssl_context);
- bool ssl_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket, boost::asio::ssl::stream_base::handshake_type type, const epee::net_utils::ssl_context_t &ssl_context);
- bool ssl_support_from_string(ssl_support_t &ssl, boost::string_ref s);
+ bool ssl_support_from_string(ssl_support_t &ssl, boost::string_ref s);
}
}
diff --git a/contrib/epee/include/net/network_throttle-detail.hpp b/contrib/epee/include/net/network_throttle-detail.hpp
index d7f2cc37a..353ae0c0c 100644
--- a/contrib/epee/include/net/network_throttle-detail.hpp
+++ b/contrib/epee/include/net/network_throttle-detail.hpp
@@ -66,6 +66,8 @@ class network_throttle : public i_network_throttle {
network_time_seconds m_last_sample_time; // time of last history[0] - so we know when to rotate the buffer
network_time_seconds m_start_time; // when we were created
bool m_any_packet_yet; // did we yet got any packet to count
+ uint64_t m_total_packets;
+ uint64_t m_total_bytes;
std::string m_name; // my name for debug and logs
std::string m_nameshort; // my name for debug and logs (used in log file name)
@@ -95,6 +97,7 @@ class network_throttle : public i_network_throttle {
virtual size_t get_recommended_size_of_planned_transport() const; ///< what should be the size (bytes) of next data block to be transported
virtual size_t get_recommended_size_of_planned_transport_window(double force_window) const; ///< ditto, but for given windows time frame
virtual double get_current_speed() const;
+ virtual void get_stats(uint64_t &total_packets, uint64_t &total_bytes) const;
private:
virtual network_time_seconds time_to_slot(network_time_seconds t) const { return std::floor( t ); } // convert exact time eg 13.7 to rounded time for slot number in history 13
diff --git a/contrib/epee/include/net/network_throttle.hpp b/contrib/epee/include/net/network_throttle.hpp
index 5092241a4..02a286326 100644
--- a/contrib/epee/include/net/network_throttle.hpp
+++ b/contrib/epee/include/net/network_throttle.hpp
@@ -152,7 +152,8 @@ class i_network_throttle {
virtual size_t get_recommended_size_of_planned_transport() const =0; // what should be the recommended limit of data size that we can transport over current network_throttle in near future
virtual double get_time_seconds() const =0; // a timer
- virtual void logger_handle_net(const std::string &filename, double time, size_t size)=0;
+ virtual void logger_handle_net(const std::string &filename, double time, size_t size)=0;
+ virtual void get_stats(uint64_t &total_packets, uint64_t &total_bytes) const =0;
};
diff --git a/contrib/epee/include/span.h b/contrib/epee/include/span.h
index 19720ea8b..e100452ca 100644
--- a/contrib/epee/include/span.h
+++ b/contrib/epee/include/span.h
@@ -31,6 +31,7 @@
#include <algorithm>
#include <cstdint>
#include <memory>
+#include <string>
#include <type_traits>
namespace epee
diff --git a/contrib/epee/include/storages/parserse_base_utils.h b/contrib/epee/include/storages/parserse_base_utils.h
index 69b650cd4..b5c4138c5 100644
--- a/contrib/epee/include/storages/parserse_base_utils.h
+++ b/contrib/epee/include/storages/parserse_base_utils.h
@@ -42,13 +42,14 @@ namespace misc_utils
// 4: alpha
// 8: whitespace
// 16: allowed in float but doesn't necessarily mean it's a float
+ // 32: \ and " (end of verbatim string)
static const constexpr uint8_t lut[256]={
0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 0, 0, // 16
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32
- 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 18, 0, // 48
+ 8, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 18, 0, // 48
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 0, 0, 0, 0, // 64
0, 4, 4, 4, 4, 22, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 80
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 96
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 32, 0, 0, 0, // 96
0, 4, 4, 4, 4, 22, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 112
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 128
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -130,7 +131,7 @@ namespace misc_utils
std::string::const_iterator it = star_end_string;
++it;
std::string::const_iterator fi = it;
- while (fi != buf_end && *fi != '\\' && *fi != '\"')
+ while (fi != buf_end && ((lut[(uint8_t)*fi] & 32)) == 0)
++fi;
val.assign(it, fi);
val.reserve(std::distance(star_end_string, buf_end));
diff --git a/contrib/epee/include/storages/portable_storage_base.h b/contrib/epee/include/storages/portable_storage_base.h
index da84fd8ea..ca7c81ddc 100644
--- a/contrib/epee/include/storages/portable_storage_base.h
+++ b/contrib/epee/include/storages/portable_storage_base.h
@@ -82,6 +82,7 @@ namespace epee
struct array_entry_t
{
array_entry_t():m_it(m_array.end()){}
+ array_entry_t(const array_entry_t& other):m_array(other.m_array), m_it(m_array.end()){}
const t_entry_type* get_first_val() const
{
diff --git a/contrib/epee/include/storages/portable_storage_val_converters.h b/contrib/epee/include/storages/portable_storage_val_converters.h
index 36bb28627..e54cda828 100644
--- a/contrib/epee/include/storages/portable_storage_val_converters.h
+++ b/contrib/epee/include/storages/portable_storage_val_converters.h
@@ -144,7 +144,7 @@ POP_WARNINGS
{
MTRACE("Converting std::string to uint64_t. Source: " << from);
// String only contains digits
- if(std::all_of(from.begin(), from.end(), ::isdigit))
+ if(std::all_of(from.begin(), from.end(), epee::misc_utils::parse::isdigit))
to = boost::lexical_cast<uint64_t>(from);
// MyMonero ISO 8061 timestamp (2017-05-06T16:27:06Z)
else if (boost::regex_match (from, boost::regex("\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\dZ")))
diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h
index 2e65876e6..da47b7d55 100644
--- a/contrib/epee/include/string_tools.h
+++ b/contrib/epee/include/string_tools.h
@@ -42,6 +42,8 @@
#include <type_traits>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/predicate.hpp>
+#include "misc_log_ex.h"
+#include "storages/parserse_base_utils.h"
#include "hex.h"
#include "memwipe.h"
#include "mlocker.h"
@@ -126,7 +128,7 @@ DISABLE_GCC_WARNING(maybe-uninitialized)
{
for (char c : str_id)
{
- if (!std::isdigit(c))
+ if (!epee::misc_utils::parse::isdigit(c))
return false;
}
}
diff --git a/contrib/epee/src/connection_basic.cpp b/contrib/epee/src/connection_basic.cpp
index cafc08ead..19f2c7b02 100644
--- a/contrib/epee/src/connection_basic.cpp
+++ b/contrib/epee/src/connection_basic.cpp
@@ -65,6 +65,15 @@ namespace epee
namespace net_utils
{
+namespace
+{
+ boost::asio::ssl::context& get_context(connection_basic_shared_state* state)
+ {
+ CHECK_AND_ASSERT_THROW_MES(state != nullptr, "state shared_ptr cannot be null");
+ return state->ssl_context;
+ }
+}
+
std::string to_string(t_connection_type type)
{
if (type == e_connection_type_NET)
@@ -119,56 +128,54 @@ connection_basic_pimpl::connection_basic_pimpl(const std::string &name) : m_thro
int connection_basic_pimpl::m_default_tos;
// methods:
-connection_basic::connection_basic(boost::asio::ip::tcp::socket&& sock, boost::shared_ptr<socket_stats> stats, ssl_support_t ssl_support, ssl_context_t &ssl_context)
+connection_basic::connection_basic(boost::asio::ip::tcp::socket&& sock, boost::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support)
:
- m_stats(std::move(stats)),
+ m_state(std::move(state)),
mI( new connection_basic_pimpl("peer") ),
strand_(GET_IO_SERVICE(sock)),
- socket_(GET_IO_SERVICE(sock), ssl_context.context),
+ socket_(GET_IO_SERVICE(sock), get_context(m_state.get())),
m_want_close_connection(false),
m_was_shutdown(false),
- m_ssl_support(ssl_support),
- m_ssl_context(ssl_context)
+ m_ssl_support(ssl_support)
{
// add nullptr checks if removed
- CHECK_AND_ASSERT_THROW_MES(bool(m_stats), "stats shared_ptr cannot be null");
+ assert(m_state != nullptr); // release runtime check in get_context
socket_.next_layer() = std::move(sock);
- ++(m_stats->sock_count); // increase the global counter
- mI->m_peer_number = m_stats->sock_number.fetch_add(1); // use, and increase the generated number
+ ++(m_state->sock_count); // increase the global counter
+ mI->m_peer_number = m_state->sock_number.fetch_add(1); // use, and increase the generated number
std::string remote_addr_str = "?";
try { boost::system::error_code e; remote_addr_str = socket().remote_endpoint(e).address().to_string(); } catch(...){} ;
- _note("Spawned connection #"<<mI->m_peer_number<<" to " << remote_addr_str << " currently we have sockets count:" << m_stats->sock_count);
+ _note("Spawned connection #"<<mI->m_peer_number<<" to " << remote_addr_str << " currently we have sockets count:" << m_state->sock_count);
}
-connection_basic::connection_basic(boost::asio::io_service &io_service, boost::shared_ptr<socket_stats> stats, ssl_support_t ssl_support, ssl_context_t &ssl_context)
+connection_basic::connection_basic(boost::asio::io_service &io_service, boost::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support)
:
- m_stats(std::move(stats)),
+ m_state(std::move(state)),
mI( new connection_basic_pimpl("peer") ),
strand_(io_service),
- socket_(io_service, ssl_context.context),
- m_want_close_connection(false),
+ socket_(io_service, get_context(m_state.get())),
+ m_want_close_connection(false),
m_was_shutdown(false),
- m_ssl_support(ssl_support),
- m_ssl_context(ssl_context)
+ m_ssl_support(ssl_support)
{
// add nullptr checks if removed
- CHECK_AND_ASSERT_THROW_MES(bool(m_stats), "stats shared_ptr cannot be null");
+ assert(m_state != nullptr); // release runtime check in get_context
- ++(m_stats->sock_count); // increase the global counter
- mI->m_peer_number = m_stats->sock_number.fetch_add(1); // use, and increase the generated number
+ ++(m_state->sock_count); // increase the global counter
+ mI->m_peer_number = m_state->sock_number.fetch_add(1); // use, and increase the generated number
std::string remote_addr_str = "?";
try { boost::system::error_code e; remote_addr_str = socket().remote_endpoint(e).address().to_string(); } catch(...){} ;
- _note("Spawned connection #"<<mI->m_peer_number<<" to " << remote_addr_str << " currently we have sockets count:" << m_stats->sock_count);
+ _note("Spawned connection #"<<mI->m_peer_number<<" to " << remote_addr_str << " currently we have sockets count:" << m_state->sock_count);
}
connection_basic::~connection_basic() noexcept(false) {
- --(m_stats->sock_count);
+ --(m_state->sock_count);
std::string remote_addr_str = "?";
try { boost::system::error_code e; remote_addr_str = socket().remote_endpoint(e).address().to_string(); } catch(...){} ;
diff --git a/contrib/epee/src/net_ssl.cpp b/contrib/epee/src/net_ssl.cpp
index eb0b0ad65..7bedb18ac 100644
--- a/contrib/epee/src/net_ssl.cpp
+++ b/contrib/epee/src/net_ssl.cpp
@@ -46,8 +46,7 @@ namespace
{
void operator()(BIO* ptr) const noexcept
{
- if (ptr)
- BIO_free(ptr);
+ BIO_free(ptr);
}
};
using openssl_bio = std::unique_ptr<BIO, openssl_bio_free>;
@@ -56,12 +55,43 @@ namespace
{
void operator()(EVP_PKEY* ptr) const noexcept
{
- if (ptr)
- EVP_PKEY_free(ptr);
+ EVP_PKEY_free(ptr);
}
};
using openssl_pkey = std::unique_ptr<EVP_PKEY, openssl_pkey_free>;
+ struct openssl_rsa_free
+ {
+ void operator()(RSA* ptr) const noexcept
+ {
+ RSA_free(ptr);
+ }
+ };
+ using openssl_rsa = std::unique_ptr<RSA, openssl_rsa_free>;
+
+ struct openssl_bignum_free
+ {
+ void operator()(BIGNUM* ptr) const noexcept
+ {
+ BN_free(ptr);
+ }
+ };
+ using openssl_bignum = std::unique_ptr<BIGNUM, openssl_bignum_free>;
+
+ boost::system::error_code load_ca_file(boost::asio::ssl::context& ctx, const std::string& path)
+ {
+ SSL_CTX* const ssl_ctx = ctx.native_handle(); // could be moved from context
+ if (ssl_ctx == nullptr)
+ return {boost::asio::error::invalid_argument};
+
+ if (!SSL_CTX_load_verify_locations(ssl_ctx, path.c_str(), nullptr))
+ {
+ return boost::system::error_code{
+ int(::ERR_get_error()), boost::asio::error::get_ssl_category()
+ };
+ }
+ return boost::system::error_code{};
+ }
}
namespace epee
@@ -69,6 +99,7 @@ namespace epee
namespace net_utils
{
+
// https://stackoverflow.com/questions/256405/programmatically-create-x509-certificate-using-openssl
bool create_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert)
{
@@ -81,19 +112,37 @@ bool create_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert)
}
openssl_pkey pkey_deleter{pkey};
- RSA *rsa = RSA_generate_key(4096, RSA_F4, NULL, NULL);
+ openssl_rsa rsa{RSA_new()};
if (!rsa)
{
+ MERROR("Error allocating RSA private key");
+ return false;
+ }
+
+ openssl_bignum exponent{BN_new()};
+ if (!exponent)
+ {
+ MERROR("Error allocating exponent");
+ return false;
+ }
+
+ BN_set_word(exponent.get(), RSA_F4);
+
+ if (RSA_generate_key_ex(rsa.get(), 4096, exponent.get(), nullptr) != 1)
+ {
MERROR("Error generating RSA private key");
return false;
}
- if (EVP_PKEY_assign_RSA(pkey, rsa) <= 0) // The RSA will be automatically freed when the EVP_PKEY structure is freed.
+
+ if (EVP_PKEY_assign_RSA(pkey, rsa.get()) <= 0)
{
MERROR("Error assigning RSA private key");
- RSA_free(rsa);
return false;
}
+ // the RSA key is now managed by the EVP_PKEY structure
+ (void)rsa.release();
+
cert = X509_new();
if (!cert)
{
@@ -122,22 +171,34 @@ bool create_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert)
return true;
}
-ssl_context_t create_ssl_context(const std::pair<std::string, std::string> &private_key_and_certificate_path, std::list<std::string> allowed_certificates, std::vector<std::vector<uint8_t>> allowed_fingerprints, bool allow_any_cert)
+ssl_options_t::ssl_options_t(std::vector<std::vector<std::uint8_t>> fingerprints, std::string ca_path)
+ : fingerprints_(std::move(fingerprints)),
+ ca_path(std::move(ca_path)),
+ auth(),
+ support(ssl_support_t::e_ssl_support_enabled),
+ verification(ssl_verification_t::user_certificates)
{
- ssl_context_t ssl_context{boost::asio::ssl::context(boost::asio::ssl::context::tlsv12), std::move(allowed_certificates), std::move(allowed_fingerprints)};
+ std::sort(fingerprints_.begin(), fingerprints_.end());
+}
+
+boost::asio::ssl::context ssl_options_t::create_context() const
+{
+ boost::asio::ssl::context ssl_context{boost::asio::ssl::context::tlsv12};
+ if (!bool(*this))
+ return ssl_context;
// only allow tls v1.2 and up
- ssl_context.context.set_options(boost::asio::ssl::context::default_workarounds);
- ssl_context.context.set_options(boost::asio::ssl::context::no_sslv2);
- ssl_context.context.set_options(boost::asio::ssl::context::no_sslv3);
- ssl_context.context.set_options(boost::asio::ssl::context::no_tlsv1);
- ssl_context.context.set_options(boost::asio::ssl::context::no_tlsv1_1);
+ ssl_context.set_options(boost::asio::ssl::context::default_workarounds);
+ ssl_context.set_options(boost::asio::ssl::context::no_sslv2);
+ ssl_context.set_options(boost::asio::ssl::context::no_sslv3);
+ ssl_context.set_options(boost::asio::ssl::context::no_tlsv1);
+ ssl_context.set_options(boost::asio::ssl::context::no_tlsv1_1);
// only allow a select handful of tls v1.3 and v1.2 ciphers to be used
- SSL_CTX_set_cipher_list(ssl_context.context.native_handle(), "ECDHE-ECDSA-CHACHA20-POLY1305-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-CHACHA20-POLY1305");
+ SSL_CTX_set_cipher_list(ssl_context.native_handle(), "ECDHE-ECDSA-CHACHA20-POLY1305-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-CHACHA20-POLY1305");
// set options on the SSL context for added security
- SSL_CTX *ctx = ssl_context.context.native_handle();
+ SSL_CTX *ctx = ssl_context.native_handle();
CHECK_AND_ASSERT_THROW_MES(ctx, "Failed to get SSL context");
SSL_CTX_clear_options(ctx, SSL_OP_LEGACY_SERVER_CONNECT); // SSL_CTX_SET_OPTIONS(3)
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); // https://stackoverflow.com/questions/22378442
@@ -153,10 +214,29 @@ ssl_context_t create_ssl_context(const std::pair<std::string, std::string> &priv
#ifdef SSL_OP_NO_COMPRESSION
SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
#endif
- ssl_context.context.set_default_verify_paths();
- CHECK_AND_ASSERT_THROW_MES(private_key_and_certificate_path.first.empty() == private_key_and_certificate_path.second.empty(), "private key and certificate must be either both given or both empty");
- if (private_key_and_certificate_path.second.empty())
+ switch (verification)
+ {
+ case ssl_verification_t::system_ca:
+ ssl_context.set_default_verify_paths();
+ break;
+ case ssl_verification_t::user_certificates:
+ ssl_context.set_verify_depth(0);
+ /* fallthrough */
+ case ssl_verification_t::user_ca:
+ if (!ca_path.empty())
+ {
+ const boost::system::error_code err = load_ca_file(ssl_context, ca_path);
+ if (err)
+ throw boost::system::system_error{err, "Failed to load user CA file at " + ca_path};
+ }
+ break;
+ default:
+ break;
+ }
+
+ CHECK_AND_ASSERT_THROW_MES(auth.private_key_path.empty() == auth.certificate_path.empty(), "private key and certificate must be either both given or both empty");
+ if (auth.private_key_path.empty())
{
EVP_PKEY *pkey;
X509 *cert;
@@ -167,19 +247,15 @@ ssl_context_t create_ssl_context(const std::pair<std::string, std::string> &priv
EVP_PKEY_free(pkey);
}
else
- {
- ssl_context.context.use_private_key_file(private_key_and_certificate_path.first, boost::asio::ssl::context::pem);
- ssl_context.context.use_certificate_file(private_key_and_certificate_path.second, boost::asio::ssl::context::pem);
- }
- ssl_context.allow_any_cert = allow_any_cert;
+ auth.use_ssl_certificate(ssl_context);
return ssl_context;
}
-void use_ssl_certificate(ssl_context_t &ssl_context, const std::pair<std::string, std::string> &private_key_and_certificate_path)
+void ssl_authentication_t::use_ssl_certificate(boost::asio::ssl::context &ssl_context) const
{
- ssl_context.context.use_private_key_file(private_key_and_certificate_path.first, boost::asio::ssl::context::pem);
- ssl_context.context.use_certificate_file(private_key_and_certificate_path.second, boost::asio::ssl::context::pem);
+ ssl_context.use_private_key_file(private_key_path, boost::asio::ssl::context::pem);
+ ssl_context.use_certificate_chain_file(certificate_path);
}
bool is_ssl(const unsigned char *data, size_t len)
@@ -202,23 +278,44 @@ bool is_ssl(const unsigned char *data, size_t len)
return false;
}
-bool is_certificate_allowed(boost::asio::ssl::verify_context &ctx, const ssl_context_t &ssl_context)
+bool ssl_options_t::has_strong_verification(boost::string_ref host) const noexcept
{
- X509_STORE_CTX *sctx = ctx.native_handle();
- if (!sctx)
- {
- MERROR("Error getting verify_context handle");
- return false;
- }
- X509 *cert =X509_STORE_CTX_get_current_cert(sctx);
- if (!cert)
+ // onion and i2p addresses contain information about the server cert
+ // which both authenticates and encrypts
+ if (host.ends_with(".onion") || host.ends_with(".i2p"))
+ return true;
+ switch (verification)
{
- MERROR("No certificate found in verify_context");
- return false;
+ default:
+ case ssl_verification_t::none:
+ case ssl_verification_t::system_ca:
+ return false;
+ case ssl_verification_t::user_certificates:
+ case ssl_verification_t::user_ca:
+ break;
}
+ return true;
+}
+bool ssl_options_t::has_fingerprint(boost::asio::ssl::verify_context &ctx) const
+{
// can we check the certificate against a list of fingerprints?
- if (!ssl_context.allowed_fingerprints.empty()) {
+ if (!fingerprints_.empty()) {
+ X509_STORE_CTX *sctx = ctx.native_handle();
+ if (!sctx)
+ {
+ MERROR("Error getting verify_context handle");
+ return false;
+ }
+
+ X509* cert = nullptr;
+ const STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(sctx);
+ if (!chain || sk_X509_num(chain) < 1 || !(cert = sk_X509_value(chain, 0)))
+ {
+ MERROR("No certificate found in verify_context");
+ return false;
+ }
+
// buffer for the certificate digest and the size of the result
std::vector<uint8_t> digest(EVP_MAX_MD_SIZE);
unsigned int size{ 0 };
@@ -232,74 +329,63 @@ bool is_certificate_allowed(boost::asio::ssl::verify_context &ctx, const ssl_con
// strip unnecessary bytes from the digest
digest.resize(size);
- // is the certificate fingerprint inside the list of allowed fingerprints?
- if (std::find(ssl_context.allowed_fingerprints.begin(), ssl_context.allowed_fingerprints.end(), digest) != ssl_context.allowed_fingerprints.end())
- return true;
- }
-
- if (!ssl_context.allowed_certificates.empty()) {
- BIO *bio_cert = BIO_new(BIO_s_mem());
- bool success = PEM_write_bio_X509(bio_cert, cert);
- if (!success)
- {
- BIO_free(bio_cert);
- MERROR("Failed to print certificate");
- return false;
- }
- BUF_MEM *buf = NULL;
- BIO_get_mem_ptr(bio_cert, &buf);
- if (!buf || !buf->data || !buf->length)
- {
- BIO_free(bio_cert);
- MERROR("Failed to write certificate: " << ERR_get_error());
- return false;
- }
- std::string certificate(std::string(buf->data, buf->length));
- BIO_free(bio_cert);
- if (std::find(ssl_context.allowed_certificates.begin(), ssl_context.allowed_certificates.end(), certificate) != ssl_context.allowed_certificates.end())
- return true;
+ return std::binary_search(fingerprints_.begin(), fingerprints_.end(), digest);
}
- // if either checklist is non-empty we must have failed it
- return ssl_context.allowed_fingerprints.empty() && ssl_context.allowed_certificates.empty();
+ return false;
}
-bool ssl_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket, boost::asio::ssl::stream_base::handshake_type type, const epee::net_utils::ssl_context_t &ssl_context)
+bool ssl_options_t::handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket, boost::asio::ssl::stream_base::handshake_type type, const std::string& host) const
{
- bool verified = false;
socket.next_layer().set_option(boost::asio::ip::tcp::no_delay(true));
- socket.set_verify_mode(boost::asio::ssl::verify_peer);
- socket.set_verify_callback([&](bool preverified, boost::asio::ssl::verify_context &ctx)
+
+ /* Using system-wide CA store for client verification is funky - there is
+ no expected hostname for server to verify against. If server doesn't have
+ specific whitelisted certificates for client, don't require client to
+ send certificate at all. */
+ const bool no_verification = verification == ssl_verification_t::none ||
+ (type == boost::asio::ssl::stream_base::server && fingerprints_.empty() && ca_path.empty());
+
+ /* According to OpenSSL documentation (and SSL specifications), server must
+ always send certificate unless "anonymous" cipher mode is used which are
+ disabled by default. Either way, the certificate is never inspected. */
+ if (no_verification)
+ socket.set_verify_mode(boost::asio::ssl::verify_none);
+ else
{
- if (!preverified)
+ socket.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert);
+
+ // in case server is doing "virtual" domains, set hostname
+ SSL* const ssl_ctx = socket.native_handle();
+ if (type == boost::asio::ssl::stream_base::client && !host.empty() && ssl_ctx)
+ SSL_set_tlsext_host_name(ssl_ctx, host.c_str());
+
+ socket.set_verify_callback([&](const bool preverified, boost::asio::ssl::verify_context &ctx)
{
- const int err = X509_STORE_CTX_get_error(ctx.native_handle());
- const int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle());
- if (err != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || depth != 0)
+ // preverified means it passed system or user CA check. System CA is never loaded
+ // when fingerprints are whitelisted.
+ const bool verified = preverified &&
+ (verification != ssl_verification_t::system_ca || host.empty() || boost::asio::ssl::rfc2818_verification(host)(preverified, ctx));
+
+ if (!verified && !has_fingerprint(ctx))
{
- MERROR("Invalid SSL certificate, error " << err << " at depth " << depth << ", connection dropped");
- return false;
+ // autodetect will reconnect without SSL - warn and keep connection encrypted
+ if (support != ssl_support_t::e_ssl_support_autodetect)
+ {
+ MERROR("SSL certificate is not in the allowed list, connection droppped");
+ return false;
+ }
+ MWARNING("SSL peer has not been verified");
}
- }
- if (!ssl_context.allow_any_cert && !is_certificate_allowed(ctx, ssl_context))
- {
- MERROR("Certificate is not in the allowed list, connection droppped");
- return false;
- }
- verified = true;
- return true;
- });
+ return true;
+ });
+ }
boost::system::error_code ec;
socket.handshake(type, ec);
if (ec)
{
- MERROR("handshake failed, connection dropped: " << ec.message());
- return false;
- }
- if (!ssl_context.allow_any_cert && !verified)
- {
- MERROR("Peer did not provide a certificate in the allowed list, connection dropped");
+ MERROR("SSL handshake failed, connection dropped: " << ec.message());
return false;
}
MDEBUG("SSL handshake success");
diff --git a/contrib/epee/src/network_throttle-detail.cpp b/contrib/epee/src/network_throttle-detail.cpp
index f89e7aec0..72544cbf6 100644
--- a/contrib/epee/src/network_throttle-detail.cpp
+++ b/contrib/epee/src/network_throttle-detail.cpp
@@ -136,6 +136,8 @@ network_throttle::network_throttle(const std::string &nameshort, const std::stri
m_target_speed = 16 * 1024; // other defaults are probably defined in the command-line parsing code when this class is used e.g. as main global throttle
m_last_sample_time = 0;
m_history.resize(m_window_size);
+ m_total_packets = 0;
+ m_total_bytes = 0;
}
void network_throttle::set_name(const std::string &name)
@@ -192,6 +194,8 @@ void network_throttle::_handle_trafic_exact(size_t packet_size, size_t orginal_s
calculate_times_struct cts ; calculate_times(packet_size, cts , false, -1);
calculate_times_struct cts2; calculate_times(packet_size, cts2, false, 5);
m_history.front().m_size += packet_size;
+ m_total_packets++;
+ m_total_bytes += packet_size;
std::ostringstream oss; oss << "["; for (auto sample: m_history) oss << sample.m_size << " "; oss << "]" << std::ends;
std::string history_str = oss.str();
@@ -352,6 +356,12 @@ double network_throttle::get_current_speed() const {
return bytes_transferred / ((m_history.size() - 1) * m_slot_size);
}
+void network_throttle::get_stats(uint64_t &total_packets, uint64_t &total_bytes) const {
+ total_packets = m_total_packets;
+ total_bytes = m_total_bytes;
+}
+
+
} // namespace
} // namespace