Change SSL certificate file list to OpenSSL builtin load_verify_location

Specifying SSL certificates for peer verification does an exact match,
making it a not-so-obvious alias for the fingerprints option. This
changes the checks to OpenSSL which loads concatenated certificate(s)
from a single file and does a certificate-authority (chain of trust)
check instead. There is no drop in security - a compromised exact match
fingerprint has the same worse case failure. There is increased security
in allowing separate long-term CA key and short-term SSL server keys.

This also removes loading of the system-default CA files if a custom
CA file or certificate fingerprint is specified.
This commit is contained in:
Lee Clagett 2019-03-11 22:01:03 -04:00
parent 5dbcceb664
commit a3b0284837
13 changed files with 92 additions and 134 deletions

View File

@ -228,8 +228,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", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = std::make_pair(std::string(), std::string()), const std::string &ca_file = {}, const std::vector<std::vector<uint8_t>> &allowed_fingerprints = {}, bool allow_any_cert = false);
bool init_server(const std::string port, const std::string& address = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = std::make_pair(std::string(), std::string()), const std::list<std::string> &allowed_certificates = {}, const std::vector<std::vector<uint8_t>> &allowed_fingerprints = {}, bool allow_any_cert = false); bool init_server(const std::string port, const std::string& address = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = std::make_pair(std::string(), std::string()), const std::string &ca_file = {}, const std::vector<std::vector<uint8_t>> &allowed_fingerprints = {}, bool allow_any_cert = false);
/// 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());
@ -382,8 +382,6 @@ namespace net_utils
std::set<connection_ptr> connections_; std::set<connection_ptr> connections_;
ssl_context_t m_ssl_context; ssl_context_t m_ssl_context;
std::list<std::string> m_allowed_certificates;
}; // class <>boosted_tcp_server }; // class <>boosted_tcp_server

View File

@ -941,14 +941,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, epee::net_utils::ssl_support_t ssl_support, const std::pair<std::string, std::string> &private_key_and_certificate_path, const std::string &ca_file, const std::vector<std::vector<uint8_t>> &allowed_fingerprints, bool allow_any_cert)
{ {
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_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled)
m_ssl_context = create_ssl_context(private_key_and_certificate_path, allowed_certificates, allowed_fingerprints, allow_any_cert); m_ssl_context = create_ssl_context(private_key_and_certificate_path, ca_file, allowed_fingerprints, allow_any_cert);
// 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);
@ -982,7 +982,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, epee::net_utils::ssl_support_t ssl_support, const std::pair<std::string, std::string> &private_key_and_certificate_path, const std::string &ca_file, const std::vector<std::vector<uint8_t>> &allowed_fingerprints, bool allow_any_cert)
{ {
uint32_t p = 0; uint32_t p = 0;
@ -990,7 +990,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, ssl_support, private_key_and_certificate_path, ca_file, allowed_fingerprints, allow_any_cert);
} }
POP_WARNINGS POP_WARNINGS
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------

View File

@ -277,7 +277,7 @@ namespace net_utils
critical_section m_lock; critical_section m_lock;
epee::net_utils::ssl_support_t m_ssl_support; epee::net_utils::ssl_support_t m_ssl_support;
std::pair<std::string, std::string> m_ssl_private_key_and_certificate_path; std::pair<std::string, std::string> m_ssl_private_key_and_certificate_path;
std::list<std::string> m_ssl_allowed_certificates; std::string m_ssl_ca_file;
std::vector<std::vector<uint8_t>> m_ssl_allowed_fingerprints; std::vector<std::vector<uint8_t>> m_ssl_allowed_fingerprints;
bool m_ssl_allow_any_cert; bool m_ssl_allow_any_cert;
@ -303,16 +303,16 @@ namespace net_utils
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, epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = {}, std::string ca_file = {}, const std::vector<std::vector<uint8_t>> &allowed_ssl_fingerprints = {}, bool allow_any_cert = false)
{ {
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), ssl_support, private_key_and_certificate_path, std::move(ca_file), allowed_ssl_fingerprints, allow_any_cert);
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, epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = {}, std::string ca_file = {}, const std::vector<std::vector<uint8_t>> &allowed_ssl_fingerprints = {}, bool allow_any_cert = false)
{ {
CRITICAL_REGION_LOCAL(m_lock); CRITICAL_REGION_LOCAL(m_lock);
disconnect(); disconnect();
@ -321,10 +321,10 @@ namespace net_utils
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_ssl_support = ssl_support;
m_ssl_private_key_and_certificate_path = private_key_and_certificate_path; m_ssl_private_key_and_certificate_path = private_key_and_certificate_path;
m_ssl_allowed_certificates = allowed_ssl_certificates; m_ssl_ca_file = std::move(ca_file);
m_ssl_allowed_fingerprints = allowed_ssl_fingerprints; m_ssl_allowed_fingerprints = allowed_ssl_fingerprints;
m_ssl_allow_any_cert = allow_any_cert; m_ssl_allow_any_cert = allow_any_cert;
m_net_client.set_ssl(m_ssl_support, m_ssl_private_key_and_certificate_path, m_ssl_allowed_certificates, m_ssl_allowed_fingerprints, m_ssl_allow_any_cert); m_net_client.set_ssl(m_ssl_support, m_ssl_private_key_and_certificate_path, m_ssl_ca_file, m_ssl_allowed_fingerprints, m_ssl_allow_any_cert);
} }
template<typename F> template<typename F>

View File

@ -61,7 +61,7 @@ namespace epee
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, 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::pair<std::string, std::string> &private_key_and_certificate_path = {},
std::list<std::string> allowed_certificates = {}, const std::string &ca_path = {},
std::vector<std::vector<uint8_t>> allowed_fingerprints = {}, std::vector<std::vector<uint8_t>> allowed_fingerprints = {},
bool allow_any_cert = false) bool allow_any_cert = false)
{ {
@ -80,7 +80,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, ssl_support, private_key_and_certificate_path, ca_path, std::move(allowed_fingerprints), allow_any_cert);
if(!res) if(!res)
{ {
LOG_ERROR("Failed to bind server"); LOG_ERROR("Failed to bind server");

View File

@ -136,12 +136,12 @@ 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(epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = {}, const std::string &ca_path = {}, std::vector<std::vector<uint8_t>> allowed_fingerprints = {}, bool allow_any_cert = false)
{ {
if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_disabled) if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_disabled)
m_ctx = {boost::asio::ssl::context(boost::asio::ssl::context::tlsv12), {}, {}}; m_ctx = {boost::asio::ssl::context(boost::asio::ssl::context::tlsv12), {}, {}};
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 = create_ssl_context(private_key_and_certificate_path, ca_path, std::move(allowed_fingerprints), allow_any_cert);
m_ssl_support = ssl_support; m_ssl_support = ssl_support;
} }
@ -212,8 +212,6 @@ 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_ctx.context.set_default_verify_paths();
m_ssl_socket.reset(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_service, m_ctx.context)); m_ssl_socket.reset(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_service, m_ctx.context));
// Get a list of endpoints corresponding to the server name. // Get a list of endpoints corresponding to the server name.

View File

@ -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
{ {
@ -49,7 +50,7 @@ namespace net_utils
struct ssl_context_t struct ssl_context_t
{ {
boost::asio::ssl::context context; boost::asio::ssl::context context;
std::list<std::string> allowed_certificates; std::string ca_path;
std::vector<std::vector<uint8_t>> allowed_fingerprints; std::vector<std::vector<uint8_t>> allowed_fingerprints;
bool allow_any_cert; bool allow_any_cert;
}; };
@ -57,7 +58,7 @@ namespace net_utils
// 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); ssl_context_t create_ssl_context(const std::pair<std::string, std::string> &private_key_and_certificate_path, const std::string &ca_path, std::vector<std::vector<uint8_t>> allowed_fingerprints, bool allow_any_cert);
void use_ssl_certificate(ssl_context_t &ssl_context, const std::pair<std::string, std::string> &private_key_and_certificate_path); 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 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_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);

View File

@ -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,9 +171,9 @@ 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_context_t create_ssl_context(const std::pair<std::string, std::string> &private_key_and_certificate_path, const std::string &ca_path, std::vector<std::vector<uint8_t>> allowed_fingerprints, bool allow_any_cert)
{ {
ssl_context_t ssl_context{boost::asio::ssl::context(boost::asio::ssl::context::tlsv12), std::move(allowed_certificates), std::move(allowed_fingerprints)}; ssl_context_t ssl_context{boost::asio::ssl::context(boost::asio::ssl::context::tlsv12), std::move(ca_path), std::move(allowed_fingerprints)};
// 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.context.set_options(boost::asio::ssl::context::default_workarounds);
@ -186,7 +202,15 @@ 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();
if (!ssl_context.ca_path.empty())
{
const boost::system::error_code err = load_ca_file(ssl_context.context, ssl_context.ca_path);
if (err)
throw boost::system::system_error{err, "Failed to load user CA file at " + ssl_context.ca_path};
}
else if (allowed_fingerprints.empty())
ssl_context.context.set_default_verify_paths(); // only use system-CAs if no user-supplied cert info
CHECK_AND_ASSERT_THROW_MES(private_key_and_certificate_path.first.empty() == private_key_and_certificate_path.second.empty(), "private key and certificate must be either both given or both empty"); CHECK_AND_ASSERT_THROW_MES(private_key_and_certificate_path.first.empty() == private_key_and_certificate_path.second.empty(), "private key and certificate must be either both given or both empty");
if (private_key_and_certificate_path.second.empty()) if (private_key_and_certificate_path.second.empty())
@ -237,21 +261,21 @@ bool is_ssl(const unsigned char *data, size_t len)
bool is_certificate_allowed(boost::asio::ssl::verify_context &ctx, const ssl_context_t &ssl_context) bool is_certificate_allowed(boost::asio::ssl::verify_context &ctx, const ssl_context_t &ssl_context)
{ {
X509_STORE_CTX *sctx = ctx.native_handle();
if (!sctx)
{
MERROR("Error getting verify_context handle");
return false;
}
X509 *cert =X509_STORE_CTX_get_current_cert(sctx);
if (!cert)
{
MERROR("No certificate found in verify_context");
return false;
}
// 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 (!ssl_context.allowed_fingerprints.empty()) {
X509_STORE_CTX *sctx = ctx.native_handle();
if (!sctx)
{
MERROR("Error getting verify_context handle");
return false;
}
X509 *cert =X509_STORE_CTX_get_current_cert(sctx);
if (!cert)
{
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 };
@ -270,52 +294,20 @@ bool is_certificate_allowed(boost::asio::ssl::verify_context &ctx, const ssl_con
return true; return true;
} }
if (!ssl_context.allowed_certificates.empty()) { return ssl_context.allowed_fingerprints.empty() && ssl_context.ca_path.empty();
BIO *bio_cert = BIO_new(BIO_s_mem());
bool success = PEM_write_bio_X509(bio_cert, cert);
if (!success)
{
BIO_free(bio_cert);
MERROR("Failed to print certificate");
return false;
}
BUF_MEM *buf = NULL;
BIO_get_mem_ptr(bio_cert, &buf);
if (!buf || !buf->data || !buf->length)
{
BIO_free(bio_cert);
MERROR("Failed to write certificate: " << ERR_get_error());
return false;
}
std::string certificate(std::string(buf->data, buf->length));
BIO_free(bio_cert);
if (std::find(ssl_context.allowed_certificates.begin(), ssl_context.allowed_certificates.end(), certificate) != ssl_context.allowed_certificates.end())
return true;
}
// 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_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 verified = false; bool verified = false;
socket.next_layer().set_option(boost::asio::ip::tcp::no_delay(true)); socket.next_layer().set_option(boost::asio::ip::tcp::no_delay(true));
socket.set_verify_mode(boost::asio::ssl::verify_peer); socket.set_verify_mode(boost::asio::ssl::verify_peer);
socket.set_verify_callback([&](bool preverified, boost::asio::ssl::verify_context &ctx) socket.set_verify_callback([&](bool preverified, boost::asio::ssl::verify_context &ctx)
{ {
if (!preverified) // preverified means it passed system or user CA check. System CA is never loaded
{ // when fingerprints are whitelisted.
const int err = X509_STORE_CTX_get_error(ctx.native_handle()); if (!preverified && !ssl_context.allow_any_cert && !is_certificate_allowed(ctx, ssl_context)) {
const int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle());
if (err != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || depth != 0)
{
MERROR("Invalid SSL certificate, error " << err << " at depth " << depth << ", connection dropped");
return false;
}
}
if (!ssl_context.allow_any_cert && !is_certificate_allowed(ctx, ssl_context))
{
MERROR("Certificate is not in the allowed list, connection droppped"); MERROR("Certificate is not in the allowed list, connection droppped");
return false; return false;
} }

View File

@ -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);
@ -158,17 +158,7 @@ namespace cryptonote
} }
const std::string ssl_private_key = command_line::get_arg(vm, arg_rpc_ssl_private_key); 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); const std::string ssl_certificate = command_line::get_arg(vm, arg_rpc_ssl_certificate);
const std::vector<std::string> ssl_allowed_certificate_paths = command_line::get_arg(vm, arg_rpc_ssl_allowed_certificates); std::string ssl_ca_path = command_line::get_arg(vm, arg_rpc_ssl_ca_certificates);
std::list<std::string> ssl_allowed_certificates;
for (const std::string &path: ssl_allowed_certificate_paths)
{
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();
}
}
const std::vector<std::string> ssl_allowed_fingerprint_strings = command_line::get_arg(vm, arg_rpc_ssl_allowed_fingerprints); 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::vector<std::vector<uint8_t>> ssl_allowed_fingerprints{ ssl_allowed_fingerprint_strings.size() };
@ -178,7 +168,7 @@ namespace cryptonote
auto rng = [](size_t len, uint8_t *ptr){ return crypto::rand(len, ptr); }; auto rng = [](size_t len, uint8_t *ptr){ return crypto::rand(len, ptr); };
return epee::http_server_impl_base<core_rpc_server, connection_context>::init( return epee::http_server_impl_base<core_rpc_server, connection_context>::init(
rng, std::move(port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login), rng, std::move(port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login),
ssl_support, std::make_pair(ssl_private_key, ssl_certificate), std::move(ssl_allowed_certificates), std::move(ssl_allowed_fingerprints), ssl_allow_any_cert ssl_support, std::make_pair(ssl_private_key, ssl_certificate), std::move(ssl_ca_path), std::move(ssl_allowed_fingerprints), ssl_allow_any_cert
); );
} }
//------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------
@ -2408,9 +2398,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 +2410,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
}; };

View File

@ -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;

View File

@ -243,7 +243,7 @@ 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> 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};
@ -321,7 +321,7 @@ 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);
@ -367,11 +367,11 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
// which both authenticates and encrypts // which both authenticates and encrypts
const bool unencrypted_proxy = const bool unencrypted_proxy =
!real_daemon.ends_with(".onion") && !real_daemon.ends_with(".i2p") && !real_daemon.ends_with(".onion") && !real_daemon.ends_with(".i2p") &&
daemon_ssl_allowed_certificates.empty() && daemon_ssl_allowed_fingerprints.empty(); daemon_ssl_ca_file.empty() && daemon_ssl_allowed_fingerprints.empty();
THROW_WALLET_EXCEPTION_IF( THROW_WALLET_EXCEPTION_IF(
unencrypted_proxy, unencrypted_proxy,
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" std::string{"Use of --"} + opts.proxy.name + " requires --" + opts.daemon_ssl_ca_certificates.name + " or --" + opts.daemon_ssl_allowed_fingerprints.name + " or use of a .onion/.i2p domain"
); );
const auto proxy_address = command_line::get_arg(vm, opts.proxy); const auto proxy_address = command_line::get_arg(vm, opts.proxy);
@ -416,22 +416,11 @@ 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::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::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, ssl_support, std::make_pair(daemon_ssl_private_key, daemon_ssl_certificate), std::move(daemon_ssl_ca_file), ssl_allowed_fingerprints, daemon_ssl_allow_any_cert);
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,7 +1089,7 @@ 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.testnet); command_line::add_arg(desc_params, opts.testnet);
@ -1156,7 +1145,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_support_t ssl_support, const std::pair<std::string, std::string> &private_key_and_certificate_path, 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, std::string ca_file, const std::vector<std::vector<uint8_t>> &allowed_fingerprints,
bool allow_any_cert) bool allow_any_cert)
{ {
if(m_http_client.is_connected()) if(m_http_client.is_connected())
@ -1166,17 +1155,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(), ssl_support, private_key_and_certificate_path, std::move(ca_file), allowed_fingerprints, 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_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_support_t ssl_support, const std::pair<std::string, std::string> &private_key_and_certificate_path, std::string ca_file, const std::vector<std::vector<uint8_t>> &allowed_fingerprints, bool allow_any_cert)
{ {
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, ssl_support, private_key_and_certificate_path, std::move(ca_file), allowed_fingerprints, allow_any_cert);
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool wallet2::is_deterministic() const bool wallet2::is_deterministic() const

View File

@ -691,13 +691,13 @@ namespace tools
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_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::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 = {}, std::string ca_file = {}, const std::vector<std::vector<uint8_t>> &allowed_fingerprints = {},
bool allow_any_cert = false); 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_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::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 = {}, std::string ca_file = {}, const std::vector<std::vector<uint8_t>> &allowed_fingerprints = {},
bool allow_any_cert = false); bool allow_any_cert = false);
void stop() { m_run.store(false, std::memory_order_relaxed); m_message_store.stop(); } void stop() { m_run.store(false, std::memory_order_relaxed); m_message_store.stop(); }

View File

@ -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,7 +247,7 @@ 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_support_t rpc_ssl_support;
@ -256,16 +256,6 @@ namespace tools
MERROR("Invalid argument for " << std::string(arg_rpc_ssl.name)); MERROR("Invalid argument for " << std::string(arg_rpc_ssl.name));
return false; return false;
} }
std::list<std::string> allowed_certificates;
for (const std::string &path: rpc_ssl_allowed_certificates)
{
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() }; std::vector<std::vector<uint8_t>> allowed_fingerprints{ rpc_ssl_allowed_fingerprints.size() };
std::transform(rpc_ssl_allowed_fingerprints.begin(), rpc_ssl_allowed_fingerprints.end(), allowed_fingerprints.begin(), epee::from_hex::vector); std::transform(rpc_ssl_allowed_fingerprints.begin(), rpc_ssl_allowed_fingerprints.end(), allowed_fingerprints.begin(), epee::from_hex::vector);
@ -277,7 +267,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) rpc_ssl_support, std::make_pair(rpc_ssl_private_key, rpc_ssl_certificate), std::move(rpc_ssl_ca_file), std::move(allowed_fingerprints)
); );
} }
//------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------
@ -4070,7 +4060,7 @@ 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)) if (!m_wallet->set_daemon(req.address, boost::none, req.trusted, ssl_support, std::make_pair(req.ssl_private_key_path, req.ssl_certificate_path), std::move(req.ssl_ca_file), ssl_allowed_fingerprints, req.ssl_allow_any_cert))
{ {
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 +4268,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);

View File

@ -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()