From 25f3000a78b56f945ed4814a28440b6232bfaa2d Mon Sep 17 00:00:00 2001 From: Seva Date: Mon, 12 Aug 2019 14:27:59 -0400 Subject: [PATCH] http: verify peer only if certificate provided --- include/opendht/dht_proxy_server.h | 4 +- include/opendht/http.h | 20 ++++--- src/dht_proxy_server.cpp | 11 ++-- src/http.cpp | 85 +++++++++++++++++++----------- 4 files changed, 73 insertions(+), 47 deletions(-) diff --git a/include/opendht/dht_proxy_server.h b/include/opendht/dht_proxy_server.h index c98ca30d..ce4792f1 100644 --- a/include/opendht/dht_proxy_server.h +++ b/include/opendht/dht_proxy_server.h @@ -347,8 +347,8 @@ private: std::thread httpServerThread_; std::unique_ptr> httpServer_; #ifdef OPENDHT_PROXY_OPENSSL - std::unique_ptr pk_; - std::unique_ptr cc_; + std::unique_ptr pk_; + std::unique_ptr cc_; #endif // http client diff --git a/include/opendht/http.h b/include/opendht/http.h index 469a8610..84635c8f 100644 --- a/include/opendht/http.h +++ b/include/opendht/http.h @@ -45,11 +45,10 @@ using socket_t = asio::ip::tcp::socket; class OPENDHT_PUBLIC Connection { public: -#ifdef OPENDHT_PROXY_OPENSSL - Connection(asio::io_context& ctx, asio::ssl::context_base::method&& ssl_method, - std::shared_ptr l = {}); -#else Connection(asio::io_context& ctx, std::shared_ptr l = {}); +#ifdef OPENDHT_PROXY_OPENSSL + Connection(asio::io_context& ctx, std::shared_ptr certificate, + std::shared_ptr l = {}); #endif ~Connection(); @@ -57,10 +56,11 @@ public: bool is_open(); bool is_v6(); - void set_endpoint(const asio::ip::tcp::endpoint& endpoint); + void set_endpoint(const asio::ip::tcp::endpoint& endpoint #ifdef OPENDHT_PROXY_OPENSSL - void set_verify_certificate(const std::string hostname, const asio::ssl::verify_mode verify_mode); + , const asio::ssl::verify_mode verify_mode = asio::ssl::verify_none #endif + ); asio::streambuf& input(); asio::streambuf& data(); @@ -84,8 +84,8 @@ private: asio::io_context& ctx_; std::unique_ptr socket_; #ifdef OPENDHT_PROXY_OPENSSL + std::unique_ptr certificate_; std::shared_ptr ssl_ctx_; - asio::ssl::context::options ssl_options_; #endif asio::ip::tcp::endpoint endpoint_; @@ -205,6 +205,9 @@ public: unsigned int id() const; void set_connection(std::shared_ptr connection); std::shared_ptr get_connection() const; +#ifdef OPENDHT_PROXY_OPENSSL + void set_certificate(std::shared_ptr certificate); +#endif void set_logger(std::shared_ptr logger); @@ -282,6 +285,9 @@ private: std::unique_ptr cbs_; State state_; +#ifdef OPENDHT_PROXY_OPENSSL + std::shared_ptr certificate_; +#endif std::string service_; std::string host_; diff --git a/src/dht_proxy_server.cpp b/src/dht_proxy_server.cpp index 977952ab..f629345e 100644 --- a/src/dht_proxy_server.cpp +++ b/src/dht_proxy_server.cpp @@ -90,19 +90,16 @@ DhtProxyServer::DhtProxyServer( asio::error_code ec; // node private key auto pk = identity.first->serialize(); // returns Blob - pk_ = std::make_unique(static_cast(pk.data()), - (std::size_t) pk.size()); + pk_ = std::make_unique(static_cast(pk.data()), (std::size_t) pk.size()); tls_context.use_private_key(*pk_, asio::ssl::context::file_format::pem, ec); if (ec) - throw std::runtime_error("Error setting Node private key: " + ec.message()); + throw std::runtime_error("Error setting node's private key: " + ec.message()); // certificate chain auto cc = identity.second->toString(true/*chain*/); - auto ccb = dht::Blob(cc.begin(), cc.end()); - cc_ = std::make_unique(static_cast(ccb.data()), - (std::size_t) ccb.size()); + cc_ = std::make_unique(static_cast(cc.data()), (std::size_t) cc.size()); tls_context.use_certificate_chain(*cc_, ec); if (ec) - throw std::runtime_error("Error setting CA chain file: " + ec.message()); + throw std::runtime_error("Error setting certificate chain: " + ec.message()); settings.tls_context(std::move(tls_context)); #endif diff --git a/src/http.cpp b/src/http.cpp index 2b8290ff..b039bffc 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -32,21 +32,37 @@ constexpr char JSON_VALUE_DELIM = '\n'; unsigned int Connection::ids_ = 1; +Connection::Connection(asio::io_context& ctx, std::shared_ptr l) + : id_(Connection::ids_++), ctx_(ctx), logger_(l) +{ #ifdef OPENDHT_PROXY_OPENSSL -Connection::Connection(asio::io_context& ctx, asio::ssl::context_base::method&& ssl_method, + ssl_ctx_ = std::make_shared(asio::ssl::context::sslv23); + ssl_ctx_->set_default_verify_paths(); + ssl_ctx_->set_verify_mode(asio::ssl::verify_peer); + socket_ = std::make_unique(ctx_, ssl_ctx_); +#else + socket_ = std::make_unique(new socket_t(ctx)); +#endif +} + +Connection::Connection(asio::io_context& ctx, std::shared_ptr certificate, std::shared_ptr l) : id_(Connection::ids_++), ctx_(ctx), logger_(l) { - ssl_ctx_ = std::make_shared(std::move(ssl_method)); + ssl_ctx_ = std::make_shared(asio::ssl::context::sslv23); ssl_ctx_->set_default_verify_paths(); + + asio::error_code ec; + auto cert = certificate->toString(false/*chain*/); + certificate_ = std::make_unique(static_cast(cert.data()), + (std::size_t) cert.size()); + ssl_ctx_->use_certificate(*certificate_, asio::ssl::context::file_format::pem, ec); + if (ec) + throw std::runtime_error("Error setting certificate: " + ec.message()); + ssl_ctx_->set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert); socket_ = std::make_unique(ctx_, ssl_ctx_); } -#else -Connection::Connection(asio::io_context& ctx, std::shared_ptr l) - : id_(Connection::ids_++), ctx_(ctx), socket_(new socket_t(ctx)), logger_(l) -{} -#endif Connection::~Connection() { @@ -78,9 +94,17 @@ Connection::is_v6() } void -Connection::set_endpoint(const asio::ip::tcp::endpoint& endpoint) -{ +Connection::set_endpoint(const asio::ip::tcp::endpoint& endpoint +#ifdef OPENDHT_PROXY_OPENSSL + , const asio::ssl::verify_mode verify_mode +#endif +){ endpoint_ = endpoint; +#ifdef OPENDHT_PROXY_OPENSSL + auto hostname = endpoint_.address().to_string(); + socket_->asio_ssl_stream().set_verify_mode(verify_mode); + socket_->asio_ssl_stream().set_verify_callback(asio::ssl::rfc2818_verification(hostname)); +#endif } asio::streambuf& @@ -130,13 +154,6 @@ Connection::async_connect(std::vector&& endpoints, Conn } #ifdef OPENDHT_PROXY_OPENSSL -void -Connection::set_verify_certificate(const std::string hostname, const asio::ssl::verify_mode verify_mode) -{ - socket_->asio_ssl_stream().set_verify_mode(verify_mode); - socket_->asio_ssl_stream().set_verify_callback(asio::ssl::rfc2818_verification(hostname)); -} - void Connection::async_handshake(HandlerCb cb) { @@ -360,6 +377,14 @@ Request::get_connection() const return conn_; } +#ifdef OPENDHT_PROXY_OPENSSL +void +Request::set_certificate(std::shared_ptr certificate) +{ + certificate_ = certificate; +} +#endif + void Request::set_logger(std::shared_ptr logger) { @@ -574,21 +599,14 @@ Request::connect(std::vector&& endpoints, HandlerCb cb) eps.append(endpoint.address().to_string() + " "); logger_->d("[http:request:%i] [connect] begin endpoints { %s}", id_, eps.c_str()); } + if (certificate_) + conn_ = std::make_shared(ctx_, certificate_); + else + conn_ = std::make_shared(ctx_); -#ifdef OPENDHT_PROXY_OPENSSL - if (service_ == "https" or service_ == "443"){ - if (!conn_){ - logger_->e("[http:request:%i] [connect] undefined SSL connection", id_); - terminate(asio::error::connection_aborted); - } - } - conn_ = std::make_shared(ctx_, asio::ssl::context::sslv23); -#else - conn_ = std::make_shared(ctx_); -#endif + // try to connect to any until one works conn_->async_connect(std::move(endpoints), [this, cb] (const asio::error_code& ec, const asio::ip::tcp::endpoint& endpoint){ - // try to connect to any until one works if (ec == asio::error::operation_aborted) return; else if (ec){ @@ -598,11 +616,16 @@ Request::connect(std::vector&& endpoints, HandlerCb cb) else { if (logger_) logger_->d("[http:request:%i] [connect] success", id_); - // save the associated endpoint - conn_->set_endpoint(endpoint); + // save & verify the endpoint + if (!certificate_) + conn_->set_endpoint(endpoint); +#ifdef OPENDHT_PROXY_OPENSSL + else if (certificate_) + conn_->set_endpoint(endpoint, asio::ssl::verify_peer + | asio::ssl::verify_fail_if_no_peer_cert); +#endif } #ifdef OPENDHT_PROXY_OPENSSL - conn_->set_verify_certificate(endpoint.address().to_string(), asio::ssl::stream_base::client); conn_->async_handshake([this, cb](const asio::error_code& ec){ if (ec){ if (logger_)