Skip to content

[#600] Add TLS SNI hostname to client options #601

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 19, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions boost/network/protocol/http/client/async_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ struct async_client
optional<string_type> verify_path,
optional<string_type> certificate_file,
optional<string_type> private_key_file,
optional<string_type> ciphers, long ssl_options)
optional<string_type> ciphers,
optional<string_type> sni_hostname, long ssl_options)
: connection_base(cache_resolved, follow_redirect, timeout),
service_ptr(service.get()
? service
Expand All @@ -57,6 +58,7 @@ struct async_client
certificate_file_(std::move(certificate_file)),
private_key_file_(std::move(private_key_file)),
ciphers_(std::move(ciphers)),
sni_hostname_(std::move(sni_hostname)),
ssl_options_(ssl_options),
always_verify_peer_(always_verify_peer) {
connection_base::resolver_strand_.reset(
Expand Down Expand Up @@ -84,7 +86,7 @@ struct async_client
connection_ = connection_base::get_connection(
resolver_, request_, always_verify_peer_, certificate_filename_,
verify_path_, certificate_file_, private_key_file_, ciphers_,
ssl_options_);
sni_hostname_, ssl_options_);
return connection_->send_request(method, request_, get_body, callback,
generator);
}
Expand All @@ -99,6 +101,7 @@ struct async_client
optional<string_type> certificate_file_;
optional<string_type> private_key_file_;
optional<string_type> ciphers_;
optional<string_type> sni_hostname_;
long ssl_options_;
bool always_verify_peer_;
};
Expand Down
3 changes: 2 additions & 1 deletion boost/network/protocol/http/client/connection/async_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ struct async_connection_base {
optional<string_type> certificate_file = optional<string_type>(),
optional<string_type> private_key_file = optional<string_type>(),
optional<string_type> ciphers = optional<string_type>(),
optional<string_type> sni_hostname = optional<string_type>(),
long ssl_options = 0) {
typedef http_async_connection<Tag, version_major, version_minor>
async_connection;
Expand All @@ -55,7 +56,7 @@ struct async_connection_base {
delegate_factory_type::new_connection_delegate(
resolver.get_io_service(), https, always_verify_peer,
certificate_filename, verify_path, certificate_file,
private_key_file, ciphers, ssl_options)));
private_key_file, ciphers, sni_hostname, ssl_options)));
BOOST_ASSERT(temp.get() != 0);
return temp;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,14 @@ struct connection_delegate_factory {
optional<string_type> certificate_filename,
optional<string_type> verify_path, optional<string_type> certificate_file,
optional<string_type> private_key_file, optional<string_type> ciphers,
long ssl_options) {
optional<string_type> sni_hostname, long ssl_options) {
connection_delegate_ptr delegate;
if (https) {
#ifdef BOOST_NETWORK_ENABLE_HTTPS
delegate.reset(new ssl_delegate(
service, always_verify_peer, certificate_filename, verify_path,
certificate_file, private_key_file, ciphers, ssl_options));
delegate.reset(new ssl_delegate(service, always_verify_peer,
certificate_filename, verify_path,
certificate_file, private_key_file,
ciphers, sni_hostname, ssl_options));
#else
BOOST_THROW_EXCEPTION(std::runtime_error("HTTPS not supported."));
#endif /* BOOST_NETWORK_ENABLE_HTTPS */
Expand All @@ -57,13 +58,13 @@ struct connection_delegate_factory {
};

} // namespace impl
/* impl */
} // namespace http
/* http */
} // namespace network
/* network */
} // namespace boost
/* boost */
/* impl */
} // namespace http
/* http */
} // namespace network
/* network */
} // namespace boost
/* boost */

#endif /* BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_DELEGATE_FACTORY_HPP_20110819 \
*/
20 changes: 11 additions & 9 deletions boost/network/protocol/http/client/connection/ssl_delegate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,18 @@ struct ssl_delegate : connection_delegate,
optional<std::string> verify_path,
optional<std::string> certificate_file,
optional<std::string> private_key_file,
optional<std::string> ciphers, long ssl_options);
optional<std::string> ciphers,
optional<std::string> sni_hostname, long ssl_options);

void connect(asio::ip::tcp::endpoint &endpoint, std::string host,
boost::uint16_t source_port,
function<void(system::error_code const &)> handler) override;
void write(asio::streambuf &command_streambuf,
function<void(system::error_code const &, size_t)> handler)
override;
void read_some(asio::mutable_buffers_1 const &read_buffer,
function<void(system::error_code const &, size_t)> handler)
override;
boost::uint16_t source_port,
function<void(system::error_code const &)> handler) override;
void write(
asio::streambuf &command_streambuf,
function<void(system::error_code const &, size_t)> handler) override;
void read_some(
asio::mutable_buffers_1 const &read_buffer,
function<void(system::error_code const &, size_t)> handler) override;
void disconnect() override;
~ssl_delegate() override;

Expand All @@ -49,6 +50,7 @@ struct ssl_delegate : connection_delegate,
optional<std::string> certificate_file_;
optional<std::string> private_key_file_;
optional<std::string> ciphers_;
optional<std::string> sni_hostname_;
long ssl_options_;
std::unique_ptr<asio::ssl::context> context_;
std::unique_ptr<asio::ip::tcp::socket> tcp_socket_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ boost::network::http::impl::ssl_delegate::ssl_delegate(
optional<std::string> certificate_filename,
optional<std::string> verify_path, optional<std::string> certificate_file,
optional<std::string> private_key_file, optional<std::string> ciphers,
long ssl_options)
optional<std::string> sni_hostname, long ssl_options)
: service_(service),
certificate_filename_(std::move(certificate_filename)),
verify_path_(std::move(verify_path)),
certificate_file_(std::move(certificate_file)),
private_key_file_(std::move(private_key_file)),
ciphers_(std::move(ciphers)),
sni_hostname_(std::move(sni_hostname)),
ssl_options_(ssl_options),
always_verify_peer_(always_verify_peer) {}

Expand Down Expand Up @@ -68,6 +69,8 @@ void boost::network::http::impl::ssl_delegate::connect(
socket_.reset(new asio::ssl::stream<asio::ip::tcp::socket &>(
*(tcp_socket_.get()), *context_));

if (sni_hostname_)
SSL_set_tlsext_host_name(socket_->native_handle(), sni_hostname_->c_str());
if (always_verify_peer_)
socket_->set_verify_callback(boost::asio::ssl::rfc2818_verification(host));
socket_->lowest_layer().async_connect(
Expand Down
23 changes: 15 additions & 8 deletions boost/network/protocol/http/client/connection/sync_ssl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,13 @@ struct https_sync_connection
https_sync_connection(
resolver_type& resolver, resolver_function_type resolve,
bool always_verify_peer, int timeout,
optional<string_type> /*unused*/const& certificate_filename =
optional<string_type> /*unused*/ const& certificate_filename =
optional<string_type>(),
optional<string_type> const& verify_path = optional<string_type>(),
optional<string_type> const& certificate_file = optional<string_type>(),
optional<string_type> const& private_key_file = optional<string_type>(),
optional<string_type> const& ciphers = optional<string_type>(),
optional<string_type> const& sni_hostname = optional<string_type>(),
long ssl_options = 0)
: connection_base(),
timeout_(timeout),
Expand Down Expand Up @@ -93,15 +94,18 @@ struct https_sync_connection
if (private_key_file)
context_.use_private_key_file(*private_key_file,
boost::asio::ssl::context::pem);
if (sni_hostname)
SSL_set_tlsext_host_name(socket_.native_handle(), sni_hostname->c_str());
}

void init_socket(string_type /*unused*/const& hostname, string_type const& port) {
void init_socket(string_type /*unused*/ const& hostname,
string_type const& port) {
connection_base::init_socket(socket_.lowest_layer(), resolver_, hostname,
port, resolve_);
socket_.handshake(boost::asio::ssl::stream_base::client);
}

void send_request_impl(string_type /*unused*/const& method,
void send_request_impl(string_type /*unused*/ const& method,
basic_request<Tag> const& request_,
body_generator_function_type generator) {
boost::asio::streambuf request_buffer;
Expand Down Expand Up @@ -142,7 +146,8 @@ struct https_sync_connection
connection_base::read_body(socket_, response_, response_buffer);
typename headers_range<basic_response<Tag> >::type connection_range =
headers(response_)["Connection"];
if (version_major == 1 && version_minor == 1 && !boost::empty(connection_range) &&
if (version_major == 1 && version_minor == 1 &&
!boost::empty(connection_range) &&
boost::iequals(boost::begin(connection_range)->second, "close")) {
close_socket();
} else if (version_major == 1 && version_minor == 0) {
Expand All @@ -157,17 +162,19 @@ struct https_sync_connection
boost::system::error_code ignored;
socket_.lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both,
ignored);
if (ignored != nullptr) { return;
}
if (ignored != nullptr) {
return;
}
socket_.lowest_layer().close(ignored);
}

~https_sync_connection() { close_socket(); }

private:
void handle_timeout(boost::system::error_code const& ec) {
if (!ec) { close_socket();
}
if (!ec) {
close_socket();
}
}

int timeout_;
Expand Down
35 changes: 17 additions & 18 deletions boost/network/protocol/http/client/facade.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ struct basic_response;

template <class Tag, unsigned version_major, unsigned version_minor>
struct basic_client_facade {

typedef typename string<Tag>::type string_type;
typedef basic_request<Tag> request;
typedef basic_response<Tag> response;
Expand Down Expand Up @@ -53,12 +52,12 @@ struct basic_client_facade {
body_generator_function_type());
}

response post(request request, string_type const& body = string_type(),
string_type const& content_type = string_type(),
body_callback_function_type body_handler =
body_callback_function_type(),
body_generator_function_type body_generator =
body_generator_function_type()) {
response post(
request request, string_type const& body = string_type(),
string_type const& content_type = string_type(),
body_callback_function_type body_handler = body_callback_function_type(),
body_generator_function_type body_generator =
body_generator_function_type()) {
if (body != string_type()) {
request << remove_header("Content-Length")
<< header("Content-Length",
Expand All @@ -82,10 +81,9 @@ struct basic_client_facade {
body_generator);
}

response post(request const& request,
body_generator_function_type body_generator,
body_callback_function_type callback =
body_generator_function_type()) {
response post(
request const& request, body_generator_function_type body_generator,
body_callback_function_type callback = body_generator_function_type()) {
return pimpl->request_skeleton(request, "POST", true, callback,
body_generator);
}
Expand All @@ -104,12 +102,12 @@ struct basic_client_facade {
return post(request, body, string_type(), callback, body_generator);
}

response put(request request, string_type const& body = string_type(),
string_type const& content_type = string_type(),
body_callback_function_type body_handler =
body_callback_function_type(),
body_generator_function_type body_generator =
body_generator_function_type()) {
response put(
request request, string_type const& body = string_type(),
string_type const& content_type = string_type(),
body_callback_function_type body_handler = body_callback_function_type(),
body_generator_function_type body_generator =
body_generator_function_type()) {
if (body != string_type()) {
request << remove_header("Content-Length")
<< header("Content-Length",
Expand Down Expand Up @@ -164,7 +162,8 @@ struct basic_client_facade {
options.always_verify_peer(), options.openssl_certificate(),
options.openssl_verify_path(), options.openssl_certificate_file(),
options.openssl_private_key_file(), options.openssl_ciphers(),
options.openssl_options(), options.io_service(), options.timeout()));
options.openssl_sni_hostname(), options.openssl_options(),
options.io_service(), options.timeout()));
}
};

Expand Down
13 changes: 13 additions & 0 deletions boost/network/protocol/http/client/options.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct client_options {
openssl_certificate_file_(),
openssl_private_key_file_(),
openssl_ciphers_(),
openssl_sni_hostname_(),
openssl_options_(0),
io_service_(),
always_verify_peer_(false),
Expand All @@ -41,6 +42,7 @@ struct client_options {
openssl_certificate_file_(other.openssl_certificate_file_),
openssl_private_key_file_(other.openssl_private_key_file_),
openssl_ciphers_(other.openssl_ciphers_),
openssl_sni_hostname_(other.openssl_sni_hostname_),
openssl_options_(other.openssl_options_),
io_service_(other.io_service_),
always_verify_peer_(other.always_verify_peer_),
Expand All @@ -60,6 +62,7 @@ struct client_options {
swap(openssl_certificate_file_, other.openssl_certificate_file_);
swap(openssl_private_key_file_, other.openssl_private_key_file_);
swap(openssl_ciphers_, other.openssl_ciphers_);
swap(openssl_sni_hostname_, other.openssl_sni_hostname_);
swap(openssl_options_, other.openssl_options_);
swap(io_service_, other.io_service_);
swap(always_verify_peer_, other.always_verify_peer_);
Expand Down Expand Up @@ -101,6 +104,11 @@ struct client_options {
return *this;
}

client_options& openssl_sni_hostname(string_type const& v) {
openssl_sni_hostname_ = v;
return *this;
}

client_options& openssl_options(long o) {
openssl_options_ = o;
return *this;
Expand Down Expand Up @@ -145,6 +153,10 @@ struct client_options {
return openssl_ciphers_;
}

boost::optional<string_type> openssl_sni_hostname() const {
return openssl_sni_hostname_;
}

long openssl_options() const { return openssl_options_; }

boost::shared_ptr<boost::asio::io_service> io_service() const {
Expand All @@ -163,6 +175,7 @@ struct client_options {
boost::optional<string_type> openssl_certificate_file_;
boost::optional<string_type> openssl_private_key_file_;
boost::optional<string_type> openssl_ciphers_;
boost::optional<string_type> openssl_sni_hostname_;
long openssl_options_;
boost::shared_ptr<boost::asio::io_service> io_service_;
bool always_verify_peer_;
Expand Down
5 changes: 3 additions & 2 deletions boost/network/protocol/http/client/pimpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,13 @@ struct basic_client_impl
optional<string_type> const& verify_path,
optional<string_type> const& certificate_file,
optional<string_type> const& private_key_file,
optional<string_type> const& ciphers, long ssl_options,
optional<string_type> const& ciphers,
optional<string_type> const& sni_hostname, long ssl_options,
boost::shared_ptr<boost::asio::io_service> service,
int timeout)
: base_type(cache_resolved, follow_redirect, always_verify_peer, timeout,
service, certificate_filename, verify_path, certificate_file,
private_key_file, ciphers, ssl_options) {}
private_key_file, ciphers, sni_hostname, ssl_options) {}

~basic_client_impl() = default;
};
Expand Down
Loading