mirror of
https://codeberg.org/anoncontributorxmr/monero.git
synced 2024-11-26 17:32:33 +00:00
Merge pull request #5320
2e578b82
Enabling daemon-rpc SSL now requires non-system CA verification (Lee Clagett)d58f3682
Require manual override for user chain certificates. (Lee Clagett)97cd1fa9
Only check top-level certificate against fingerprint list. (Lee Clagett)7c388fb3
Call `use_certificate_chain_file` instead of `use_certificate_file` (Lee Clagett)eca0fea4
Perform RFC 2818 hostname verification in client SSL handshakes (Lee Clagett)0416764c
Require server verification when SSL is enabled. (Lee Clagett)96d602ac
Add `verify_fail_if_no_cert` option for proper client authentication (Lee Clagett)21eb1b07
Pass SSL arguments via one class and use shared_ptr instead of reference (Lee Clagett)1f5ed328
Change default SSL to "enabled" if user specifies fingerprint/certificate (Lee Clagett)f18a069f
Do not require client certificate unless server has some whitelisted. (Lee Clagett)a3b02848
Change SSL certificate file list to OpenSSL builtin load_verify_location (Lee Clagett)
This commit is contained in:
commit
7c85f3b28e
15 changed files with 475 additions and 323 deletions
|
@ -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::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", 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", 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,10 +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;
|
|
||||||
std::list<std::string> m_allowed_certificates;
|
|
||||||
|
|
||||||
}; // class <>boosted_tcp_server
|
}; // class <>boosted_tcp_server
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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::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();
|
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, allowed_certificates, 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::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;
|
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, allowed_certificates, 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());
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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::list<std::string> m_ssl_allowed_certificates;
|
|
||||||
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 = {}, 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{};
|
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, 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;
|
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);
|
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_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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
|
|
|
@ -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 = {},
|
|
||||||
std::list<std::string> allowed_certificates = {},
|
|
||||||
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, 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)
|
if(!res)
|
||||||
{
|
{
|
||||||
LOG_ERROR("Failed to bind server");
|
LOG_ERROR("Failed to bind server");
|
||||||
|
|
|
@ -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 = {}, 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)
|
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, std::move(allowed_certificates), 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, addr))
|
||||||
{
|
{
|
||||||
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,23 +212,21 @@ namespace net_utils
|
||||||
|
|
||||||
// Set SSL options
|
// Set SSL options
|
||||||
// disable sslv2
|
// disable sslv2
|
||||||
m_ctx.context.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2);
|
m_ssl_socket.reset(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_service, m_ctx));
|
||||||
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));
|
|
||||||
|
|
||||||
// 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,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);
|
||||||
}
|
}
|
||||||
|
@ -394,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,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)
|
||||||
|
@ -635,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);
|
||||||
|
@ -644,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);
|
||||||
|
@ -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)
|
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);
|
||||||
|
@ -661,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;
|
||||||
|
|
|
@ -31,10 +31,11 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <vector>
|
||||||
#include <boost/utility/string_ref.hpp>
|
#include <boost/utility/string_ref.hpp>
|
||||||
#include <boost/asio/ip/tcp.hpp>
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
#include <boost/asio/ssl.hpp>
|
#include <boost/asio/ssl.hpp>
|
||||||
|
#include <boost/system/error_code.hpp>
|
||||||
|
|
||||||
namespace epee
|
namespace epee
|
||||||
{
|
{
|
||||||
|
@ -45,23 +46,93 @@ 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::list<std::string> allowed_certificates;
|
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 specific (non-chain) certificate(s) only.
|
||||||
bool allow_any_cert;
|
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
|
// 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, std::list<std::string> allowed_certificates, 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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(...){} ;
|
||||||
|
|
|
@ -77,6 +77,21 @@ namespace
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
using openssl_bignum = std::unique_ptr<BIGNUM, openssl_bignum_free>;
|
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
|
namespace epee
|
||||||
|
@ -84,6 +99,7 @@ namespace epee
|
||||||
namespace net_utils
|
namespace net_utils
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/256405/programmatically-create-x509-certificate-using-openssl
|
// https://stackoverflow.com/questions/256405/programmatically-create-x509-certificate-using-openssl
|
||||||
bool create_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert)
|
bool create_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert)
|
||||||
{
|
{
|
||||||
|
@ -155,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, 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
|
// 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
|
||||||
|
@ -186,10 +214,29 @@ ssl_context_t create_ssl_context(const std::pair<std::string, std::string> &priv
|
||||||
#ifdef SSL_OP_NO_COMPRESSION
|
#ifdef SSL_OP_NO_COMPRESSION
|
||||||
SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
|
SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
|
||||||
#endif
|
#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");
|
switch (verification)
|
||||||
if (private_key_and_certificate_path.second.empty())
|
{
|
||||||
|
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;
|
EVP_PKEY *pkey;
|
||||||
X509 *cert;
|
X509 *cert;
|
||||||
|
@ -200,19 +247,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_chain_file(certificate_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_ssl(const unsigned char *data, size_t len)
|
bool is_ssl(const unsigned char *data, size_t len)
|
||||||
|
@ -235,23 +278,44 @@ 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_strong_verification(boost::string_ref host) const noexcept
|
||||||
{
|
{
|
||||||
X509_STORE_CTX *sctx = ctx.native_handle();
|
// onion and i2p addresses contain information about the server cert
|
||||||
if (!sctx)
|
// which both authenticates and encrypts
|
||||||
|
if (host.ends_with(".onion") || host.ends_with(".i2p"))
|
||||||
|
return true;
|
||||||
|
switch (verification)
|
||||||
{
|
{
|
||||||
MERROR("Error getting verify_context handle");
|
default:
|
||||||
return false;
|
case ssl_verification_t::none:
|
||||||
}
|
case ssl_verification_t::system_ca:
|
||||||
X509 *cert =X509_STORE_CTX_get_current_cert(sctx);
|
return false;
|
||||||
if (!cert)
|
case ssl_verification_t::user_certificates:
|
||||||
{
|
case ssl_verification_t::user_ca:
|
||||||
MERROR("No certificate found in verify_context");
|
break;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
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?
|
// 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
|
// buffer for the certificate digest and the size of the result
|
||||||
std::vector<uint8_t> digest(EVP_MAX_MD_SIZE);
|
std::vector<uint8_t> digest(EVP_MAX_MD_SIZE);
|
||||||
unsigned int size{ 0 };
|
unsigned int size{ 0 };
|
||||||
|
@ -265,74 +329,63 @@ 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ssl_context.allowed_certificates.empty()) {
|
return false;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if either checklist is non-empty we must have failed it
|
|
||||||
return ssl_context.allowed_fingerprints.empty() && ssl_context.allowed_certificates.empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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.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());
|
// preverified means it passed system or user CA check. System CA is never loaded
|
||||||
const int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle());
|
// when fingerprints are whitelisted.
|
||||||
if (err != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || depth != 0)
|
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");
|
// autodetect will reconnect without SSL - warn and keep connection encrypted
|
||||||
return false;
|
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");
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
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;
|
|
||||||
});
|
|
||||||
|
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
socket.handshake(type, ec);
|
socket.handshake(type, ec);
|
||||||
if (ec)
|
if (ec)
|
||||||
{
|
{
|
||||||
MERROR("handshake failed, connection dropped: " << ec.message());
|
MERROR("SSL 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");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MDEBUG("SSL handshake success");
|
MDEBUG("SSL handshake success");
|
||||||
|
|
|
@ -91,7 +91,7 @@ namespace cryptonote
|
||||||
command_line::add_arg(desc, arg_rpc_ssl);
|
command_line::add_arg(desc, arg_rpc_ssl);
|
||||||
command_line::add_arg(desc, arg_rpc_ssl_private_key);
|
command_line::add_arg(desc, arg_rpc_ssl_private_key);
|
||||||
command_line::add_arg(desc, arg_rpc_ssl_certificate);
|
command_line::add_arg(desc, arg_rpc_ssl_certificate);
|
||||||
command_line::add_arg(desc, arg_rpc_ssl_allowed_certificates);
|
command_line::add_arg(desc, arg_rpc_ssl_ca_certificates);
|
||||||
command_line::add_arg(desc, arg_rpc_ssl_allowed_fingerprints);
|
command_line::add_arg(desc, arg_rpc_ssl_allowed_fingerprints);
|
||||||
command_line::add_arg(desc, arg_rpc_ssl_allow_any_cert);
|
command_line::add_arg(desc, arg_rpc_ssl_allow_any_cert);
|
||||||
command_line::add_arg(desc, arg_bootstrap_daemon_address);
|
command_line::add_arg(desc, arg_bootstrap_daemon_address);
|
||||||
|
@ -149,36 +149,38 @@ 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());
|
||||||
|
|
||||||
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_autodetect;
|
||||||
const std::string ssl = command_line::get_arg(vm, arg_rpc_ssl);
|
if (command_line::get_arg(vm, arg_rpc_ssl_allow_any_cert))
|
||||||
if (!epee::net_utils::ssl_support_from_string(ssl_support, ssl))
|
ssl_options.verification = epee::net_utils::ssl_verification_t::none;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
MFATAL("Invalid RPC SSL support: " << ssl);
|
std::string ssl_ca_path = command_line::get_arg(vm, arg_rpc_ssl_ca_certificates);
|
||||||
return false;
|
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);
|
||||||
|
|
||||||
|
if (!ssl_ca_path.empty() || !ssl_allowed_fingerprints.empty())
|
||||||
|
ssl_options = epee::net_utils::ssl_options_t{std::move(ssl_allowed_fingerprints), std::move(ssl_ca_path)};
|
||||||
}
|
}
|
||||||
const std::string ssl_private_key = command_line::get_arg(vm, arg_rpc_ssl_private_key);
|
|
||||||
const std::string ssl_certificate = command_line::get_arg(vm, arg_rpc_ssl_certificate);
|
ssl_options.auth = epee::net_utils::ssl_authentication_t{
|
||||||
const std::vector<std::string> ssl_allowed_certificate_paths = command_line::get_arg(vm, arg_rpc_ssl_allowed_certificates);
|
command_line::get_arg(vm, arg_rpc_ssl_private_key), command_line::get_arg(vm, arg_rpc_ssl_certificate)
|
||||||
std::list<std::string> ssl_allowed_certificates;
|
};
|
||||||
for (const std::string &path: ssl_allowed_certificate_paths)
|
|
||||||
|
// user specified CA file or fingeprints implies enabled SSL by default
|
||||||
|
if (ssl_options.verification != epee::net_utils::ssl_verification_t::user_certificates || !command_line::is_arg_defaulted(vm, arg_rpc_ssl))
|
||||||
{
|
{
|
||||||
ssl_allowed_certificates.push_back({});
|
const std::string ssl = command_line::get_arg(vm, arg_rpc_ssl);
|
||||||
if (!epee::file_io_utils::load_file_to_string(path, ssl_allowed_certificates.back()))
|
if (!epee::net_utils::ssl_support_from_string(ssl_options.support, ssl))
|
||||||
{
|
{
|
||||||
MERROR("Failed to load certificate: " << path);
|
MFATAL("Invalid RPC SSL support: " << ssl);
|
||||||
ssl_allowed_certificates.back() = std::string();
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 bool ssl_allow_any_cert = command_line::get_arg(vm, arg_rpc_ssl_allow_any_cert);
|
|
||||||
|
|
||||||
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_allowed_certificates), std::move(ssl_allowed_fingerprints), ssl_allow_any_cert
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
@ -2408,9 +2410,9 @@ namespace cryptonote
|
||||||
, ""
|
, ""
|
||||||
};
|
};
|
||||||
|
|
||||||
const command_line::arg_descriptor<std::vector<std::string>> core_rpc_server::arg_rpc_ssl_allowed_certificates = {
|
const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_ssl_ca_certificates = {
|
||||||
"rpc-ssl-allowed-certificates"
|
"rpc-ssl-ca-certificates"
|
||||||
, "List of paths to PEM format certificates of allowed peers (all allowed if empty)"
|
, "Path to file containing concatenated PEM format certificate(s) to replace system CA(s)."
|
||||||
};
|
};
|
||||||
|
|
||||||
const command_line::arg_descriptor<std::vector<std::string>> core_rpc_server::arg_rpc_ssl_allowed_fingerprints = {
|
const command_line::arg_descriptor<std::vector<std::string>> core_rpc_server::arg_rpc_ssl_allowed_fingerprints = {
|
||||||
|
@ -2420,7 +2422,7 @@ namespace cryptonote
|
||||||
|
|
||||||
const command_line::arg_descriptor<bool> core_rpc_server::arg_rpc_ssl_allow_any_cert = {
|
const command_line::arg_descriptor<bool> core_rpc_server::arg_rpc_ssl_allow_any_cert = {
|
||||||
"rpc-ssl-allow-any-cert"
|
"rpc-ssl-allow-any-cert"
|
||||||
, "Allow any peer certificate, rather than just those on the allowed list"
|
, "Allow any peer certificate"
|
||||||
, false
|
, false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ namespace cryptonote
|
||||||
static const command_line::arg_descriptor<std::string> arg_rpc_ssl;
|
static const command_line::arg_descriptor<std::string> arg_rpc_ssl;
|
||||||
static const command_line::arg_descriptor<std::string> arg_rpc_ssl_private_key;
|
static const command_line::arg_descriptor<std::string> arg_rpc_ssl_private_key;
|
||||||
static const command_line::arg_descriptor<std::string> arg_rpc_ssl_certificate;
|
static const command_line::arg_descriptor<std::string> arg_rpc_ssl_certificate;
|
||||||
static const command_line::arg_descriptor<std::vector<std::string>> arg_rpc_ssl_allowed_certificates;
|
static const command_line::arg_descriptor<std::string> arg_rpc_ssl_ca_certificates;
|
||||||
static const command_line::arg_descriptor<std::vector<std::string>> arg_rpc_ssl_allowed_fingerprints;
|
static const command_line::arg_descriptor<std::vector<std::string>> arg_rpc_ssl_allowed_fingerprints;
|
||||||
static const command_line::arg_descriptor<bool> arg_rpc_ssl_allow_any_cert;
|
static const command_line::arg_descriptor<bool> arg_rpc_ssl_allow_any_cert;
|
||||||
static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_address;
|
static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_address;
|
||||||
|
|
|
@ -243,9 +243,10 @@ struct options {
|
||||||
const command_line::arg_descriptor<std::string> daemon_ssl = {"daemon-ssl", tools::wallet2::tr("Enable SSL on daemon RPC connections: enabled|disabled|autodetect"), "autodetect"};
|
const command_line::arg_descriptor<std::string> daemon_ssl = {"daemon-ssl", tools::wallet2::tr("Enable SSL on daemon RPC connections: enabled|disabled|autodetect"), "autodetect"};
|
||||||
const command_line::arg_descriptor<std::string> daemon_ssl_private_key = {"daemon-ssl-private-key", tools::wallet2::tr("Path to a PEM format private key"), ""};
|
const command_line::arg_descriptor<std::string> daemon_ssl_private_key = {"daemon-ssl-private-key", tools::wallet2::tr("Path to a PEM format private key"), ""};
|
||||||
const command_line::arg_descriptor<std::string> daemon_ssl_certificate = {"daemon-ssl-certificate", tools::wallet2::tr("Path to a PEM format certificate"), ""};
|
const command_line::arg_descriptor<std::string> daemon_ssl_certificate = {"daemon-ssl-certificate", tools::wallet2::tr("Path to a PEM format certificate"), ""};
|
||||||
const command_line::arg_descriptor<std::vector<std::string>> daemon_ssl_allowed_certificates = {"daemon-ssl-allowed-certificates", tools::wallet2::tr("List of paths to PEM format certificates of allowed RPC servers")};
|
const command_line::arg_descriptor<std::string> daemon_ssl_ca_certificates = {"daemon-ssl-ca-certificates", tools::wallet2::tr("Path to file containing concatenated PEM format certificate(s) to replace system CA(s).")};
|
||||||
const command_line::arg_descriptor<std::vector<std::string>> daemon_ssl_allowed_fingerprints = {"daemon-ssl-allowed-fingerprints", tools::wallet2::tr("List of valid fingerprints of allowed RPC servers")};
|
const command_line::arg_descriptor<std::vector<std::string>> daemon_ssl_allowed_fingerprints = {"daemon-ssl-allowed-fingerprints", tools::wallet2::tr("List of valid fingerprints of allowed RPC servers")};
|
||||||
const command_line::arg_descriptor<bool> daemon_ssl_allow_any_cert = {"daemon-ssl-allow-any-cert", tools::wallet2::tr("Allow any SSL certificate from the daemon"), false};
|
const command_line::arg_descriptor<bool> daemon_ssl_allow_any_cert = {"daemon-ssl-allow-any-cert", tools::wallet2::tr("Allow any SSL certificate from the daemon"), false};
|
||||||
|
const command_line::arg_descriptor<bool> daemon_ssl_allow_chained = {"daemon-ssl-allow-chained", tools::wallet2::tr("Allow user (via --daemon-ssl-ca-certificates) chain certificates"), false};
|
||||||
const command_line::arg_descriptor<bool> testnet = {"testnet", tools::wallet2::tr("For testnet. Daemon must also be launched with --testnet flag"), false};
|
const command_line::arg_descriptor<bool> testnet = {"testnet", tools::wallet2::tr("For testnet. Daemon must also be launched with --testnet flag"), false};
|
||||||
const command_line::arg_descriptor<bool> stagenet = {"stagenet", tools::wallet2::tr("For stagenet. Daemon must also be launched with --stagenet flag"), false};
|
const command_line::arg_descriptor<bool> stagenet = {"stagenet", tools::wallet2::tr("For stagenet. Daemon must also be launched with --stagenet flag"), false};
|
||||||
const command_line::arg_descriptor<std::string, false, true, 2> shared_ringdb_dir = {
|
const command_line::arg_descriptor<std::string, false, true, 2> shared_ringdb_dir = {
|
||||||
|
@ -314,6 +315,7 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
|
||||||
const uint64_t kdf_rounds = command_line::get_arg(vm, opts.kdf_rounds);
|
const uint64_t kdf_rounds = command_line::get_arg(vm, opts.kdf_rounds);
|
||||||
THROW_WALLET_EXCEPTION_IF(kdf_rounds == 0, tools::error::wallet_internal_error, "KDF rounds must not be 0");
|
THROW_WALLET_EXCEPTION_IF(kdf_rounds == 0, tools::error::wallet_internal_error, "KDF rounds must not be 0");
|
||||||
|
|
||||||
|
const bool use_proxy = command_line::has_arg(vm, opts.proxy);
|
||||||
auto daemon_address = command_line::get_arg(vm, opts.daemon_address);
|
auto daemon_address = command_line::get_arg(vm, opts.daemon_address);
|
||||||
auto daemon_host = command_line::get_arg(vm, opts.daemon_host);
|
auto daemon_host = command_line::get_arg(vm, opts.daemon_host);
|
||||||
auto daemon_port = command_line::get_arg(vm, opts.daemon_port);
|
auto daemon_port = command_line::get_arg(vm, opts.daemon_port);
|
||||||
|
@ -321,13 +323,37 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
|
||||||
auto device_derivation_path = command_line::get_arg(vm, opts.hw_device_derivation_path);
|
auto device_derivation_path = command_line::get_arg(vm, opts.hw_device_derivation_path);
|
||||||
auto daemon_ssl_private_key = command_line::get_arg(vm, opts.daemon_ssl_private_key);
|
auto daemon_ssl_private_key = command_line::get_arg(vm, opts.daemon_ssl_private_key);
|
||||||
auto daemon_ssl_certificate = command_line::get_arg(vm, opts.daemon_ssl_certificate);
|
auto daemon_ssl_certificate = command_line::get_arg(vm, opts.daemon_ssl_certificate);
|
||||||
auto daemon_ssl_allowed_certificates = command_line::get_arg(vm, opts.daemon_ssl_allowed_certificates);
|
auto daemon_ssl_ca_file = command_line::get_arg(vm, opts.daemon_ssl_ca_certificates);
|
||||||
auto daemon_ssl_allowed_fingerprints = command_line::get_arg(vm, opts.daemon_ssl_allowed_fingerprints);
|
auto daemon_ssl_allowed_fingerprints = command_line::get_arg(vm, opts.daemon_ssl_allowed_fingerprints);
|
||||||
auto daemon_ssl_allow_any_cert = command_line::get_arg(vm, opts.daemon_ssl_allow_any_cert);
|
auto daemon_ssl_allow_any_cert = command_line::get_arg(vm, opts.daemon_ssl_allow_any_cert);
|
||||||
auto daemon_ssl = command_line::get_arg(vm, opts.daemon_ssl);
|
auto daemon_ssl = command_line::get_arg(vm, opts.daemon_ssl);
|
||||||
epee::net_utils::ssl_support_t ssl_support;
|
|
||||||
THROW_WALLET_EXCEPTION_IF(!epee::net_utils::ssl_support_from_string(ssl_support, daemon_ssl), tools::error::wallet_internal_error,
|
// user specified CA file or fingeprints implies enabled SSL by default
|
||||||
tools::wallet2::tr("Invalid argument for ") + std::string(opts.daemon_ssl.name));
|
epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
|
||||||
|
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())
|
||||||
|
{
|
||||||
|
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 (command_line::get_arg(vm, opts.daemon_ssl_allow_chained))
|
||||||
|
ssl_options.verification = epee::net_utils::ssl_verification_t::user_ca;
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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"));
|
||||||
|
@ -357,22 +383,24 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
|
||||||
if (daemon_address.empty())
|
if (daemon_address.empty())
|
||||||
daemon_address = std::string("http://") + daemon_host + ":" + std::to_string(daemon_port);
|
daemon_address = std::string("http://") + daemon_host + ":" + std::to_string(daemon_port);
|
||||||
|
|
||||||
boost::asio::ip::tcp::endpoint proxy{};
|
|
||||||
if (command_line::has_arg(vm, opts.proxy))
|
|
||||||
{
|
{
|
||||||
namespace ip = boost::asio::ip;
|
|
||||||
const boost::string_ref real_daemon = boost::string_ref{daemon_address}.substr(0, daemon_address.rfind(':'));
|
const boost::string_ref real_daemon = boost::string_ref{daemon_address}.substr(0, daemon_address.rfind(':'));
|
||||||
|
|
||||||
// onion and i2p addresses contain information about the server cert
|
const bool verification_required =
|
||||||
// which both authenticates and encrypts
|
ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || use_proxy;
|
||||||
const bool unencrypted_proxy =
|
|
||||||
!real_daemon.ends_with(".onion") && !real_daemon.ends_with(".i2p") &&
|
|
||||||
daemon_ssl_allowed_certificates.empty() && daemon_ssl_allowed_fingerprints.empty();
|
|
||||||
THROW_WALLET_EXCEPTION_IF(
|
THROW_WALLET_EXCEPTION_IF(
|
||||||
unencrypted_proxy,
|
verification_required && !ssl_options.has_strong_verification(real_daemon),
|
||||||
tools::error::wallet_internal_error,
|
tools::error::wallet_internal_error,
|
||||||
std::string{"Use of --"} + opts.proxy.name + " requires --" + opts.daemon_ssl_allowed_certificates.name + " or --" + opts.daemon_ssl_allowed_fingerprints.name + " or use of a .onion/.i2p domain"
|
tools::wallet2::tr("Enabling --") + std::string{use_proxy ? opts.proxy.name : opts.daemon_ssl.name} + tools::wallet2::tr(" requires --") +
|
||||||
|
opts.daemon_ssl_ca_certificates.name + tools::wallet2::tr(" or --") + opts.daemon_ssl_allowed_fingerprints.name + tools::wallet2::tr(" or use of a .onion/.i2p domain")
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::asio::ip::tcp::endpoint proxy{};
|
||||||
|
if (use_proxy)
|
||||||
|
{
|
||||||
|
namespace ip = boost::asio::ip;
|
||||||
|
|
||||||
const auto proxy_address = command_line::get_arg(vm, opts.proxy);
|
const auto proxy_address = command_line::get_arg(vm, opts.proxy);
|
||||||
|
|
||||||
|
@ -416,22 +444,8 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
|
||||||
catch (const std::exception &e) { }
|
catch (const std::exception &e) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<std::string> ssl_allowed_certificates;
|
|
||||||
for (const std::string &path: daemon_ssl_allowed_certificates)
|
|
||||||
{
|
|
||||||
ssl_allowed_certificates.push_back({});
|
|
||||||
if (!epee::file_io_utils::load_file_to_string(path, ssl_allowed_certificates.back()))
|
|
||||||
{
|
|
||||||
MERROR("Failed to load certificate: " << path);
|
|
||||||
ssl_allowed_certificates.back() = std::string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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), ssl_allowed_certificates, 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);
|
||||||
|
@ -1100,9 +1114,10 @@ void wallet2::init_options(boost::program_options::options_description& desc_par
|
||||||
command_line::add_arg(desc_params, opts.daemon_ssl);
|
command_line::add_arg(desc_params, opts.daemon_ssl);
|
||||||
command_line::add_arg(desc_params, opts.daemon_ssl_private_key);
|
command_line::add_arg(desc_params, opts.daemon_ssl_private_key);
|
||||||
command_line::add_arg(desc_params, opts.daemon_ssl_certificate);
|
command_line::add_arg(desc_params, opts.daemon_ssl_certificate);
|
||||||
command_line::add_arg(desc_params, opts.daemon_ssl_allowed_certificates);
|
command_line::add_arg(desc_params, opts.daemon_ssl_ca_certificates);
|
||||||
command_line::add_arg(desc_params, opts.daemon_ssl_allowed_fingerprints);
|
command_line::add_arg(desc_params, opts.daemon_ssl_allowed_fingerprints);
|
||||||
command_line::add_arg(desc_params, opts.daemon_ssl_allow_any_cert);
|
command_line::add_arg(desc_params, opts.daemon_ssl_allow_any_cert);
|
||||||
|
command_line::add_arg(desc_params, opts.daemon_ssl_allow_chained);
|
||||||
command_line::add_arg(desc_params, opts.testnet);
|
command_line::add_arg(desc_params, opts.testnet);
|
||||||
command_line::add_arg(desc_params, opts.stagenet);
|
command_line::add_arg(desc_params, opts.stagenet);
|
||||||
command_line::add_arg(desc_params, opts.shared_ringdb_dir);
|
command_line::add_arg(desc_params, opts.shared_ringdb_dir);
|
||||||
|
@ -1154,10 +1169,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,
|
|
||||||
const std::list<std::string> &allowed_certificates, 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();
|
||||||
|
@ -1166,17 +1178,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, allowed_certificates, 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, const std::list<std::string> &allowed_certificates, 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, allowed_certificates, 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
|
||||||
|
|
|
@ -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 = {},
|
|
||||||
const std::list<std::string> &allowed_certificates = {}, 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 = {},
|
|
||||||
const std::list<std::string> &allowed_certificates = {}, 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(); }
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ namespace
|
||||||
const command_line::arg_descriptor<std::string> arg_rpc_ssl = {"rpc-ssl", tools::wallet2::tr("Enable SSL on wallet RPC connections: enabled|disabled|autodetect"), "autodetect"};
|
const command_line::arg_descriptor<std::string> arg_rpc_ssl = {"rpc-ssl", tools::wallet2::tr("Enable SSL on wallet RPC connections: enabled|disabled|autodetect"), "autodetect"};
|
||||||
const command_line::arg_descriptor<std::string> arg_rpc_ssl_private_key = {"rpc-ssl-private-key", tools::wallet2::tr("Path to a PEM format private key"), ""};
|
const command_line::arg_descriptor<std::string> arg_rpc_ssl_private_key = {"rpc-ssl-private-key", tools::wallet2::tr("Path to a PEM format private key"), ""};
|
||||||
const command_line::arg_descriptor<std::string> arg_rpc_ssl_certificate = {"rpc-ssl-certificate", tools::wallet2::tr("Path to a PEM format certificate"), ""};
|
const command_line::arg_descriptor<std::string> arg_rpc_ssl_certificate = {"rpc-ssl-certificate", tools::wallet2::tr("Path to a PEM format certificate"), ""};
|
||||||
const command_line::arg_descriptor<std::vector<std::string>> arg_rpc_ssl_allowed_certificates = {"rpc-ssl-allowed-certificates", tools::wallet2::tr("List of paths to PEM format certificates of allowed RPC servers (all allowed if empty)")};
|
const command_line::arg_descriptor<std::string> arg_rpc_ssl_ca_certificates = {"rpc-ssl-ca-certificates", tools::wallet2::tr("Path to file containing concatenated PEM format certificate(s) to replace system CA(s).")};
|
||||||
const command_line::arg_descriptor<std::vector<std::string>> arg_rpc_ssl_allowed_fingerprints = {"rpc-ssl-allowed-fingerprints", tools::wallet2::tr("List of certificate fingerprints to allow")};
|
const command_line::arg_descriptor<std::vector<std::string>> arg_rpc_ssl_allowed_fingerprints = {"rpc-ssl-allowed-fingerprints", tools::wallet2::tr("List of certificate fingerprints to allow")};
|
||||||
|
|
||||||
constexpr const char default_rpc_username[] = "monero";
|
constexpr const char default_rpc_username[] = "monero";
|
||||||
|
@ -247,28 +247,34 @@ namespace tools
|
||||||
|
|
||||||
auto rpc_ssl_private_key = command_line::get_arg(vm, arg_rpc_ssl_private_key);
|
auto rpc_ssl_private_key = command_line::get_arg(vm, arg_rpc_ssl_private_key);
|
||||||
auto rpc_ssl_certificate = command_line::get_arg(vm, arg_rpc_ssl_certificate);
|
auto rpc_ssl_certificate = command_line::get_arg(vm, arg_rpc_ssl_certificate);
|
||||||
auto rpc_ssl_allowed_certificates = command_line::get_arg(vm, arg_rpc_ssl_allowed_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_options_t rpc_ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
|
||||||
if (!epee::net_utils::ssl_support_from_string(rpc_ssl_support, rpc_ssl))
|
|
||||||
|
if (!rpc_ssl_ca_file.empty() || !rpc_ssl_allowed_fingerprints.empty())
|
||||||
{
|
{
|
||||||
MERROR("Invalid argument for " << std::string(arg_rpc_ssl.name));
|
std::vector<std::vector<uint8_t>> allowed_fingerprints{ rpc_ssl_allowed_fingerprints.size() };
|
||||||
return false;
|
std::transform(rpc_ssl_allowed_fingerprints.begin(), rpc_ssl_allowed_fingerprints.end(), allowed_fingerprints.begin(), epee::from_hex::vector);
|
||||||
}
|
|
||||||
std::list<std::string> allowed_certificates;
|
rpc_ssl_options = epee::net_utils::ssl_options_t{
|
||||||
for (const std::string &path: rpc_ssl_allowed_certificates)
|
std::move(allowed_fingerprints), std::move(rpc_ssl_ca_file)
|
||||||
{
|
};
|
||||||
allowed_certificates.push_back({});
|
|
||||||
if (!epee::file_io_utils::load_file_to_string(path, allowed_certificates.back()))
|
|
||||||
{
|
|
||||||
MERROR("Failed to load certificate: " << path);
|
|
||||||
allowed_certificates.back() = std::string();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::vector<uint8_t>> allowed_fingerprints{ rpc_ssl_allowed_fingerprints.size() };
|
// user specified CA file or fingeprints implies enabled SSL by default
|
||||||
std::transform(rpc_ssl_allowed_fingerprints.begin(), rpc_ssl_allowed_fingerprints.end(), allowed_fingerprints.begin(), epee::from_hex::vector);
|
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_options.support, rpc_ssl))
|
||||||
|
{
|
||||||
|
MERROR("Invalid argument for " << std::string(arg_rpc_ssl.name));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc_ssl_options.auth = epee::net_utils::ssl_authentication_t{
|
||||||
|
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;
|
||||||
|
@ -277,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(allowed_certificates), std::move(allowed_fingerprints)
|
std::move(rpc_ssl_options)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
@ -4054,13 +4060,7 @@ 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;
|
|
||||||
if (!epee::net_utils::ssl_support_from_string(ssl_support, req.ssl_support))
|
|
||||||
{
|
|
||||||
er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION;
|
|
||||||
er.message = std::string("Invalid ssl support mode");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
std::vector<std::vector<uint8_t>> ssl_allowed_fingerprints;
|
std::vector<std::vector<uint8_t>> ssl_allowed_fingerprints;
|
||||||
ssl_allowed_fingerprints.reserve(req.ssl_allowed_fingerprints.size());
|
ssl_allowed_fingerprints.reserve(req.ssl_allowed_fingerprints.size());
|
||||||
for (const std::string &fp: req.ssl_allowed_fingerprints)
|
for (const std::string &fp: req.ssl_allowed_fingerprints)
|
||||||
|
@ -4070,7 +4070,31 @@ 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), req.ssl_allowed_certificates, ssl_allowed_fingerprints, req.ssl_allow_any_cert))
|
|
||||||
|
epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
|
||||||
|
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)};
|
||||||
|
|
||||||
|
if (!epee::net_utils::ssl_support_from_string(ssl_options.support, req.ssl_support))
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION;
|
||||||
|
er.message = std::string("Invalid ssl support mode");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl_options.auth = epee::net_utils::ssl_authentication_t{
|
||||||
|
std::move(req.ssl_private_key_path), std::move(req.ssl_certificate_path)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled && !ssl_options.has_strong_verification(boost::string_ref{}))
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION;
|
||||||
|
er.message = "SSL is enabled but no user certificate or fingerprints were provided";
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
@ -4278,7 +4302,7 @@ int main(int argc, char** argv) {
|
||||||
command_line::add_arg(desc_params, arg_rpc_ssl);
|
command_line::add_arg(desc_params, arg_rpc_ssl);
|
||||||
command_line::add_arg(desc_params, arg_rpc_ssl_private_key);
|
command_line::add_arg(desc_params, arg_rpc_ssl_private_key);
|
||||||
command_line::add_arg(desc_params, arg_rpc_ssl_certificate);
|
command_line::add_arg(desc_params, arg_rpc_ssl_certificate);
|
||||||
command_line::add_arg(desc_params, arg_rpc_ssl_allowed_certificates);
|
command_line::add_arg(desc_params, arg_rpc_ssl_ca_certificates);
|
||||||
command_line::add_arg(desc_params, arg_rpc_ssl_allowed_fingerprints);
|
command_line::add_arg(desc_params, arg_rpc_ssl_allowed_fingerprints);
|
||||||
|
|
||||||
daemonizer::init_options(hidden_options, desc_params);
|
daemonizer::init_options(hidden_options, desc_params);
|
||||||
|
|
|
@ -2448,7 +2448,7 @@ namespace wallet_rpc
|
||||||
std::string ssl_support; // disabled, enabled, autodetect
|
std::string ssl_support; // disabled, enabled, autodetect
|
||||||
std::string ssl_private_key_path;
|
std::string ssl_private_key_path;
|
||||||
std::string ssl_certificate_path;
|
std::string ssl_certificate_path;
|
||||||
std::list<std::string> ssl_allowed_certificates;
|
std::string ssl_ca_file;
|
||||||
std::vector<std::string> ssl_allowed_fingerprints;
|
std::vector<std::string> ssl_allowed_fingerprints;
|
||||||
bool ssl_allow_any_cert;
|
bool ssl_allow_any_cert;
|
||||||
|
|
||||||
|
@ -2458,7 +2458,7 @@ namespace wallet_rpc
|
||||||
KV_SERIALIZE_OPT(ssl_support, (std::string)"autodetect")
|
KV_SERIALIZE_OPT(ssl_support, (std::string)"autodetect")
|
||||||
KV_SERIALIZE(ssl_private_key_path)
|
KV_SERIALIZE(ssl_private_key_path)
|
||||||
KV_SERIALIZE(ssl_certificate_path)
|
KV_SERIALIZE(ssl_certificate_path)
|
||||||
KV_SERIALIZE(ssl_allowed_certificates)
|
KV_SERIALIZE(ssl_ca_file)
|
||||||
KV_SERIALIZE(ssl_allowed_fingerprints)
|
KV_SERIALIZE(ssl_allowed_fingerprints)
|
||||||
KV_SERIALIZE_OPT(ssl_allow_any_cert, false)
|
KV_SERIALIZE_OPT(ssl_allow_any_cert, false)
|
||||||
END_KV_SERIALIZE_MAP()
|
END_KV_SERIALIZE_MAP()
|
||||||
|
|
Loading…
Reference in a new issue