RESTinio
Loading...
Searching...
No Matches
tls.hpp
Go to the documentation of this file.
1/*
2 restinio
3*/
4
5/*!
6 Support for https.
7*/
8
9#pragma once
10
11#include <restinio/traits.hpp>
12#include <restinio/impl/tls_socket.hpp>
13
14namespace restinio
15{
16
17namespace connection_state
18{
19
20/*!
21 * @brief Accessor to TLS-specific information related to a connection.
22 *
23 * @note
24 * You have to manually include `restinio/tls.hpp` to get the definition
25 * of that class. This definition is not present if you include only
26 * `restinio/core.hpp`
27 *
28 * @since v.0.6.0
29 */
31{
33
34public:
35 tls_accessor_t( tls_socket_t & tls_socket ) : m_tls_socket{tls_socket} {}
36
37 /*!
38 * @brief Get the access to native handle behind Asio's ssl_stream.
39 *
40 * Usage example:
41 * \code
42 * struct openssl_free_t {
43 * void operator()(void * ptr) const noexcept
44 * {
45 * OPENSSL_free( ptr );
46 * }
47 * };
48 *
49 * std::string extract_user_name_from_client_certificate(
50 * const restinio::connection_state::tls_accessor_t & info )
51 * {
52 * auto nhandle = info.native_handle();
53 *
54 * std::unique_ptr<X509, decltype(&X509_free)> client_cert{
55 * SSL_get_peer_certificate(nhandle),
56 * X509_free
57 * };
58 * if( !client_cert )
59 * throw std::runtime_error( "Unable to get client certificate!" );
60 *
61 * X509_NAME * subject_name = X509_get_subject_name( client_cert.get() );
62 *
63 * int last_pos = -1;
64 * last_pos = X509_NAME_get_index_by_NID(
65 * subject_name,
66 * NID_commonName,
67 * last_pos );
68 * if( last_pos < 0 )
69 * throw std::runtime_error( "commonName is not found!" );
70 *
71 * unsigned char * common_name_utf8{};
72 * if( ASN1_STRING_to_UTF8(
73 * &common_name_utf8,
74 * X509_NAME_ENTRY_get_data(
75 * X509_NAME_get_entry( subject_name, last_pos ) ) ) < 0 )
76 * throw std::runtime_error( "ASN1_STRING_to_UTF8 failed!" );
77 *
78 * std::unique_ptr<unsigned char, openssl_free_t > common_name_deleter{
79 * common_name_utf8
80 * };
81 *
82 * return { reinterpret_cast<char *>(common_name_utf8) };
83 * }
84 * \endcode
85 *
86 * @since v.0.6.0
87 */
88 [[nodiscard]]
89 auto native_handle() const noexcept
90 {
91 return m_tls_socket.asio_ssl_stream().native_handle();
92 }
93};
94
95//
96// The implementation of TLS-related part of notice_t.
97//
98
99template< typename Lambda >
100void
101accepted_t::try_inspect_tls( Lambda && lambda ) const
102{
103 if( m_tls_socket )
105}
106
107template< typename Lambda >
108decltype(auto)
109accepted_t::inspect_tls_or_throw( Lambda && lambda ) const
110{
111 if( !m_tls_socket )
112 throw exception_t{ "an attempt to call inspect_tls for "
113 "non-TLS-connection" };
114
115 return lambda( tls_accessor_t{*m_tls_socket} );
116}
117
118template< typename Lambda, typename T >
119T
120accepted_t::inspect_tls_or_default( Lambda && lambda, T && default_value ) const
121{
122 if( m_tls_socket )
123 return lambda( tls_accessor_t{*m_tls_socket} );
124
125 return default_value;
126}
127
128} /* namespace connection_state */
129
130//
131// tls_traits_t
132//
133
134template <
135 typename Timer_Factory,
136 typename Logger,
137 typename Request_Handler = default_request_handler_t,
138 typename Strand = asio_ns::strand< default_asio_executor > >
139using tls_traits_t = traits_t< Timer_Factory, Logger, Request_Handler, Strand, tls_socket_t >;
140
141//
142// single_thread_traits_t
143//
144
145template <
146 typename Timer_Factory,
147 typename Logger,
151
153
154//
155// prepare_connection_and_start_read()
156//
157
158//! Customizes connection init routine with an additional step:
159//! perform handshake and only then start reading.
160template < typename Connection, typename Start_Read_CB, typename Failed_CB >
161void
163 tls_socket_t & socket,
164 Connection & con,
165 Start_Read_CB start_read_cb,
166 Failed_CB failed_cb )
167{
168 socket.async_handshake(
169 asio_ns::ssl::stream_base::server,
170 [ start_read_cb = std::move( start_read_cb ),
171 failed_cb = std::move( failed_cb ),
172 con = con.shared_from_this() ]( const asio_ns::error_code & ec ){
173 if( !ec )
174 start_read_cb();
175 else
176 failed_cb( ec );
177 } );
178}
179
180//
181// socket_type_dependent_settings_t
182//
183
184//! Customizes extra settings needed for working with socket.
185/*!
186 Adds tls context setting.
187*/
188template < typename Settings >
190{
191protected:
193
194public:
198
199 //! Setup an exclusive TLS-context for server's settings.
200 Settings &
202 asio_ns::ssl::context context ) &
203 {
204 m_tls_context = std::make_shared< asio_ns::ssl::context >(
205 std::move( context ) );
206 return upcast_reference();
207 }
208
209 //! Setup an exclusive TLS-context for server's settings.
210 Settings &&
212 asio_ns::ssl::context context ) &&
213 {
214 return std::move( this->tls_context( std::move( context ) ) );
215 }
216
217 //! Setup a shared TLS-context for server's settings.
218 /*!
219 * This method can be used when several servers should share
220 * the same TLS context. Or if TLS should be shared with some
221 * other entity in an application.
222 *
223 * Example:
224 * @code
225 * using traits_t = restinio::default_tls_traits_t;
226 *
227 * auto tls_context = std::make_shared< asio::ssl::context >(
228 * asio::ssl::context::sslv23 );
229 * ... // Tuning of tls_context.
230 *
231 * restinio::server_settings_t< traits_t > first_settings;
232 * first_settings.address( "localhost" );
233 * first_settings.port( 443 );
234 * first_settings.tls_context( tls_context );
235 * ...
236 *
237 * restinio::server_settings_t< traits_t > second_settings;
238 * second_settings.address( "localhost" );
239 * second_settings.port( 5553 );
240 * second_settings.tls_context( tls_context );
241 * ...
242 * @endcode
243 *
244 * @since v.0.6.10
245 */
246 Settings &
248 std::shared_ptr< asio_ns::ssl::context > shared_context ) &
249 {
250 m_tls_context = std::move( shared_context );
251 return upcast_reference();
252 }
253
254 //! Setup a shared TLS-context for server's settings.
255 /*!
256 * This method can be used when several servers should share
257 * the same TLS context. Or if TLS should be shared with some
258 * other entity in an application.
259 *
260 * Example:
261 * @code
262 * using traits_t = restinio::default_tls_traits_t;
263 *
264 * auto tls_context = std::make_shared< asio::ssl::context >(
265 * asio::ssl::context::sslv23 );
266 * ... // Tuning of tls_context.
267 *
268 * auto first_server = restinio::run_async< traits_t >(
269 * restinio::own_io_context(),
270 * restinio::server_settings_t< traits_t >{}
271 * .address( "localhost" )
272 * .port( 443 )
273 * .tls_context( tls_context ),
274 * 4u );
275 *
276 * auto second_server = restinio::run_async< traits_t >(
277 * restinio::own_io_context(),
278 * restinio::server_settings_t< traits_t >{}
279 * .address( "localhost" )
280 * .port( 5553 )
281 * .tls_context( tls_context ),
282 * 4u );
283 * @endcode
284 *
285 * @since v.0.6.10
286 */
287 Settings &&
289 std::shared_ptr< asio_ns::ssl::context > shared_context ) &&
290 {
291 return std::move( this->tls_context( std::move(shared_context) ) );
292 }
293
294 //! Get away the TLS-context from settings.
295 /*!
296 * @note
297 * This method is intended to be used by RESTinio's internals.
298 *
299 * @since v.0.6.10
300 */
301 std::shared_ptr< asio_ns::ssl::context >
303 {
304 return std::move(m_tls_context);
305 }
306
307 private:
308 Settings &
310 {
311 return static_cast< Settings & >( *this );
312 }
313
314 std::shared_ptr< asio_ns::ssl::context > m_tls_context{
317 };
318};
319
320namespace impl
321{
322
323// An overload for the case of non-TLS-connection.
324inline tls_socket_t *
326 tls_socket_t & socket ) noexcept
327{
328 return &socket;
329}
330
331//
332// socket_supplier_t
333//
334
335//! A custom socket storage for tls_socket_t.
336template <>
338{
339 protected:
340 template < typename Settings >
342 Settings & settings,
343 asio_ns::io_context & io_context )
345 , m_io_context{ io_context }
346 {
347 m_sockets.reserve( settings.concurrent_accepts_count() );
348
349 while( m_sockets.size() < settings.concurrent_accepts_count() )
350 {
351 m_sockets.emplace_back( m_io_context, m_tls_context );
352 }
353 }
354
355 virtual ~socket_supplier_t() = default;
356
359 //! Index of a socket in the pool.
360 std::size_t idx )
361 {
362 return m_sockets.at( idx );
363 }
364
365 auto
367 //! Index of a socket in the pool.
368 std::size_t idx )
369 {
370 tls_socket_t res{ m_io_context, m_tls_context };
371 std::swap( res, m_sockets.at( idx ) );
372 return res;
373 }
374
375 //! The number of sockets that can be used for
376 //! cuncurrent accept operations.
377 auto
379 {
380 return m_sockets.size();
381 }
382
383 private:
384 std::shared_ptr< asio_ns::ssl::context > m_tls_context;
385 asio_ns::io_context & m_io_context;
387};
388
389} /* namespace impl */
390
391} /* namespace restinio */
decltype(auto) inspect_tls_or_throw(Lambda &&lambda) const
Calls the specified lambda-function if the accepted connection is a TLS-connection.
Definition tls.hpp:109
T inspect_tls_or_default(Lambda &&lambda, T &&default_value) const
Calls the specified lambda-function if the accepted connection is a TLS-connection.
Definition tls.hpp:120
tls_socket_t * m_tls_socket
An optional pointer to TLS-related connection.
void try_inspect_tls(Lambda &&lambda) const
Calls the specified lambda-function if the accepted connection is a TLS-connection.
Definition tls.hpp:101
Accessor to TLS-specific information related to a connection.
Definition tls.hpp:31
tls_accessor_t(tls_socket_t &tls_socket)
Definition tls.hpp:35
auto native_handle() const noexcept
Get the access to native handle behind Asio's ssl_stream.
Definition tls.hpp:89
Exception class for all exceptions thrown by RESTinio.
Definition exception.hpp:26
exception_t(const char *err)
Definition exception.hpp:29
A custom socket storage for tls_socket_t.
Definition tls.hpp:338
tls_socket_t & socket(std::size_t idx)
Definition tls.hpp:358
auto concurrent_accept_sockets_count() const
The number of sockets that can be used for cuncurrent accept operations.
Definition tls.hpp:378
std::shared_ptr< asio_ns::ssl::context > m_tls_context
Definition tls.hpp:384
std::vector< tls_socket_t > m_sockets
Definition tls.hpp:386
socket_supplier_t(Settings &settings, asio_ns::io_context &io_context)
Definition tls.hpp:341
Socket adapter for asio::ssl::stream< asio::ip::tcp::socket >.
socket_t & asio_ssl_stream()
Get an access to underlying Asio's socket.
Customizes extra settings needed for working with socket.
Definition tls.hpp:190
Settings & tls_context(std::shared_ptr< asio_ns::ssl::context > shared_context) &
Setup a shared TLS-context for server's settings.
Definition tls.hpp:247
Settings && tls_context(std::shared_ptr< asio_ns::ssl::context > shared_context) &&
Setup a shared TLS-context for server's settings.
Definition tls.hpp:288
std::shared_ptr< asio_ns::ssl::context > m_tls_context
Definition tls.hpp:314
Settings && tls_context(asio_ns::ssl::context context) &&
Setup an exclusive TLS-context for server's settings.
Definition tls.hpp:211
socket_type_dependent_settings_t(socket_type_dependent_settings_t &&)=default
Settings & tls_context(asio_ns::ssl::context context) &
Setup an exclusive TLS-context for server's settings.
Definition tls.hpp:201
std::shared_ptr< asio_ns::ssl::context > giveaway_tls_context()
Get away the TLS-context from settings.
Definition tls.hpp:302
tls_socket_t * make_tls_socket_pointer_for_state_listener(tls_socket_t &socket) noexcept
Definition tls.hpp:325
std::function< request_handling_status_t(request_handle_t) > default_request_handler_t
traits_t< Timer_Factory, Logger, Request_Handler, Strand, tls_socket_t > tls_traits_t
Definition tls.hpp:139
impl::tls_socket_t tls_socket_t
A public alias for the actual implementation of TLS-socket.
Definition tls_fwd.hpp:30
void prepare_connection_and_start_read(tls_socket_t &socket, Connection &con, Start_Read_CB start_read_cb, Failed_CB failed_cb)
Customizes connection init routine with an additional step: perform handshake and only then start rea...
Definition tls.hpp:162