Skip to content

Commit 5d35a9a

Browse files
committed
Add SSL support to P2P
1 parent ac02af9 commit 5d35a9a

29 files changed

+630
-301
lines changed

contrib/epee/include/net/abstract_tcp_server2.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,11 @@ namespace net_utils
296296

297297

298298
bool speed_limit_is_enabled() const; ///< tells us should we be sleeping here (e.g. do not sleep on RPC connections)
299-
299+
void set_ssl_enabled()
300+
{
301+
m_state.ssl.enabled = true;
302+
m_state.ssl.handshaked = true;
303+
}
300304
bool cancel();
301305

302306
private:
@@ -376,10 +380,10 @@ namespace net_utils
376380
}
377381

378382
bool add_connection(t_connection_context& out, boost::asio::ip::tcp::socket&& sock, network_address real_remote, epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
379-
try_connect_result_t try_connect(connection_ptr new_connection_l, const std::string& adr, const std::string& port, boost::asio::ip::tcp::socket &sock_, const boost::asio::ip::tcp::endpoint &remote_endpoint, const std::string &bind_ip, uint32_t conn_timeout, epee::net_utils::ssl_support_t ssl_support);
380-
bool connect(const std::string& adr, const std::string& port, uint32_t conn_timeot, t_connection_context& cn, const std::string& bind_ip = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
383+
try_connect_result_t try_connect(connection_ptr new_connection_l, const std::string& adr, const std::string& port, boost::asio::ip::tcp::socket &sock_, const boost::asio::ip::tcp::endpoint &remote_endpoint, const std::string &bind_ip, uint32_t conn_timeout, epee::net_utils::ssl_options_t& ssl_support);
384+
bool connect(const std::string& adr, const std::string& port, uint32_t conn_timeot, t_connection_context& cn, const std::string& bind_ip = "0.0.0.0", epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
381385
template<class t_callback>
382-
bool connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeot, const t_callback &cb, const std::string& bind_ip = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
386+
bool connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeot, const t_callback &cb, const std::string& bind_ip = "0.0.0.0", epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
383387

384388
boost::asio::ssl::context& get_ssl_context() noexcept
385389
{

contrib/epee/include/net/abstract_tcp_server2.inl

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -895,7 +895,7 @@ namespace net_utils
895895
boost::uuids::random_generator()(),
896896
*real_remote,
897897
is_income,
898-
connection_basic::m_ssl_support == ssl_support_t::e_ssl_support_enabled
898+
connection_basic::m_ssl_support
899899
);
900900
m_host = real_remote->host_str();
901901
try { host_count(1); } catch(...) { /* ignore */ }
@@ -1559,7 +1559,7 @@ namespace net_utils
15591559
}
15601560
//---------------------------------------------------------------------------------
15611561
template<class t_protocol_handler>
1562-
typename boosted_tcp_server<t_protocol_handler>::try_connect_result_t boosted_tcp_server<t_protocol_handler>::try_connect(connection_ptr new_connection_l, const std::string& adr, const std::string& port, boost::asio::ip::tcp::socket &sock_, const boost::asio::ip::tcp::endpoint &remote_endpoint, const std::string &bind_ip, uint32_t conn_timeout, epee::net_utils::ssl_support_t ssl_support)
1562+
typename boosted_tcp_server<t_protocol_handler>::try_connect_result_t boosted_tcp_server<t_protocol_handler>::try_connect(connection_ptr new_connection_l, const std::string& adr, const std::string& port, boost::asio::ip::tcp::socket &sock_, const boost::asio::ip::tcp::endpoint &remote_endpoint, const std::string &bind_ip, uint32_t conn_timeout, epee::net_utils::ssl_options_t& ssl_options)
15631563
{
15641564
TRY_ENTRY();
15651565

@@ -1635,7 +1635,7 @@ namespace net_utils
16351635
{
16361636
// Handshake
16371637
MDEBUG("Handshaking SSL...");
1638-
if (!new_connection_l->handshake(boost::asio::ssl::stream_base::client))
1638+
if (!new_connection_l->client_handshake(ssl_options))
16391639
{
16401640
if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
16411641
{
@@ -1649,6 +1649,7 @@ namespace net_utils
16491649
sock_.close();
16501650
return CONNECT_FAILURE;
16511651
}
1652+
new_connection_l->set_ssl_enabled();
16521653
}
16531654

16541655
return CONNECT_SUCCESS;
@@ -1657,11 +1658,11 @@ namespace net_utils
16571658
}
16581659
//---------------------------------------------------------------------------------
16591660
template<class t_protocol_handler>
1660-
bool boosted_tcp_server<t_protocol_handler>::connect(const std::string& adr, const std::string& port, uint32_t conn_timeout, t_connection_context& conn_context, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support)
1661+
bool boosted_tcp_server<t_protocol_handler>::connect(const std::string& adr, const std::string& port, uint32_t conn_timeout, t_connection_context& conn_context, const std::string& bind_ip, epee::net_utils::ssl_options_t ssl_options)
16611662
{
16621663
TRY_ENTRY();
16631664

1664-
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support) );
1665+
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_options.support) );
16651666
connections_mutex.lock();
16661667
connections_.insert(new_connection_l);
16671668
MDEBUG("connections_ size now " << connections_.size());
@@ -1746,15 +1747,16 @@ namespace net_utils
17461747
//boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port);
17471748
boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
17481749

1749-
auto try_connect_result = try_connect(new_connection_l, adr, port, sock_, remote_endpoint, bind_ip_to_use, conn_timeout, ssl_support);
1750+
auto try_connect_result = try_connect(new_connection_l, adr, port, sock_, remote_endpoint, bind_ip_to_use, conn_timeout, ssl_options);
17501751
if (try_connect_result == CONNECT_FAILURE)
17511752
return false;
1752-
if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect && try_connect_result == CONNECT_NO_SSL)
1753+
if (ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect && try_connect_result == CONNECT_NO_SSL)
17531754
{
17541755
// we connected, but could not connect with SSL, try without
17551756
MERROR("SSL handshake failed on an autodetect connection, reconnecting without SSL");
17561757
new_connection_l->disable_ssl();
1757-
try_connect_result = try_connect(new_connection_l, adr, port, sock_, remote_endpoint, bind_ip_to_use, conn_timeout, epee::net_utils::ssl_support_t::e_ssl_support_disabled);
1758+
ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_disabled;
1759+
try_connect_result = try_connect(new_connection_l, adr, port, sock_, remote_endpoint, bind_ip_to_use, conn_timeout, ssl_options);
17581760
if (try_connect_result != CONNECT_SUCCESS)
17591761
return false;
17601762
}
@@ -1783,10 +1785,10 @@ namespace net_utils
17831785
}
17841786
//---------------------------------------------------------------------------------
17851787
template<class t_protocol_handler> template<class t_callback>
1786-
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)
1788+
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_options_t ssl_options)
17871789
{
17881790
TRY_ENTRY();
1789-
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support) );
1791+
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_options.support) );
17901792
connections_mutex.lock();
17911793
connections_.insert(new_connection_l);
17921794
MDEBUG("connections_ size now " << connections_.size());

contrib/epee/include/net/connection_basic.hpp

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -132,37 +132,15 @@ class connection_basic { // not-templated base class for rapid developmet of som
132132
ssl_support_t get_ssl_support() const { return m_ssl_support; }
133133
void disable_ssl() { m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_disabled; }
134134

135-
bool handshake(boost::asio::ssl::stream_base::handshake_type type, boost::asio::const_buffer buffer = {})
135+
bool client_handshake(ssl_options_t& ssl)
136136
{
137-
//m_state != nullptr verified in constructor
138-
return m_state->ssl_options().handshake(socket_, type, buffer);
139-
}
140-
141-
template<typename MutableBufferSequence, typename ReadHandler>
142-
void async_read_some(const MutableBufferSequence &buffers, ReadHandler &&handler)
143-
{
144-
if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
145-
socket_.async_read_some(buffers, std::forward<ReadHandler>(handler));
146-
else
147-
socket().async_read_some(buffers, std::forward<ReadHandler>(handler));
137+
return ssl.handshake(socket_, boost::asio::ssl::stream_base::client);
148138
}
149139

150-
template<typename ConstBufferSequence, typename WriteHandler>
151-
void async_write_some(const ConstBufferSequence &buffers, WriteHandler &&handler)
140+
bool server_handshake(boost::asio::const_buffer buffer)
152141
{
153-
if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
154-
socket_.async_write_some(buffers, std::forward<WriteHandler>(handler));
155-
else
156-
socket().async_write_some(buffers, std::forward<WriteHandler>(handler));
157-
}
158-
159-
template<typename ConstBufferSequence, typename WriteHandler>
160-
void async_write(const ConstBufferSequence &buffers, WriteHandler &&handler)
161-
{
162-
if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
163-
boost::asio::async_write(socket_, buffers, std::forward<WriteHandler>(handler));
164-
else
165-
boost::asio::async_write(socket(), buffers, std::forward<WriteHandler>(handler));
142+
//m_state != nullptr verified in constructor
143+
return m_state->ssl_options().handshake(socket_, boost::asio::ssl::stream_base::server, buffer);
166144
}
167145

168146
// various handlers to be called from connection class:

contrib/epee/include/net/levin_base.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ namespace levin
130130
//! Provides space for levin (p2p) header, so that payload can be sent without copy
131131
class message_writer
132132
{
133-
byte_slice finalize(uint32_t command, uint32_t flags, uint32_t return_code, bool expect_response);
133+
byte_slice finalize(uint32_t command, uint32_t flags, uint32_t return_code, bool expect_response, bool pad);
134134
public:
135135
using header = bucket_head2;
136136

@@ -147,12 +147,13 @@ namespace levin
147147
{
148148
return buffer.size() < sizeof(header) ? 0 : buffer.size() - sizeof(header);
149149
}
150-
151-
byte_slice finalize_invoke(uint32_t command) { return finalize(command, LEVIN_PACKET_REQUEST, 0, true); }
152-
byte_slice finalize_notify(uint32_t command) { return finalize(command, LEVIN_PACKET_REQUEST, 0, false); }
153-
byte_slice finalize_response(uint32_t command, uint32_t return_code)
150+
151+
// `pad == true` will add 0-8192 of zero bytes (actual amount randomized)
152+
byte_slice finalize_invoke(uint32_t command, bool pad) { return finalize(command, LEVIN_PACKET_REQUEST, 0, true, pad); }
153+
byte_slice finalize_notify(uint32_t command, bool pad) { return finalize(command, LEVIN_PACKET_REQUEST, 0, false, pad); }
154+
byte_slice finalize_response(uint32_t command, uint32_t return_code, bool pad)
154155
{
155-
return finalize(command, LEVIN_PACKET_RESPONSE, return_code, false);
156+
return finalize(command, LEVIN_PACKET_RESPONSE, return_code, false, pad);
156157
}
157158

158159
//! Has space for levin header until a finalize method is used

contrib/epee/include/net/levin_protocol_handler_async.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ class async_protocol_handler
486486

487487
bool is_response = (m_oponent_protocol_ver == LEVIN_PROTOCOL_VER_1 && m_current_head.m_flags&LEVIN_PACKET_RESPONSE);
488488

489-
MDEBUG(m_connection_context << "LEVIN_PACKET_RECEIVED. [len=" << m_current_head.m_cb
489+
MDEBUG(m_connection_context << "LEVIN_PACKET_RECEIVED. [len=" << m_current_head.m_cb
490490
<< ", flags" << m_current_head.m_flags
491491
<< ", r?=" << m_current_head.m_have_to_return_data
492492
<<", cmd = " << m_current_head.m_command
@@ -526,7 +526,7 @@ class async_protocol_handler
526526
if (m_current_head.m_command == m_connection_context.handshake_command() && m_connection_context.handshake_complete())
527527
m_max_packet_size = m_config.m_max_packet_size;
528528

529-
if(!send_message(return_message.finalize_response(m_current_head.m_command, return_code)))
529+
if(!send_message(return_message.finalize_response(m_current_head.m_command, return_code, m_connection_context.should_pad())))
530530
return false;
531531
}
532532
else
@@ -620,7 +620,7 @@ class async_protocol_handler
620620
if (command == m_connection_context.handshake_command())
621621
m_max_packet_size = m_config.m_max_packet_size;
622622

623-
if(!send_message(in_msg.finalize_invoke(command)))
623+
if(!send_message(in_msg.finalize_invoke(command, m_connection_context.should_pad())))
624624
{
625625
LOG_ERROR_CC(m_connection_context, "Failed to do_send");
626626
err_code = LEVIN_ERROR_CONNECTION;

contrib/epee/include/net/net_ssl.h

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ namespace epee
4646
namespace net_utils
4747
{
4848
enum class ssl_support_t: uint8_t {
49-
e_ssl_support_disabled,
49+
e_ssl_support_disabled = 0,
5050
e_ssl_support_enabled,
5151
e_ssl_support_autodetect,
5252
};
@@ -107,6 +107,9 @@ namespace net_utils
107107
//! \return True if `host` can be verified using `this` configuration WITHOUT system "root" CAs.
108108
bool has_strong_verification(boost::string_ref host) const noexcept;
109109

110+
//! \return All fingerprints
111+
const std::vector<std::vector<std::uint8_t>>& fingerprints() const noexcept { return fingerprints_; }
112+
110113
//! Search against internal fingerprints. Always false if `behavior() != user_certificate_check`.
111114
bool has_fingerprint(boost::asio::ssl::verify_context &ctx) const;
112115

@@ -151,6 +154,30 @@ namespace net_utils
151154
bool create_ec_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert);
152155
bool create_rsa_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert);
153156

157+
std::vector<std::uint8_t> convert_fingerprint(const boost::string_ref id);
158+
159+
/**
160+
* @brief Create a binary X509 certificate fingerprint
161+
*
162+
* @param[in] cert The certificate which will be used to create the fingerprint
163+
* @param[in] fdig The digest algorithm to use, defaults to SHA-256 b/c that is what ssl_options_t uses
164+
* @return The binary fingerprint string
165+
*
166+
* @throw boost::system_error if there is an OpenSSL error
167+
*/
168+
std::string get_ssl_fingerprint(const X509 *cert, const EVP_MD *fdig = EVP_sha256());
169+
170+
/**
171+
* @brief Create a binary X509 certificate fingerprint
172+
*
173+
* @param[in] context The context for the current certificate.
174+
* @param[in] fdig The digest algorithm to use, defaults to SHA-256 b/c that is what ssl_options_t uses
175+
* @return The binary fingerprint string
176+
*
177+
* @throw boost::system_error if there is an OpenSSL error
178+
*/
179+
std::string get_ssl_fingerprint(boost::asio::ssl::context& context, const EVP_MD *fdig = EVP_sha256());
180+
154181
/**
155182
* @brief Create a human-readable X509 certificate fingerprint
156183
*

contrib/epee/include/net/net_utils_base.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@
3232
#include <boost/uuid/uuid.hpp>
3333
#include <boost/asio/io_service.hpp>
3434
#include <boost/asio/ip/address_v6.hpp>
35+
#include <boost/optional/optional.hpp>
3536
#include <typeinfo>
3637
#include <type_traits>
3738
#include "byte_slice.h"
3839
#include "enums.h"
3940
#include "misc_log_ex.h"
41+
#include "net_ssl.h"
4042
#include "serialization/keyvalue_serialization.h"
4143
#include "int-util.h"
4244

@@ -367,7 +369,7 @@ namespace net_utils
367369
const network_address m_remote_address;
368370
const bool m_is_income;
369371
const time_t m_started;
370-
const bool m_ssl;
372+
const ssl_support_t m_ssl;
371373
time_t m_last_recv;
372374
time_t m_last_send;
373375
uint64_t m_recv_cnt;
@@ -378,7 +380,7 @@ namespace net_utils
378380
double m_max_speed_up;
379381

380382
connection_context_base(boost::uuids::uuid connection_id,
381-
const network_address &remote_address, bool is_income, bool ssl,
383+
const network_address &remote_address, bool is_income, ssl_support_t ssl,
382384
time_t last_recv = 0, time_t last_send = 0,
383385
uint64_t recv_cnt = 0, uint64_t send_cnt = 0):
384386
m_connection_id(connection_id),
@@ -400,7 +402,7 @@ namespace net_utils
400402
m_remote_address(),
401403
m_is_income(false),
402404
m_started(time(NULL)),
403-
m_ssl(false),
405+
m_ssl(ssl_support_t::e_ssl_support_disabled),
404406
m_last_recv(0),
405407
m_last_send(0),
406408
m_recv_cnt(0),
@@ -421,11 +423,18 @@ namespace net_utils
421423
set_details(a.m_connection_id, a.m_remote_address, a.m_is_income, a.m_ssl);
422424
return *this;
423425
}
426+
427+
bool should_pad() const
428+
{
429+
if (m_remote_address.get_zone() == zone::public_)
430+
return m_ssl != ssl_support_t::e_ssl_support_disabled;
431+
return true; // all other zones use encryption by default
432+
}
424433

425434
private:
426435
template<class t_protocol_handler>
427436
friend class connection;
428-
void set_details(boost::uuids::uuid connection_id, const network_address &remote_address, bool is_income, bool ssl)
437+
void set_details(boost::uuids::uuid connection_id, const network_address &remote_address, bool is_income, ssl_support_t ssl)
429438
{
430439
this->~connection_context_base();
431440
new(this) connection_context_base(connection_id, remote_address, is_income, ssl);

contrib/epee/include/storages/levin_abstract_invoke2.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ namespace epee
111111
levin::message_writer to_send;
112112
stg.store_to_binary(to_send.buffer);
113113

114-
int res = transport.send(to_send.finalize_notify(command), conn_id);
114+
const bool ssl = (context.m_ssl != ssl_support_t::e_ssl_support_disabled);
115+
int res = transport.send(to_send.finalize_notify(command, ssl), conn_id);
115116
if(res <=0 )
116117
{
117118
MERROR("Failed to notify command " << command << " return code " << res);

contrib/epee/src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ target_link_libraries(epee
7070
${Boost_REGEX_LIBRARY}
7171
${Boost_SYSTEM_LIBRARY}
7272
${OPENSSL_LIBRARIES}
73+
${SODIUM_LIBRARY}
7374
PRIVATE
7475
${EXTRA_LIBRARIES})
7576

0 commit comments

Comments
 (0)