Skip to content

Commit c8ffcf0

Browse files
author
Teddy Reed
committed
[cpp-netlib#600] Add TLS SNI hostname to client options
1 parent e654986 commit c8ffcf0

11 files changed

+106
-71
lines changed

boost/network/protocol/http/client/async_impl.hpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ struct async_client
4444
optional<string_type> verify_path,
4545
optional<string_type> certificate_file,
4646
optional<string_type> private_key_file,
47-
optional<string_type> ciphers, long ssl_options)
47+
optional<string_type> ciphers,
48+
optional<string_type> sni_hostname, long ssl_options)
4849
: connection_base(cache_resolved, follow_redirect, timeout),
4950
service_ptr(service.get()
5051
? service
@@ -57,6 +58,7 @@ struct async_client
5758
certificate_file_(std::move(certificate_file)),
5859
private_key_file_(std::move(private_key_file)),
5960
ciphers_(std::move(ciphers)),
61+
sni_hostname_(std::move(sni_hostname)),
6062
ssl_options_(ssl_options),
6163
always_verify_peer_(always_verify_peer) {
6264
connection_base::resolver_strand_.reset(
@@ -84,7 +86,7 @@ struct async_client
8486
connection_ = connection_base::get_connection(
8587
resolver_, request_, always_verify_peer_, certificate_filename_,
8688
verify_path_, certificate_file_, private_key_file_, ciphers_,
87-
ssl_options_);
89+
sni_hostname_, ssl_options_);
8890
return connection_->send_request(method, request_, get_body, callback,
8991
generator);
9092
}
@@ -99,6 +101,7 @@ struct async_client
99101
optional<string_type> certificate_file_;
100102
optional<string_type> private_key_file_;
101103
optional<string_type> ciphers_;
104+
optional<string_type> sni_hostname_;
102105
long ssl_options_;
103106
bool always_verify_peer_;
104107
};

boost/network/protocol/http/client/connection/async_base.hpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct async_connection_base {
4545
optional<string_type> certificate_file = optional<string_type>(),
4646
optional<string_type> private_key_file = optional<string_type>(),
4747
optional<string_type> ciphers = optional<string_type>(),
48+
optional<string_type> sni_hostname = optional<string_type>(),
4849
long ssl_options = 0) {
4950
typedef http_async_connection<Tag, version_major, version_minor>
5051
async_connection;
@@ -55,7 +56,7 @@ struct async_connection_base {
5556
delegate_factory_type::new_connection_delegate(
5657
resolver.get_io_service(), https, always_verify_peer,
5758
certificate_filename, verify_path, certificate_file,
58-
private_key_file, ciphers, ssl_options)));
59+
private_key_file, ciphers, sni_hostname, ssl_options)));
5960
BOOST_ASSERT(temp.get() != 0);
6061
return temp;
6162
}

boost/network/protocol/http/client/connection/connection_delegate_factory.hpp

+12-11
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,14 @@ struct connection_delegate_factory {
3939
optional<string_type> certificate_filename,
4040
optional<string_type> verify_path, optional<string_type> certificate_file,
4141
optional<string_type> private_key_file, optional<string_type> ciphers,
42-
long ssl_options) {
42+
optional<string_type> sni_hostname, long ssl_options) {
4343
connection_delegate_ptr delegate;
4444
if (https) {
4545
#ifdef BOOST_NETWORK_ENABLE_HTTPS
46-
delegate.reset(new ssl_delegate(
47-
service, always_verify_peer, certificate_filename, verify_path,
48-
certificate_file, private_key_file, ciphers, ssl_options));
46+
delegate.reset(new ssl_delegate(service, always_verify_peer,
47+
certificate_filename, verify_path,
48+
certificate_file, private_key_file,
49+
ciphers, sni_hostname, ssl_options));
4950
#else
5051
BOOST_THROW_EXCEPTION(std::runtime_error("HTTPS not supported."));
5152
#endif /* BOOST_NETWORK_ENABLE_HTTPS */
@@ -57,13 +58,13 @@ struct connection_delegate_factory {
5758
};
5859

5960
} // namespace impl
60-
/* impl */
61-
} // namespace http
62-
/* http */
63-
} // namespace network
64-
/* network */
65-
} // namespace boost
66-
/* boost */
61+
/* impl */
62+
} // namespace http
63+
/* http */
64+
} // namespace network
65+
/* network */
66+
} // namespace boost
67+
/* boost */
6768

6869
#endif /* BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_DELEGATE_FACTORY_HPP_20110819 \
6970
*/

boost/network/protocol/http/client/connection/ssl_delegate.hpp

+11-9
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,18 @@ struct ssl_delegate : connection_delegate,
2828
optional<std::string> verify_path,
2929
optional<std::string> certificate_file,
3030
optional<std::string> private_key_file,
31-
optional<std::string> ciphers, long ssl_options);
31+
optional<std::string> ciphers,
32+
optional<std::string> sni_hostname, long ssl_options);
3233

3334
void connect(asio::ip::tcp::endpoint &endpoint, std::string host,
34-
boost::uint16_t source_port,
35-
function<void(system::error_code const &)> handler) override;
36-
void write(asio::streambuf &command_streambuf,
37-
function<void(system::error_code const &, size_t)> handler)
38-
override;
39-
void read_some(asio::mutable_buffers_1 const &read_buffer,
40-
function<void(system::error_code const &, size_t)> handler)
41-
override;
35+
boost::uint16_t source_port,
36+
function<void(system::error_code const &)> handler) override;
37+
void write(
38+
asio::streambuf &command_streambuf,
39+
function<void(system::error_code const &, size_t)> handler) override;
40+
void read_some(
41+
asio::mutable_buffers_1 const &read_buffer,
42+
function<void(system::error_code const &, size_t)> handler) override;
4243
void disconnect() override;
4344
~ssl_delegate() override;
4445

@@ -49,6 +50,7 @@ struct ssl_delegate : connection_delegate,
4950
optional<std::string> certificate_file_;
5051
optional<std::string> private_key_file_;
5152
optional<std::string> ciphers_;
53+
optional<std::string> sni_hostname_;
5254
long ssl_options_;
5355
std::unique_ptr<asio::ssl::context> context_;
5456
std::unique_ptr<asio::ip::tcp::socket> tcp_socket_;

boost/network/protocol/http/client/connection/ssl_delegate.ipp

+4-1
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ boost::network::http::impl::ssl_delegate::ssl_delegate(
1616
optional<std::string> certificate_filename,
1717
optional<std::string> verify_path, optional<std::string> certificate_file,
1818
optional<std::string> private_key_file, optional<std::string> ciphers,
19-
long ssl_options)
19+
optional<std::string> sni_hostname, long ssl_options)
2020
: service_(service),
2121
certificate_filename_(std::move(certificate_filename)),
2222
verify_path_(std::move(verify_path)),
2323
certificate_file_(std::move(certificate_file)),
2424
private_key_file_(std::move(private_key_file)),
2525
ciphers_(std::move(ciphers)),
26+
sni_hostname_(std::move(sni_hostname)),
2627
ssl_options_(ssl_options),
2728
always_verify_peer_(always_verify_peer) {}
2829

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

72+
if (sni_hostname_)
73+
SSL_set_tlsext_host_name(socket_->native_handle(), sni_hostname_->c_str());
7174
if (always_verify_peer_)
7275
socket_->set_verify_callback(boost::asio::ssl::rfc2818_verification(host));
7376
socket_->lowest_layer().async_connect(

boost/network/protocol/http/client/connection/sync_ssl.hpp

+15-8
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,13 @@ struct https_sync_connection
5252
https_sync_connection(
5353
resolver_type& resolver, resolver_function_type resolve,
5454
bool always_verify_peer, int timeout,
55-
optional<string_type> /*unused*/const& certificate_filename =
55+
optional<string_type> /*unused*/ const& certificate_filename =
5656
optional<string_type>(),
5757
optional<string_type> const& verify_path = optional<string_type>(),
5858
optional<string_type> const& certificate_file = optional<string_type>(),
5959
optional<string_type> const& private_key_file = optional<string_type>(),
6060
optional<string_type> const& ciphers = optional<string_type>(),
61+
optional<string_type> const& sni_hostname = optional<string_type>(),
6162
long ssl_options = 0)
6263
: connection_base(),
6364
timeout_(timeout),
@@ -93,15 +94,18 @@ struct https_sync_connection
9394
if (private_key_file)
9495
context_.use_private_key_file(*private_key_file,
9596
boost::asio::ssl::context::pem);
97+
if (sni_hostname)
98+
SSL_set_tlsext_host_name(socket_.native_handle(), sni_hostname->c_str());
9699
}
97100

98-
void init_socket(string_type /*unused*/const& hostname, string_type const& port) {
101+
void init_socket(string_type /*unused*/ const& hostname,
102+
string_type const& port) {
99103
connection_base::init_socket(socket_.lowest_layer(), resolver_, hostname,
100104
port, resolve_);
101105
socket_.handshake(boost::asio::ssl::stream_base::client);
102106
}
103107

104-
void send_request_impl(string_type /*unused*/const& method,
108+
void send_request_impl(string_type /*unused*/ const& method,
105109
basic_request<Tag> const& request_,
106110
body_generator_function_type generator) {
107111
boost::asio::streambuf request_buffer;
@@ -142,7 +146,8 @@ struct https_sync_connection
142146
connection_base::read_body(socket_, response_, response_buffer);
143147
typename headers_range<basic_response<Tag> >::type connection_range =
144148
headers(response_)["Connection"];
145-
if (version_major == 1 && version_minor == 1 && !boost::empty(connection_range) &&
149+
if (version_major == 1 && version_minor == 1 &&
150+
!boost::empty(connection_range) &&
146151
boost::iequals(boost::begin(connection_range)->second, "close")) {
147152
close_socket();
148153
} else if (version_major == 1 && version_minor == 0) {
@@ -157,17 +162,19 @@ struct https_sync_connection
157162
boost::system::error_code ignored;
158163
socket_.lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both,
159164
ignored);
160-
if (ignored != nullptr) { return;
161-
}
165+
if (ignored != nullptr) {
166+
return;
167+
}
162168
socket_.lowest_layer().close(ignored);
163169
}
164170

165171
~https_sync_connection() { close_socket(); }
166172

167173
private:
168174
void handle_timeout(boost::system::error_code const& ec) {
169-
if (!ec) { close_socket();
170-
}
175+
if (!ec) {
176+
close_socket();
177+
}
171178
}
172179

173180
int timeout_;

boost/network/protocol/http/client/facade.hpp

+17-18
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ struct basic_response;
2525

2626
template <class Tag, unsigned version_major, unsigned version_minor>
2727
struct basic_client_facade {
28-
2928
typedef typename string<Tag>::type string_type;
3029
typedef basic_request<Tag> request;
3130
typedef basic_response<Tag> response;
@@ -53,12 +52,12 @@ struct basic_client_facade {
5352
body_generator_function_type());
5453
}
5554

56-
response post(request request, string_type const& body = string_type(),
57-
string_type const& content_type = string_type(),
58-
body_callback_function_type body_handler =
59-
body_callback_function_type(),
60-
body_generator_function_type body_generator =
61-
body_generator_function_type()) {
55+
response post(
56+
request request, string_type const& body = string_type(),
57+
string_type const& content_type = string_type(),
58+
body_callback_function_type body_handler = body_callback_function_type(),
59+
body_generator_function_type body_generator =
60+
body_generator_function_type()) {
6261
if (body != string_type()) {
6362
request << remove_header("Content-Length")
6463
<< header("Content-Length",
@@ -82,10 +81,9 @@ struct basic_client_facade {
8281
body_generator);
8382
}
8483

85-
response post(request const& request,
86-
body_generator_function_type body_generator,
87-
body_callback_function_type callback =
88-
body_generator_function_type()) {
84+
response post(
85+
request const& request, body_generator_function_type body_generator,
86+
body_callback_function_type callback = body_generator_function_type()) {
8987
return pimpl->request_skeleton(request, "POST", true, callback,
9088
body_generator);
9189
}
@@ -104,12 +102,12 @@ struct basic_client_facade {
104102
return post(request, body, string_type(), callback, body_generator);
105103
}
106104

107-
response put(request request, string_type const& body = string_type(),
108-
string_type const& content_type = string_type(),
109-
body_callback_function_type body_handler =
110-
body_callback_function_type(),
111-
body_generator_function_type body_generator =
112-
body_generator_function_type()) {
105+
response put(
106+
request request, string_type const& body = string_type(),
107+
string_type const& content_type = string_type(),
108+
body_callback_function_type body_handler = body_callback_function_type(),
109+
body_generator_function_type body_generator =
110+
body_generator_function_type()) {
113111
if (body != string_type()) {
114112
request << remove_header("Content-Length")
115113
<< header("Content-Length",
@@ -164,7 +162,8 @@ struct basic_client_facade {
164162
options.always_verify_peer(), options.openssl_certificate(),
165163
options.openssl_verify_path(), options.openssl_certificate_file(),
166164
options.openssl_private_key_file(), options.openssl_ciphers(),
167-
options.openssl_options(), options.io_service(), options.timeout()));
165+
options.openssl_sni_hostname(), options.openssl_options(),
166+
options.io_service(), options.timeout()));
168167
}
169168
};
170169

boost/network/protocol/http/client/options.hpp

+13
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ struct client_options {
2828
openssl_certificate_file_(),
2929
openssl_private_key_file_(),
3030
openssl_ciphers_(),
31+
openssl_sni_hostname_(),
3132
openssl_options_(0),
3233
io_service_(),
3334
always_verify_peer_(false),
@@ -41,6 +42,7 @@ struct client_options {
4142
openssl_certificate_file_(other.openssl_certificate_file_),
4243
openssl_private_key_file_(other.openssl_private_key_file_),
4344
openssl_ciphers_(other.openssl_ciphers_),
45+
openssl_sni_hostname_(other.openssl_sni_hostname_),
4446
openssl_options_(other.openssl_options_),
4547
io_service_(other.io_service_),
4648
always_verify_peer_(other.always_verify_peer_),
@@ -60,6 +62,7 @@ struct client_options {
6062
swap(openssl_certificate_file_, other.openssl_certificate_file_);
6163
swap(openssl_private_key_file_, other.openssl_private_key_file_);
6264
swap(openssl_ciphers_, other.openssl_ciphers_);
65+
swap(openssl_sni_hostname_, other.openssl_sni_hostname_);
6366
swap(openssl_options_, other.openssl_options_);
6467
swap(io_service_, other.io_service_);
6568
swap(always_verify_peer_, other.always_verify_peer_);
@@ -101,6 +104,11 @@ struct client_options {
101104
return *this;
102105
}
103106

107+
client_options& openssl_sni_hostname(string_type const& v) {
108+
openssl_sni_hostname_ = v;
109+
return *this;
110+
}
111+
104112
client_options& openssl_options(long o) {
105113
openssl_options_ = o;
106114
return *this;
@@ -145,6 +153,10 @@ struct client_options {
145153
return openssl_ciphers_;
146154
}
147155

156+
boost::optional<string_type> openssl_sni_hostname() const {
157+
return openssl_sni_hostname_;
158+
}
159+
148160
long openssl_options() const { return openssl_options_; }
149161

150162
boost::shared_ptr<boost::asio::io_service> io_service() const {
@@ -163,6 +175,7 @@ struct client_options {
163175
boost::optional<string_type> openssl_certificate_file_;
164176
boost::optional<string_type> openssl_private_key_file_;
165177
boost::optional<string_type> openssl_ciphers_;
178+
boost::optional<string_type> openssl_sni_hostname_;
166179
long openssl_options_;
167180
boost::shared_ptr<boost::asio::io_service> io_service_;
168181
bool always_verify_peer_;

boost/network/protocol/http/client/pimpl.hpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,13 @@ struct basic_client_impl
7373
optional<string_type> const& verify_path,
7474
optional<string_type> const& certificate_file,
7575
optional<string_type> const& private_key_file,
76-
optional<string_type> const& ciphers, long ssl_options,
76+
optional<string_type> const& ciphers,
77+
optional<string_type> const& sni_hostname, long ssl_options,
7778
boost::shared_ptr<boost::asio::io_service> service,
7879
int timeout)
7980
: base_type(cache_resolved, follow_redirect, always_verify_peer, timeout,
8081
service, certificate_filename, verify_path, certificate_file,
81-
private_key_file, ciphers, ssl_options) {}
82+
private_key_file, ciphers, sni_hostname, ssl_options) {}
8283

8384
~basic_client_impl() = default;
8485
};

0 commit comments

Comments
 (0)