diff options
author | Lee Clagett <code@leeclagett.com> | 2019-03-19 16:04:32 -0400 |
---|---|---|
committer | Lee Clagett <code@leeclagett.com> | 2019-04-07 00:44:37 -0400 |
commit | eca0fea45a1fe2eb359c6fff5f5701e0b2fcdc5a (patch) | |
tree | dcd4b88bee4974e03ea82f667d7cfa45cee55df7 /contrib/epee/src | |
parent | Require server verification when SSL is enabled. (diff) | |
download | monero-eca0fea45a1fe2eb359c6fff5f5701e0b2fcdc5a.tar.xz |
Perform RFC 2818 hostname verification in client SSL handshakes
If the verification mode is `system_ca`, clients will now do hostname
verification. Thus, only certificates from expected hostnames are
allowed when SSL is enabled. This can be overridden by forcible setting
the SSL mode to autodetect.
Clients will also send the hostname even when `system_ca` is not being
performed. This leaks possible metadata, but allows servers providing
multiple hostnames to respond with the correct certificate. One example
is cloudflare, which getmonero.org is currently using.
Diffstat (limited to '')
-rw-r--r-- | contrib/epee/src/net_ssl.cpp | 15 |
1 files changed, 12 insertions, 3 deletions
diff --git a/contrib/epee/src/net_ssl.cpp b/contrib/epee/src/net_ssl.cpp index cf8fa68ee..fbc809043 100644 --- a/contrib/epee/src/net_ssl.cpp +++ b/contrib/epee/src/net_ssl.cpp @@ -311,7 +311,7 @@ bool ssl_options_t::has_fingerprint(boost::asio::ssl::verify_context &ctx) const return false; } -bool ssl_options_t::handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket, boost::asio::ssl::stream_base::handshake_type type) const +bool 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 { socket.next_layer().set_option(boost::asio::ip::tcp::no_delay(true)); @@ -330,11 +330,20 @@ bool ssl_options_t::handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::soc else { socket.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert); - socket.set_verify_callback([&](bool preverified, boost::asio::ssl::verify_context &ctx) + + // 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) { // preverified means it passed system or user CA check. System CA is never loaded // when fingerprints are whitelisted. - if (!preverified && !has_fingerprint(ctx)) + 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)) { // autodetect will reconnect without SSL - warn and keep connection encrypted if (support != ssl_support_t::e_ssl_support_autodetect) |