Pass SSL arguments via one class and use shared_ptr instead of reference

This commit is contained in:
Lee Clagett 2019-03-15 00:03:32 -04:00
parent 1f5ed328aa
commit 21eb1b0725
13 changed files with 302 additions and 209 deletions

View file

@ -90,10 +90,10 @@ namespace net_utils
public: public:
typedef typename t_protocol_handler::connection_context t_connection_context; typedef typename t_protocol_handler::connection_context t_connection_context;
struct shared_state : socket_stats struct shared_state : connection_basic_shared_state
{ {
shared_state() shared_state()
: socket_stats(), pfilter(nullptr), config() : connection_basic_shared_state(), pfilter(nullptr), config()
{} {}
i_connection_filter* pfilter; i_connection_filter* pfilter;
@ -104,14 +104,12 @@ namespace net_utils
explicit connection( boost::asio::io_service& io_service, explicit connection( boost::asio::io_service& io_service,
boost::shared_ptr<shared_state> state, boost::shared_ptr<shared_state> state,
t_connection_type connection_type, t_connection_type connection_type,
epee::net_utils::ssl_support_t ssl_support, epee::net_utils::ssl_support_t ssl_support);
ssl_context_t &ssl_context);
explicit connection( boost::asio::ip::tcp::socket&& sock, explicit connection( boost::asio::ip::tcp::socket&& sock,
boost::shared_ptr<shared_state> state, boost::shared_ptr<shared_state> state,
t_connection_type connection_type, t_connection_type connection_type,
epee::net_utils::ssl_support_t ssl_support, epee::net_utils::ssl_support_t ssl_support);
ssl_context_t &ssl_context);
@ -228,8 +226,8 @@ namespace net_utils
std::map<std::string, t_connection_type> server_type_map; std::map<std::string, t_connection_type> server_type_map;
void create_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::string &ca_file = {}, 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", 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::string &ca_file = {}, 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", ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect);
/// Run the server's io_service loop. /// 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()); bool run_server(size_t threads_count, bool wait = true, const boost::thread::attributes& attrs = boost::thread::attributes());
@ -380,8 +378,6 @@ namespace net_utils
boost::mutex connections_mutex; boost::mutex connections_mutex;
std::set<connection_ptr> connections_; std::set<connection_ptr> connections_;
ssl_context_t m_ssl_context;
}; // class <>boosted_tcp_server }; // class <>boosted_tcp_server

View file

@ -80,10 +80,9 @@ PRAGMA_WARNING_DISABLE_VS(4355)
connection<t_protocol_handler>::connection( boost::asio::io_service& io_service, connection<t_protocol_handler>::connection( boost::asio::io_service& io_service,
boost::shared_ptr<shared_state> state, boost::shared_ptr<shared_state> state,
t_connection_type connection_type, t_connection_type connection_type,
epee::net_utils::ssl_support_t ssl_support, ssl_support_t ssl_support
ssl_context_t &ssl_context
) )
: 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, connection<t_protocol_handler>::connection( boost::asio::ip::tcp::socket&& sock,
boost::shared_ptr<shared_state> state, boost::shared_ptr<shared_state> state,
t_connection_type connection_type, t_connection_type connection_type,
epee::net_utils::ssl_support_t ssl_support, ssl_support_t ssl_support
ssl_context_t &ssl_context
) )
: :
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_protocol_handler(this, check_and_get(state).config, context),
m_connection_type( connection_type ), m_connection_type( connection_type ),
m_throttle_speed_in("speed_in", "throttle_speed_in"), 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) << _dbg3("[sock " << socket_.native_handle() << "] new connection from " << print_connection_context_short(context) <<
" to " << local_ep.address().to_string() << ':' << local_ep.port() << " 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"); _dbg2("[sock " << socket().native_handle() << "] host denied " << context.m_remote_address.host_str() << ", shutdowning connection");
close(); close();
@ -901,8 +899,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
m_threads_count(0), m_threads_count(0),
m_thread_index(0), m_thread_index(0),
m_connection_type( connection_type ), m_connection_type( connection_type ),
new_connection_(), new_connection_()
m_ssl_context({boost::asio::ssl::context(boost::asio::ssl::context::tlsv12), {}})
{ {
create_server_type_map(); create_server_type_map();
m_thread_name_prefix = "NET"; m_thread_name_prefix = "NET";
@ -918,8 +915,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
m_threads_count(0), m_threads_count(0),
m_thread_index(0), m_thread_index(0),
m_connection_type(connection_type), m_connection_type(connection_type),
new_connection_(), new_connection_()
m_ssl_context({boost::asio::ssl::context(boost::asio::ssl::context::sslv23), {}})
{ {
create_server_type_map(); create_server_type_map();
m_thread_name_prefix = "NET"; m_thread_name_prefix = "NET";
@ -941,14 +937,14 @@ PRAGMA_WARNING_DISABLE_VS(4355)
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
template<class t_protocol_handler> 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::string &ca_file, 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(); TRY_ENTRY();
m_stop_signal_sent = false; m_stop_signal_sent = false;
m_port = port; m_port = port;
m_address = address; m_address = address;
if (ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled) if (ssl_options)
m_ssl_context = create_ssl_context(private_key_and_certificate_path, ca_file, allowed_fingerprints, allow_any_cert); m_state->configure_ssl(std::move(ssl_options));
// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). // 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 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); 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(); boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_.local_endpoint();
m_port = binded_endpoint.port(); m_port = binded_endpoint.port();
MDEBUG("start accept"); 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(), acceptor_.async_accept(new_connection_->socket(),
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this, boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
boost::asio::placeholders::error)); boost::asio::placeholders::error));
@ -982,7 +978,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
PUSH_WARNINGS PUSH_WARNINGS
DISABLE_GCC_WARNING(maybe-uninitialized) DISABLE_GCC_WARNING(maybe-uninitialized)
template<class t_protocol_handler> 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::string &ca_file, 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; uint32_t p = 0;
@ -990,7 +986,7 @@ DISABLE_GCC_WARNING(maybe-uninitialized)
MERROR("Failed to convert port no = " << port); MERROR("Failed to convert port no = " << port);
return false; return false;
} }
return this->init_server(p, address, ssl_support, private_key_and_certificate_path, ca_file, allowed_fingerprints, allow_any_cert); return this->init_server(p, address, std::move(ssl_options));
} }
POP_WARNINGS POP_WARNINGS
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
@ -1165,7 +1161,7 @@ POP_WARNINGS
new_connection_->setRpcStation(); // hopefully this is not needed actually new_connection_->setRpcStation(); // hopefully this is not needed actually
} }
connection_ptr conn(std::move(new_connection_)); 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(), acceptor_.async_accept(new_connection_->socket(),
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this, boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
boost::asio::placeholders::error)); boost::asio::placeholders::error));
@ -1200,7 +1196,7 @@ POP_WARNINGS
assert(m_state != nullptr); // always set in constructor assert(m_state != nullptr); // always set in constructor
_erro("Some problems at accept: " << e.message() << ", connections_count = " << m_state->sock_count); _erro("Some problems at accept: " << e.message() << ", connections_count = " << m_state->sock_count);
misc_utils::sleep_no_w(100); 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(), acceptor_.async_accept(new_connection_->socket(),
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this, boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
boost::asio::placeholders::error)); boost::asio::placeholders::error));
@ -1211,7 +1207,7 @@ POP_WARNINGS
{ {
if(std::addressof(get_io_service()) == std::addressof(GET_IO_SERVICE(sock))) 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))) if(conn->start(false, 1 < m_threads_count, std::move(real_remote)))
{ {
conn->get_context(out); conn->get_context(out);
@ -1298,7 +1294,7 @@ POP_WARNINGS
_dbg3("Connected success to " << adr << ':' << port); _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) 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 // Handshake
@ -1329,7 +1325,7 @@ POP_WARNINGS
{ {
TRY_ENTRY(); 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_mutex.lock();
connections_.insert(new_connection_l); connections_.insert(new_connection_l);
MDEBUG("connections_ size now " << connections_.size()); 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) 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(); 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_mutex.lock();
connections_.insert(new_connection_l); connections_.insert(new_connection_l);
MDEBUG("connections_ size now " << connections_.size()); MDEBUG("connections_ size now " << connections_.size());

View file

@ -57,15 +57,30 @@ namespace epee
{ {
namespace net_utils namespace net_utils
{ {
struct socket_stats
{
socket_stats()
: sock_count(0), sock_number(0)
{}
std::atomic<long> sock_count; class connection_basic_shared_state
std::atomic<long> sock_number; {
}; 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); std::string to_string(t_connection_type type);
class connection_basic { // not-templated base class for rapid developmet of some code parts 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 // 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; const boost::shared_ptr<connection_basic_shared_state> m_state;
public: public:
std::unique_ptr< connection_basic_pimpl > mI; // my Implementation 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<> // 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. /// Strand to ensure the connection's handlers are not called concurrently.
boost::asio::io_service::strand strand_; boost::asio::io_service::strand strand_;
/// Socket for the connection. /// 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_; boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
ssl_support_t m_ssl_support;
public: public:
// first counter is the ++/-- count of current sockets, the other socket_number is only-increasing ++ number generator // 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::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<socket_stats> stats, ssl_support_t ssl_support, ssl_context_t &ssl_context); 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); virtual ~connection_basic() noexcept(false);
//! \return `socket_stats` object passed in construction (ptr never changes). //! \return `shared_state` object passed in construction (ptr never changes).
socket_stats& get_stats() noexcept { return *m_stats; /* verified in constructor */ } 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, ssl_context_t &ssl_context); 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(); } boost::asio::ip::tcp::socket& socket() { return socket_.next_layer(); }
ssl_support_t get_ssl_support() const { return m_ssl_support; } 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) 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> template<typename MutableBufferSequence, typename ReadHandler>

View file

@ -275,11 +275,6 @@ namespace net_utils
chunked_state m_chunked_state; chunked_state m_chunked_state;
std::string m_chunked_cache; std::string m_chunked_cache;
critical_section m_lock; 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::string m_ssl_ca_file;
std::vector<std::vector<uint8_t>> m_ssl_allowed_fingerprints;
bool m_ssl_allow_any_cert;
public: public:
explicit http_simple_client_template() explicit http_simple_client_template()
@ -297,34 +292,28 @@ namespace net_utils
, m_chunked_state() , m_chunked_state()
, m_chunked_cache() , m_chunked_cache()
, m_lock() , 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_host() const { return m_host_buff; };
const std::string &get_port() const { return m_port; }; 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 = {}, std::string ca_file = {}, 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{}; http::url_content parsed{};
const bool r = parse_url(address, parsed); const bool r = parse_url(address, parsed);
CHECK_AND_ASSERT_MES(r, false, "failed to parse url: " << address); 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, std::move(ca_file), 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; 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 = {}, std::string ca_file = {}, 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); CRITICAL_REGION_LOCAL(m_lock);
disconnect(); disconnect();
m_host_buff = std::move(host); m_host_buff = std::move(host);
m_port = std::move(port); m_port = std::move(port);
m_auth = user ? http_client_auth{std::move(*user)} : http_client_auth{}; m_auth = user ? http_client_auth{std::move(*user)} : http_client_auth{};
m_ssl_support = ssl_support; m_net_client.set_ssl(std::move(ssl_options));
m_ssl_private_key_and_certificate_path = private_key_and_certificate_path;
m_ssl_ca_file = std::move(ca_file);
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_ca_file, m_ssl_allowed_fingerprints, m_ssl_allow_any_cert);
} }
template<typename F> template<typename F>

View file

@ -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", 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>(), std::vector<std::string> access_control_origins = std::vector<std::string>(),
boost::optional<net_utils::http::login> user = boost::none, 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, net_utils::ssl_options_t ssl_options = net_utils::ssl_support_t::e_ssl_support_autodetect)
const std::pair<std::string, std::string> &private_key_and_certificate_path = {},
const std::string &ca_path = {},
std::vector<std::vector<uint8_t>> allowed_fingerprints = {},
bool allow_any_cert = false)
{ {
//set self as callback handler //set self as callback handler
@ -80,7 +76,7 @@ namespace epee
m_net_server.get_config_object().m_user = std::move(user); m_net_server.get_config_object().m_user = std::move(user);
MGINFO("Binding on " << bind_ip << ":" << bind_port); 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, ca_path, std::move(allowed_fingerprints), allow_any_cert); bool res = m_net_server.init_server(bind_port, bind_ip, std::move(ssl_options));
if(!res) if(!res)
{ {
LOG_ERROR("Failed to bind server"); LOG_ERROR("Failed to bind server");

View file

@ -101,10 +101,10 @@ namespace net_utils
inline inline
blocked_mode_client() : blocked_mode_client() :
m_io_service(), 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_connector(direct_connect{}),
m_ssl_socket(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_service, m_ctx.context)), m_ssl_socket(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_service, m_ctx)),
m_ssl_support(epee::net_utils::ssl_support_t::e_ssl_support_autodetect), m_ssl_options(epee::net_utils::ssl_support_t::e_ssl_support_autodetect),
m_initialized(true), m_initialized(true),
m_connected(false), m_connected(false),
m_deadline(m_io_service), m_deadline(m_io_service),
@ -136,13 +136,13 @@ namespace net_utils
catch(...) { /* ignore */ } 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 = {}, const std::string &ca_path = {}, 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) if (ssl_options)
m_ctx = {boost::asio::ssl::context(boost::asio::ssl::context::tlsv12), {}, {}}; m_ctx = ssl_options.create_context();
else else
m_ctx = create_ssl_context(private_key_and_certificate_path, ca_path, std::move(allowed_fingerprints), allow_any_cert); m_ctx = boost::asio::ssl::context(boost::asio::ssl::context::tlsv12);
m_ssl_support = ssl_support; m_ssl_options = std::move(ssl_options);
} }
inline inline
@ -174,7 +174,7 @@ namespace net_utils
// SSL Options // 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_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))
{ {
if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect) if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
{ {
@ -191,7 +191,7 @@ namespace net_utils
return CONNECT_FAILURE; 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; return CONNECT_SUCCESS;
}else }else
@ -212,21 +212,21 @@ namespace net_utils
// Set SSL options // Set SSL options
// disable sslv2 // disable sslv2
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. // 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) if (try_connect_result == CONNECT_FAILURE)
return false; 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) if (try_connect_result == CONNECT_NO_SSL)
{ {
MERROR("SSL handshake failed on an autodetect connection, reconnecting without 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; m_ssl_options.support = epee::net_utils::ssl_support_t::e_ssl_support_disabled;
if (try_connect(addr, port, timeout, m_ssl_support) != CONNECT_SUCCESS) if (try_connect(addr, port, timeout, m_ssl_options.support) != CONNECT_SUCCESS)
return false; return false;
} }
} }
@ -258,7 +258,7 @@ namespace net_utils
if(m_connected) if(m_connected)
{ {
m_connected = false; m_connected = false;
if(m_ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled) if(m_ssl_options)
shutdown_ssl(); shutdown_ssl();
m_ssl_socket->next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both); m_ssl_socket->next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both);
} }
@ -392,7 +392,7 @@ namespace net_utils
if (!m_connected || !m_ssl_socket->next_layer().is_open()) if (!m_connected || !m_ssl_socket->next_layer().is_open())
return false; return false;
if (ssl) 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; return true;
} }
@ -556,7 +556,7 @@ namespace net_utils
{ {
m_deadline.cancel(); m_deadline.cancel();
boost::system::error_code ec; 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(); shutdown_ssl();
m_ssl_socket->next_layer().cancel(ec); m_ssl_socket->next_layer().cancel(ec);
if(ec) if(ec)
@ -633,7 +633,7 @@ namespace net_utils
bool write(const void* data, size_t sz, boost::system::error_code& ec) bool write(const void* data, size_t sz, boost::system::error_code& ec)
{ {
bool success; 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); success = boost::asio::write(*m_ssl_socket, boost::asio::buffer(data, sz), ec);
else else
success = boost::asio::write(m_ssl_socket->next_layer(), boost::asio::buffer(data, sz), ec); success = boost::asio::write(m_ssl_socket->next_layer(), boost::asio::buffer(data, sz), ec);
@ -642,7 +642,7 @@ namespace net_utils
void async_write(const void* data, size_t sz, boost::system::error_code& ec) 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); boost::asio::async_write(*m_ssl_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
else else
boost::asio::async_write(m_ssl_socket->next_layer(), boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1); boost::asio::async_write(m_ssl_socket->next_layer(), boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
@ -650,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) 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); boost::asio::async_read(m_ssl_socket->next_layer(), boost::asio::buffer(buff, sz), transfer_at_least, hndlr);
else else
boost::asio::async_read(*m_ssl_socket, boost::asio::buffer(buff, sz), transfer_at_least, hndlr); boost::asio::async_read(*m_ssl_socket, boost::asio::buffer(buff, sz), transfer_at_least, hndlr);
@ -659,10 +659,10 @@ namespace net_utils
protected: protected:
boost::asio::io_service m_io_service; 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::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> m_ssl_socket;
std::function<connect_func> m_connector; 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_initialized;
bool m_connected; bool m_connected;
boost::asio::steady_timer m_deadline; boost::asio::steady_timer m_deadline;

View file

@ -46,23 +46,71 @@ namespace net_utils
e_ssl_support_enabled, e_ssl_support_enabled,
e_ssl_support_autodetect, e_ssl_support_autodetect,
}; };
struct ssl_context_t enum class ssl_verification_t : uint8_t
{ {
boost::asio::ssl::context context; none = 0, //!< Do not verify peer.
std::string ca_path; system_ca, //!< Verify peer via system ca only (do not inspect user certificates)
std::vector<std::vector<uint8_t>> allowed_fingerprints; user_certificates //!< Verify peer via user certificate(s) only.
bool allow_any_cert; };
};
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; }
//! 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;
bool handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket, boost::asio::ssl::stream_base::handshake_type type) const;
};
// https://security.stackexchange.com/questions/34780/checking-client-hello-for-https-classification // https://security.stackexchange.com/questions/34780/checking-client-hello-for-https-classification
constexpr size_t get_ssl_magic_size() { return 9; } constexpr size_t get_ssl_magic_size() { return 9; }
bool is_ssl(const unsigned char *data, size_t len); 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, const std::string &ca_path, std::vector<std::vector<uint8_t>> allowed_fingerprints, bool allow_any_cert); bool ssl_support_from_string(ssl_support_t &ssl, boost::string_ref s);
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);
} }
} }

View file

@ -65,6 +65,15 @@ namespace epee
namespace net_utils 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) std::string to_string(t_connection_type type)
{ {
if (type == e_connection_type_NET) 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; int connection_basic_pimpl::m_default_tos;
// methods: // 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") ), mI( new connection_basic_pimpl("peer") ),
strand_(GET_IO_SERVICE(sock)), 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_want_close_connection(false),
m_was_shutdown(false), m_was_shutdown(false),
m_ssl_support(ssl_support), m_ssl_support(ssl_support)
m_ssl_context(ssl_context)
{ {
// add nullptr checks if removed // 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); socket_.next_layer() = std::move(sock);
++(m_stats->sock_count); // increase the global counter ++(m_state->sock_count); // increase the global counter
mI->m_peer_number = m_stats->sock_number.fetch_add(1); // use, and increase the generated number mI->m_peer_number = m_state->sock_number.fetch_add(1); // use, and increase the generated number
std::string remote_addr_str = "?"; std::string remote_addr_str = "?";
try { boost::system::error_code e; remote_addr_str = socket().remote_endpoint(e).address().to_string(); } catch(...){} ; 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") ), mI( new connection_basic_pimpl("peer") ),
strand_(io_service), strand_(io_service),
socket_(io_service, ssl_context.context), socket_(io_service, get_context(m_state.get())),
m_want_close_connection(false), m_want_close_connection(false),
m_was_shutdown(false), m_was_shutdown(false),
m_ssl_support(ssl_support), m_ssl_support(ssl_support)
m_ssl_context(ssl_context)
{ {
// add nullptr checks if removed // 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 ++(m_state->sock_count); // increase the global counter
mI->m_peer_number = m_stats->sock_number.fetch_add(1); // use, and increase the generated number mI->m_peer_number = m_state->sock_number.fetch_add(1); // use, and increase the generated number
std::string remote_addr_str = "?"; std::string remote_addr_str = "?";
try { boost::system::error_code e; remote_addr_str = socket().remote_endpoint(e).address().to_string(); } catch(...){} ; 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) { connection_basic::~connection_basic() noexcept(false) {
--(m_stats->sock_count); --(m_state->sock_count);
std::string remote_addr_str = "?"; std::string remote_addr_str = "?";
try { boost::system::error_code e; remote_addr_str = socket().remote_endpoint(e).address().to_string(); } catch(...){} ; try { boost::system::error_code e; remote_addr_str = socket().remote_endpoint(e).address().to_string(); } catch(...){} ;

View file

@ -171,22 +171,34 @@ bool create_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert)
return true; return true;
} }
ssl_context_t create_ssl_context(const std::pair<std::string, std::string> &private_key_and_certificate_path, const std::string &ca_path, 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(ca_path), 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 // only allow tls v1.2 and up
ssl_context.context.set_options(boost::asio::ssl::context::default_workarounds); ssl_context.set_options(boost::asio::ssl::context::default_workarounds);
ssl_context.context.set_options(boost::asio::ssl::context::no_sslv2); ssl_context.set_options(boost::asio::ssl::context::no_sslv2);
ssl_context.context.set_options(boost::asio::ssl::context::no_sslv3); ssl_context.set_options(boost::asio::ssl::context::no_sslv3);
ssl_context.context.set_options(boost::asio::ssl::context::no_tlsv1); ssl_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::no_tlsv1_1);
// only allow a select handful of tls v1.3 and v1.2 ciphers to be used // 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 // 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"); 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_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 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); // https://stackoverflow.com/questions/22378442
@ -203,17 +215,25 @@ ssl_context_t create_ssl_context(const std::pair<std::string, std::string> &priv
SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION); SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
#endif #endif
if (!ssl_context.ca_path.empty()) switch (verification)
{ {
const boost::system::error_code err = load_ca_file(ssl_context.context, ssl_context.ca_path); case ssl_verification_t::system_ca:
if (err) ssl_context.set_default_verify_paths();
throw boost::system::system_error{err, "Failed to load user CA file at " + ssl_context.ca_path}; break;
case ssl_verification_t::user_certificates:
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;
} }
else if (allowed_fingerprints.empty())
ssl_context.context.set_default_verify_paths(); // only use system-CAs if no user-supplied cert info
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"); 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 (private_key_and_certificate_path.second.empty()) if (auth.private_key_path.empty())
{ {
EVP_PKEY *pkey; EVP_PKEY *pkey;
X509 *cert; X509 *cert;
@ -224,19 +244,15 @@ ssl_context_t create_ssl_context(const std::pair<std::string, std::string> &priv
EVP_PKEY_free(pkey); EVP_PKEY_free(pkey);
} }
else else
{ auth.use_ssl_certificate(ssl_context);
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;
return 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.use_private_key_file(private_key_path, 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_certificate_file(certificate_path, boost::asio::ssl::context::pem);
} }
bool is_ssl(const unsigned char *data, size_t len) bool is_ssl(const unsigned char *data, size_t len)
@ -259,10 +275,10 @@ bool is_ssl(const unsigned char *data, size_t len)
return false; return false;
} }
bool is_certificate_allowed(boost::asio::ssl::verify_context &ctx, const ssl_context_t &ssl_context) bool ssl_options_t::has_fingerprint(boost::asio::ssl::verify_context &ctx) const
{ {
// can we check the certificate against a list of fingerprints? // 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(); X509_STORE_CTX *sctx = ctx.native_handle();
if (!sctx) if (!sctx)
{ {
@ -289,15 +305,13 @@ bool is_certificate_allowed(boost::asio::ssl::verify_context &ctx, const ssl_con
// strip unnecessary bytes from the digest // strip unnecessary bytes from the digest
digest.resize(size); digest.resize(size);
// is the certificate fingerprint inside the list of allowed fingerprints? return std::binary_search(fingerprints_.begin(), fingerprints_.end(), digest);
if (std::find(ssl_context.allowed_fingerprints.begin(), ssl_context.allowed_fingerprints.end(), digest) != ssl_context.allowed_fingerprints.end())
return true;
} }
return ssl_context.allowed_fingerprints.empty() && ssl_context.ca_path.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
{ {
bool verified = false; bool verified = false;
socket.next_layer().set_option(boost::asio::ip::tcp::no_delay(true)); socket.next_layer().set_option(boost::asio::ip::tcp::no_delay(true));
@ -306,8 +320,8 @@ bool ssl_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socke
no expected hostname for server to verify against. If server doesn't have no expected hostname for server to verify against. If server doesn't have
specific whitelisted certificates for client, don't require client to specific whitelisted certificates for client, don't require client to
send certificate at all. */ send certificate at all. */
const bool no_verification = ssl_context.allow_any_cert || const bool no_verification = verification == ssl_verification_t::none ||
(type == boost::asio::ssl::stream_base::server && ssl_context.allowed_fingerprints.empty() && ssl_context.ca_path.empty()); (type == boost::asio::ssl::stream_base::server && fingerprints_.empty() && ca_path.empty());
/* According to OpenSSL documentation (and SSL specifications), server must /* According to OpenSSL documentation (and SSL specifications), server must
always send certificate unless "anonymous" cipher mode is used which are always send certificate unless "anonymous" cipher mode is used which are
@ -321,7 +335,7 @@ bool ssl_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socke
{ {
// preverified means it passed system or user CA check. System CA is never loaded // preverified means it passed system or user CA check. System CA is never loaded
// when fingerprints are whitelisted. // when fingerprints are whitelisted.
if (!preverified && !is_certificate_allowed(ctx, ssl_context)) { if (!preverified && verification == ssl_verification_t::user_certificates && !has_fingerprint(ctx)) {
MERROR("Certificate is not in the allowed list, connection droppped"); MERROR("Certificate is not in the allowed list, connection droppped");
return false; return false;
} }
@ -337,7 +351,7 @@ bool ssl_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socke
MERROR("handshake failed, connection dropped: " << ec.message()); MERROR("handshake failed, connection dropped: " << ec.message());
return false; return false;
} }
if (!no_verification && !verified) if (verification == ssl_verification_t::none && !verified)
{ {
MERROR("Peer did not provide a certificate in the allowed list, connection dropped"); MERROR("Peer did not provide a certificate in the allowed list, connection dropped");
return false; return false;

View file

@ -149,21 +149,29 @@ namespace cryptonote
if (rpc_config->login) if (rpc_config->login)
http_login.emplace(std::move(rpc_config->login->username), std::move(rpc_config->login->password).password()); http_login.emplace(std::move(rpc_config->login->username), std::move(rpc_config->login->password).password());
const std::string ssl_private_key = command_line::get_arg(vm, arg_rpc_ssl_private_key); epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect;
const std::string ssl_certificate = command_line::get_arg(vm, arg_rpc_ssl_certificate); if (command_line::get_arg(vm, arg_rpc_ssl_allow_any_cert))
std::string ssl_ca_path = command_line::get_arg(vm, arg_rpc_ssl_ca_certificates); ssl_options.verification = epee::net_utils::ssl_verification_t::none;
else
{
std::string ssl_ca_path = command_line::get_arg(vm, arg_rpc_ssl_ca_certificates);
const std::vector<std::string> ssl_allowed_fingerprint_strings = command_line::get_arg(vm, arg_rpc_ssl_allowed_fingerprints);
std::vector<std::vector<uint8_t>> ssl_allowed_fingerprints{ ssl_allowed_fingerprint_strings.size() };
std::transform(ssl_allowed_fingerprint_strings.begin(), ssl_allowed_fingerprint_strings.end(), ssl_allowed_fingerprints.begin(), epee::from_hex::vector);
const std::vector<std::string> ssl_allowed_fingerprint_strings = command_line::get_arg(vm, arg_rpc_ssl_allowed_fingerprints); if (!ssl_ca_path.empty() || !ssl_allowed_fingerprints.empty())
std::vector<std::vector<uint8_t>> ssl_allowed_fingerprints{ ssl_allowed_fingerprint_strings.size() }; ssl_options = epee::net_utils::ssl_options_t{std::move(ssl_allowed_fingerprints), std::move(ssl_ca_path)};
std::transform(ssl_allowed_fingerprint_strings.begin(), ssl_allowed_fingerprint_strings.end(), ssl_allowed_fingerprints.begin(), epee::from_hex::vector); }
const bool ssl_allow_any_cert = command_line::get_arg(vm, arg_rpc_ssl_allow_any_cert);
ssl_options.auth = epee::net_utils::ssl_authentication_t{
command_line::get_arg(vm, arg_rpc_ssl_private_key), command_line::get_arg(vm, arg_rpc_ssl_certificate)
};
// user specified CA file or fingeprints implies enabled SSL by default // user specified CA file or fingeprints implies enabled SSL by default
epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_enabled; if (ssl_options.verification != epee::net_utils::ssl_verification_t::user_certificates || !command_line::is_arg_defaulted(vm, arg_rpc_ssl))
if ((ssl_allowed_fingerprints.empty() && ssl_ca_path.empty()) || !command_line::is_arg_defaulted(vm, arg_rpc_ssl))
{ {
const std::string ssl = command_line::get_arg(vm, arg_rpc_ssl); const std::string ssl = command_line::get_arg(vm, arg_rpc_ssl);
if (!epee::net_utils::ssl_support_from_string(ssl_support, ssl)) if (!epee::net_utils::ssl_support_from_string(ssl_options.support, ssl))
{ {
MFATAL("Invalid RPC SSL support: " << ssl); MFATAL("Invalid RPC SSL support: " << ssl);
return false; return false;
@ -172,8 +180,7 @@ namespace cryptonote
auto rng = [](size_t len, uint8_t *ptr){ return crypto::rand(len, ptr); }; auto rng = [](size_t len, uint8_t *ptr){ return crypto::rand(len, ptr); };
return epee::http_server_impl_base<core_rpc_server, connection_context>::init( return epee::http_server_impl_base<core_rpc_server, connection_context>::init(
rng, std::move(port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login), rng, std::move(port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login), std::move(ssl_options)
ssl_support, std::make_pair(ssl_private_key, ssl_certificate), std::move(ssl_ca_path), std::move(ssl_allowed_fingerprints), ssl_allow_any_cert
); );
} }
//------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------

View file

@ -327,13 +327,29 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
auto daemon_ssl = command_line::get_arg(vm, opts.daemon_ssl); auto daemon_ssl = command_line::get_arg(vm, opts.daemon_ssl);
// user specified CA file or fingeprints implies enabled SSL by default // user specified CA file or fingeprints implies enabled SSL by default
epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_enabled; epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
if ((daemon_ssl_ca_file.empty() && daemon_ssl_allowed_fingerprints.empty()) || !command_line::is_arg_defaulted(vm, opts.daemon_ssl)) if (command_line::get_arg(vm, opts.daemon_ssl_allow_any_cert))
ssl_options.verification = epee::net_utils::ssl_verification_t::none;
else if (!daemon_ssl_ca_file.empty() || !daemon_ssl_allowed_fingerprints.empty())
{ {
THROW_WALLET_EXCEPTION_IF(!epee::net_utils::ssl_support_from_string(ssl_support, daemon_ssl), tools::error::wallet_internal_error, std::vector<std::vector<uint8_t>> ssl_allowed_fingerprints{ daemon_ssl_allowed_fingerprints.size() };
std::transform(daemon_ssl_allowed_fingerprints.begin(), daemon_ssl_allowed_fingerprints.end(), ssl_allowed_fingerprints.begin(), epee::from_hex::vector);
ssl_options = epee::net_utils::ssl_options_t{
std::move(ssl_allowed_fingerprints), std::move(daemon_ssl_ca_file)
};
}
if (ssl_options.verification != epee::net_utils::ssl_verification_t::user_certificates || !command_line::is_arg_defaulted(vm, opts.daemon_ssl))
{
THROW_WALLET_EXCEPTION_IF(!epee::net_utils::ssl_support_from_string(ssl_options.support, daemon_ssl), tools::error::wallet_internal_error,
tools::wallet2::tr("Invalid argument for ") + std::string(opts.daemon_ssl.name)); tools::wallet2::tr("Invalid argument for ") + std::string(opts.daemon_ssl.name));
} }
ssl_options.auth = epee::net_utils::ssl_authentication_t{
std::move(daemon_ssl_private_key), std::move(daemon_ssl_certificate)
};
THROW_WALLET_EXCEPTION_IF(!daemon_address.empty() && !daemon_host.empty() && 0 != daemon_port, THROW_WALLET_EXCEPTION_IF(!daemon_address.empty() && !daemon_host.empty() && 0 != daemon_port,
tools::error::wallet_internal_error, tools::wallet2::tr("can't specify daemon host or port more than once")); tools::error::wallet_internal_error, tools::wallet2::tr("can't specify daemon host or port more than once"));
@ -421,11 +437,8 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
catch (const std::exception &e) { } catch (const std::exception &e) { }
} }
std::vector<std::vector<uint8_t>> ssl_allowed_fingerprints{ daemon_ssl_allowed_fingerprints.size() };
std::transform(daemon_ssl_allowed_fingerprints.begin(), daemon_ssl_allowed_fingerprints.end(), ssl_allowed_fingerprints.begin(), epee::from_hex::vector);
std::unique_ptr<tools::wallet2> wallet(new tools::wallet2(nettype, kdf_rounds, unattended)); std::unique_ptr<tools::wallet2> wallet(new tools::wallet2(nettype, kdf_rounds, unattended));
wallet->init(std::move(daemon_address), std::move(login), std::move(proxy), 0, *trusted_daemon, ssl_support, std::make_pair(daemon_ssl_private_key, daemon_ssl_certificate), std::move(daemon_ssl_ca_file), ssl_allowed_fingerprints, daemon_ssl_allow_any_cert); wallet->init(std::move(daemon_address), std::move(login), std::move(proxy), 0, *trusted_daemon, std::move(ssl_options));
boost::filesystem::path ringdb_path = command_line::get_arg(vm, opts.shared_ringdb_dir); boost::filesystem::path ringdb_path = command_line::get_arg(vm, opts.shared_ringdb_dir);
wallet->set_ring_database(ringdb_path.string()); wallet->set_ring_database(ringdb_path.string());
wallet->get_message_store().set_options(vm); wallet->get_message_store().set_options(vm);
@ -1148,10 +1161,7 @@ std::unique_ptr<wallet2> wallet2::make_dummy(const boost::program_options::varia
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool wallet2::set_daemon(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, bool trusted_daemon, bool wallet2::set_daemon(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, bool trusted_daemon, epee::net_utils::ssl_options_t ssl_options)
epee::net_utils::ssl_support_t ssl_support, const std::pair<std::string, std::string> &private_key_and_certificate_path,
std::string ca_file, const std::vector<std::vector<uint8_t>> &allowed_fingerprints,
bool allow_any_cert)
{ {
if(m_http_client.is_connected()) if(m_http_client.is_connected())
m_http_client.disconnect(); m_http_client.disconnect();
@ -1160,17 +1170,17 @@ bool wallet2::set_daemon(std::string daemon_address, boost::optional<epee::net_u
m_trusted_daemon = trusted_daemon; m_trusted_daemon = trusted_daemon;
MINFO("setting daemon to " << get_daemon_address()); MINFO("setting daemon to " << get_daemon_address());
return m_http_client.set_server(get_daemon_address(), get_daemon_login(), ssl_support, private_key_and_certificate_path, std::move(ca_file), allowed_fingerprints, allow_any_cert); return m_http_client.set_server(get_daemon_address(), get_daemon_login(), std::move(ssl_options));
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool wallet2::init(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, boost::asio::ip::tcp::endpoint proxy, uint64_t upper_transaction_weight_limit, bool trusted_daemon, epee::net_utils::ssl_support_t ssl_support, const std::pair<std::string, std::string> &private_key_and_certificate_path, std::string ca_file, const std::vector<std::vector<uint8_t>> &allowed_fingerprints, bool allow_any_cert) bool wallet2::init(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, boost::asio::ip::tcp::endpoint proxy, uint64_t upper_transaction_weight_limit, bool trusted_daemon, epee::net_utils::ssl_options_t ssl_options)
{ {
m_checkpoints.init_default_checkpoints(m_nettype); m_checkpoints.init_default_checkpoints(m_nettype);
m_is_initialized = true; m_is_initialized = true;
m_upper_transaction_weight_limit = upper_transaction_weight_limit; m_upper_transaction_weight_limit = upper_transaction_weight_limit;
if (proxy != boost::asio::ip::tcp::endpoint{}) if (proxy != boost::asio::ip::tcp::endpoint{})
m_http_client.set_connector(net::socks::connector{std::move(proxy)}); m_http_client.set_connector(net::socks::connector{std::move(proxy)});
return set_daemon(daemon_address, daemon_login, trusted_daemon, ssl_support, private_key_and_certificate_path, std::move(ca_file), allowed_fingerprints, allow_any_cert); return set_daemon(daemon_address, daemon_login, trusted_daemon, std::move(ssl_options));
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool wallet2::is_deterministic() const bool wallet2::is_deterministic() const

View file

@ -689,16 +689,10 @@ namespace tools
boost::asio::ip::tcp::endpoint proxy = {}, boost::asio::ip::tcp::endpoint proxy = {},
uint64_t upper_transaction_weight_limit = 0, uint64_t upper_transaction_weight_limit = 0,
bool trusted_daemon = true, bool trusted_daemon = true,
epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
const std::pair<std::string, std::string> &private_key_and_certificate_path = {},
std::string ca_file = {}, const std::vector<std::vector<uint8_t>> &allowed_fingerprints = {},
bool allow_any_cert = false);
bool set_daemon(std::string daemon_address = "http://localhost:8080", bool set_daemon(std::string daemon_address = "http://localhost:8080",
boost::optional<epee::net_utils::http::login> daemon_login = boost::none, bool trusted_daemon = true, boost::optional<epee::net_utils::http::login> daemon_login = boost::none, bool trusted_daemon = true,
epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
const std::pair<std::string, std::string> &private_key_and_certificate_path = {},
std::string ca_file = {}, const std::vector<std::vector<uint8_t>> &allowed_fingerprints = {},
bool allow_any_cert = false);
void stop() { m_run.store(false, std::memory_order_relaxed); m_message_store.stop(); } void stop() { m_run.store(false, std::memory_order_relaxed); m_message_store.stop(); }

View file

@ -250,20 +250,31 @@ namespace tools
auto rpc_ssl_ca_file = command_line::get_arg(vm, arg_rpc_ssl_ca_certificates); auto rpc_ssl_ca_file = command_line::get_arg(vm, arg_rpc_ssl_ca_certificates);
auto rpc_ssl_allowed_fingerprints = command_line::get_arg(vm, arg_rpc_ssl_allowed_fingerprints); auto rpc_ssl_allowed_fingerprints = command_line::get_arg(vm, arg_rpc_ssl_allowed_fingerprints);
auto rpc_ssl = command_line::get_arg(vm, arg_rpc_ssl); auto rpc_ssl = command_line::get_arg(vm, arg_rpc_ssl);
epee::net_utils::ssl_support_t rpc_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_enabled; epee::net_utils::ssl_options_t rpc_ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
if (!rpc_ssl_ca_file.empty() || !rpc_ssl_allowed_fingerprints.empty())
{
std::vector<std::vector<uint8_t>> allowed_fingerprints{ rpc_ssl_allowed_fingerprints.size() };
std::transform(rpc_ssl_allowed_fingerprints.begin(), rpc_ssl_allowed_fingerprints.end(), allowed_fingerprints.begin(), epee::from_hex::vector);
rpc_ssl_options = epee::net_utils::ssl_options_t{
std::move(allowed_fingerprints), std::move(rpc_ssl_ca_file)
};
}
// user specified CA file or fingeprints implies enabled SSL by default // user specified CA file or fingeprints implies enabled SSL by default
if ((rpc_ssl_ca_file.empty() && rpc_ssl_allowed_fingerprints.empty()) || !command_line::is_arg_defaulted(vm, arg_rpc_ssl)) if (rpc_ssl_options.verification != epee::net_utils::ssl_verification_t::user_certificates || !command_line::is_arg_defaulted(vm, arg_rpc_ssl))
{ {
if (!epee::net_utils::ssl_support_from_string(rpc_ssl_support, rpc_ssl)) if (!epee::net_utils::ssl_support_from_string(rpc_ssl_options.support, rpc_ssl))
{ {
MERROR("Invalid argument for " << std::string(arg_rpc_ssl.name)); MERROR("Invalid argument for " << std::string(arg_rpc_ssl.name));
return false; return false;
} }
} }
std::vector<std::vector<uint8_t>> allowed_fingerprints{ rpc_ssl_allowed_fingerprints.size() }; rpc_ssl_options.auth = epee::net_utils::ssl_authentication_t{
std::transform(rpc_ssl_allowed_fingerprints.begin(), rpc_ssl_allowed_fingerprints.end(), allowed_fingerprints.begin(), epee::from_hex::vector); std::move(rpc_ssl_private_key), std::move(rpc_ssl_certificate)
};
m_auto_refresh_period = DEFAULT_AUTO_REFRESH_PERIOD; m_auto_refresh_period = DEFAULT_AUTO_REFRESH_PERIOD;
m_last_auto_refresh_time = boost::posix_time::min_date_time; m_last_auto_refresh_time = boost::posix_time::min_date_time;
@ -272,7 +283,7 @@ namespace tools
auto rng = [](size_t len, uint8_t *ptr) { return crypto::rand(len, ptr); }; auto rng = [](size_t len, uint8_t *ptr) { return crypto::rand(len, ptr); };
return epee::http_server_impl_base<wallet_rpc_server, connection_context>::init( return epee::http_server_impl_base<wallet_rpc_server, connection_context>::init(
rng, std::move(bind_port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login), rng, std::move(bind_port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login),
rpc_ssl_support, std::make_pair(rpc_ssl_private_key, rpc_ssl_certificate), std::move(rpc_ssl_ca_file), std::move(allowed_fingerprints) std::move(rpc_ssl_options)
); );
} }
//------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------
@ -4049,8 +4060,8 @@ namespace tools
er.message = "Command unavailable in restricted mode."; er.message = "Command unavailable in restricted mode.";
return false; return false;
} }
epee::net_utils::ssl_support_t ssl_support; epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
if (!epee::net_utils::ssl_support_from_string(ssl_support, req.ssl_support)) if (!epee::net_utils::ssl_support_from_string(ssl_options.support, req.ssl_support))
{ {
er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION; er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION;
er.message = std::string("Invalid ssl support mode"); er.message = std::string("Invalid ssl support mode");
@ -4065,7 +4076,16 @@ namespace tools
for (auto c: fp) for (auto c: fp)
v.push_back(c); v.push_back(c);
} }
if (!m_wallet->set_daemon(req.address, boost::none, req.trusted, ssl_support, std::make_pair(req.ssl_private_key_path, req.ssl_certificate_path), std::move(req.ssl_ca_file), ssl_allowed_fingerprints, req.ssl_allow_any_cert)) if (req.ssl_allow_any_cert)
ssl_options.verification = epee::net_utils::ssl_verification_t::none;
else if (!ssl_allowed_fingerprints.empty() || !req.ssl_ca_file.empty())
ssl_options = epee::net_utils::ssl_options_t{std::move(ssl_allowed_fingerprints), std::move(req.ssl_ca_file)};
ssl_options.auth = epee::net_utils::ssl_authentication_t{
std::move(req.ssl_private_key_path), std::move(req.ssl_certificate_path)
};
if (!m_wallet->set_daemon(req.address, boost::none, req.trusted, std::move(ssl_options)))
{ {
er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION; er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION;
er.message = std::string("Unable to set daemon"); er.message = std::string("Unable to set daemon");