1//
2// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3//
4// Distributed under the Boost Software License, Version 1.0. (See accompanying
5// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7// Official repository: https://github.com/boostorg/beast
8//
9
10#ifndef BOOST_BEAST_CORE_SSL_STREAM_HPP
11#define BOOST_BEAST_CORE_SSL_STREAM_HPP
12
13#include <boost/beast/core/detail/config.hpp>
14
15// This include is necessary to work with `ssl::stream` and `boost::beast::websocket::stream`
16#include <boost/beast/websocket/ssl.hpp>
17
18#include <boost/beast/core/flat_stream.hpp>
19
20// VFALCO We include this because anyone who uses ssl will
21// very likely need to check for ssl::error::stream_truncated
22#include <boost/asio/ssl/error.hpp>
23
24#include <boost/asio/ssl/stream.hpp>
25#include <cstddef>
26#include <memory>
27#include <type_traits>
28#include <utility>
29
30namespace boost {
31namespace beast {
32
33/** Provides stream-oriented functionality using OpenSSL
34
35 The stream class template provides asynchronous and blocking
36 stream-oriented functionality using SSL.
37
38 @par Thread Safety
39 @e Distinct @e objects: Safe.@n
40 @e Shared @e objects: Unsafe. The application must also ensure that all
41 asynchronous operations are performed within the same implicit or explicit
42 strand.
43
44 @par Example
45 To use this template with a @ref tcp_stream, you would write:
46 @code
47 net::io_context ioc;
48 net::ssl::context ctx{net::ssl::context::tlsv12};
49 beast::ssl_stream<beast::tcp_stream> sock{ioc, ctx};
50 @endcode
51
52 In addition to providing an interface identical to `net::ssl::stream`,
53 the wrapper has the following additional properties:
54
55 @li Satisfies @b MoveConstructible
56
57 @li Satisfies @b MoveAssignable
58
59 @li Constructible from a moved socket.
60
61 @li Uses @ref flat_stream internally, as a performance work-around for a
62 limitation of `net::ssl::stream` when writing buffer sequences
63 having length greater than one.
64
65 @par Concepts:
66 @li AsyncReadStream
67 @li AsyncWriteStream
68 @li Stream
69 @li SyncReadStream
70 @li SyncWriteStream
71*/
72template<class NextLayer>
73class ssl_stream
74 : public net::ssl::stream_base
75{
76 using ssl_stream_type = net::ssl::stream<NextLayer>;
77 using stream_type = boost::beast::flat_stream<ssl_stream_type>;
78
79 std::unique_ptr<stream_type> p_;
80
81public:
82 /// The native handle type of the SSL stream.
83 using native_handle_type =
84 typename ssl_stream_type::native_handle_type;
85
86 /// Structure for use with deprecated impl_type.
87 using impl_struct = typename ssl_stream_type::impl_struct;
88
89 /// The type of the next layer.
90 using next_layer_type = typename ssl_stream_type::next_layer_type;
91
92 /// The type of the executor associated with the object.
93 using executor_type = typename stream_type::executor_type;
94
95 /// Rebinds the stream type to another executor.
96 template<class Executor1>
97 struct rebind_executor
98 {
99 /// The stream type when rebound to the specified executor.
100 using other = ssl_stream<
101 typename stream_type::template rebind_executor<Executor1>::other
102 >;
103 };
104
105
106 /** Construct a stream.
107
108 This constructor creates a stream and initialises the underlying stream
109 object.
110
111 @param arg The argument to be passed to initialise the underlying stream.
112
113 @param ctx The SSL context to be used for the stream.
114 */
115 template<class Arg>
116 ssl_stream(
117 Arg&& arg,
118 net::ssl::context& ctx)
119 : p_(new stream_type{
120 std::forward<Arg>(arg), ctx})
121 {
122 }
123
124 /** Get the executor associated with the object.
125
126 This function may be used to obtain the executor object that the stream
127 uses to dispatch handlers for asynchronous operations.
128
129 @return A copy of the executor that stream will use to dispatch handlers.
130 */
131 executor_type
132 get_executor() noexcept
133 {
134 return p_->get_executor();
135 }
136
137 /** Get the underlying implementation in the native type.
138
139 This function may be used to obtain the underlying implementation of the
140 context. This is intended to allow access to context functionality that is
141 not otherwise provided.
142
143 @par Example
144 The native_handle() function returns a pointer of type @c SSL* that is
145 suitable for passing to functions such as @c SSL_get_verify_result and
146 @c SSL_get_peer_certificate:
147 @code
148 boost::beast::ssl_stream<net::ip::tcp::socket> ss{ioc, ctx};
149
150 // ... establish connection and perform handshake ...
151
152 if (X509* cert = SSL_get_peer_certificate(ss.native_handle()))
153 {
154 if (SSL_get_verify_result(ss.native_handle()) == X509_V_OK)
155 {
156 // ...
157 }
158 }
159 @endcode
160 */
161 native_handle_type
162 native_handle() noexcept
163 {
164 return p_->next_layer().native_handle();
165 }
166
167 /** Get a reference to the next layer.
168
169 This function returns a reference to the next layer in a stack of stream
170 layers.
171
172 @note The next layer is the wrapped stream and not the @ref flat_stream
173 used in the implementation.
174
175 @return A reference to the next layer in the stack of stream layers.
176 Ownership is not transferred to the caller.
177 */
178 next_layer_type const&
179 next_layer() const noexcept
180 {
181 return p_->next_layer().next_layer();
182 }
183
184 /** Get a reference to the next layer.
185
186 This function returns a reference to the next layer in a stack of stream
187 layers.
188
189 @note The next layer is the wrapped stream and not the @ref flat_stream
190 used in the implementation.
191
192 @return A reference to the next layer in the stack of stream layers.
193 Ownership is not transferred to the caller.
194 */
195 next_layer_type&
196 next_layer() noexcept
197 {
198 return p_->next_layer().next_layer();
199 }
200
201 /** Set the peer verification mode.
202
203 This function may be used to configure the peer verification mode used by
204 the stream. The new mode will override the mode inherited from the context.
205
206 @param v A bitmask of peer verification modes.
207
208 @throws boost::system::system_error Thrown on failure.
209
210 @note Calls @c SSL_set_verify.
211 */
212 void
213 set_verify_mode(net::ssl::verify_mode v)
214 {
215 p_->next_layer().set_verify_mode(v);
216 }
217
218 /** Set the peer verification mode.
219
220 This function may be used to configure the peer verification mode used by
221 the stream. The new mode will override the mode inherited from the context.
222
223 @param v A bitmask of peer verification modes. See `verify_mode` for
224 available values.
225
226 @param ec Set to indicate what error occurred, if any.
227
228 @note Calls @c SSL_set_verify.
229 */
230 void
231 set_verify_mode(net::ssl::verify_mode v,
232 boost::system::error_code& ec)
233 {
234 p_->next_layer().set_verify_mode(v, ec);
235 }
236
237 /** Set the peer verification depth.
238
239 This function may be used to configure the maximum verification depth
240 allowed by the stream.
241
242 @param depth Maximum depth for the certificate chain verification that
243 shall be allowed.
244
245 @throws boost::system::system_error Thrown on failure.
246
247 @note Calls @c SSL_set_verify_depth.
248 */
249 void
250 set_verify_depth(int depth)
251 {
252 p_->next_layer().set_verify_depth(depth);
253 }
254
255 /** Set the peer verification depth.
256
257 This function may be used to configure the maximum verification depth
258 allowed by the stream.
259
260 @param depth Maximum depth for the certificate chain verification that
261 shall be allowed.
262
263 @param ec Set to indicate what error occurred, if any.
264
265 @note Calls @c SSL_set_verify_depth.
266 */
267 void
268 set_verify_depth(
269 int depth, boost::system::error_code& ec)
270 {
271 p_->next_layer().set_verify_depth(depth, ec);
272 }
273
274 /** Set the callback used to verify peer certificates.
275
276 This function is used to specify a callback function that will be called
277 by the implementation when it needs to verify a peer certificate.
278
279 @param callback The function object to be used for verifying a certificate.
280 The function signature of the handler must be:
281 @code bool verify_callback(
282 bool preverified, // True if the certificate passed pre-verification.
283 verify_context& ctx // The peer certificate and other context.
284 ); @endcode
285 The return value of the callback is true if the certificate has passed
286 verification, false otherwise.
287
288 @throws boost::system::system_error Thrown on failure.
289
290 @note Calls @c SSL_set_verify.
291 */
292 template<class VerifyCallback>
293 void
294 set_verify_callback(VerifyCallback callback)
295 {
296 p_->next_layer().set_verify_callback(callback);
297 }
298
299 /** Set the callback used to verify peer certificates.
300
301 This function is used to specify a callback function that will be called
302 by the implementation when it needs to verify a peer certificate.
303
304 @param callback The function object to be used for verifying a certificate.
305 The function signature of the handler must be:
306 @code bool verify_callback(
307 bool preverified, // True if the certificate passed pre-verification.
308 net::verify_context& ctx // The peer certificate and other context.
309 ); @endcode
310 The return value of the callback is true if the certificate has passed
311 verification, false otherwise.
312
313 @param ec Set to indicate what error occurred, if any.
314
315 @note Calls @c SSL_set_verify.
316 */
317 template<class VerifyCallback>
318 void
319 set_verify_callback(VerifyCallback callback,
320 boost::system::error_code& ec)
321 {
322 p_->next_layer().set_verify_callback(callback, ec);
323 }
324
325 /** Perform SSL handshaking.
326
327 This function is used to perform SSL handshaking on the stream. The
328 function call will block until handshaking is complete or an error occurs.
329
330 @param type The type of handshaking to be performed, i.e. as a client or as
331 a server.
332
333 @throws boost::system::system_error Thrown on failure.
334 */
335 void
336 handshake(handshake_type type)
337 {
338 p_->next_layer().handshake(type);
339 }
340
341 /** Perform SSL handshaking.
342
343 This function is used to perform SSL handshaking on the stream. The
344 function call will block until handshaking is complete or an error occurs.
345
346 @param type The type of handshaking to be performed, i.e. as a client or as
347 a server.
348
349 @param ec Set to indicate what error occurred, if any.
350 */
351 void
352 handshake(handshake_type type,
353 boost::system::error_code& ec)
354 {
355 p_->next_layer().handshake(type, ec);
356 }
357
358 /** Perform SSL handshaking.
359
360 This function is used to perform SSL handshaking on the stream. The
361 function call will block until handshaking is complete or an error occurs.
362
363 @param type The type of handshaking to be performed, i.e. as a client or as
364 a server.
365
366 @param buffers The buffered data to be reused for the handshake.
367
368 @throws boost::system::system_error Thrown on failure.
369 */
370 template<class ConstBufferSequence>
371 void
372 handshake(
373 handshake_type type, ConstBufferSequence const& buffers)
374 {
375 p_->next_layer().handshake(type, buffers);
376 }
377
378 /** Perform SSL handshaking.
379
380 This function is used to perform SSL handshaking on the stream. The
381 function call will block until handshaking is complete or an error occurs.
382
383 @param type The type of handshaking to be performed, i.e. as a client or as
384 a server.
385
386 @param buffers The buffered data to be reused for the handshake.
387
388 @param ec Set to indicate what error occurred, if any.
389 */
390 template<class ConstBufferSequence>
391 void
392 handshake(handshake_type type,
393 ConstBufferSequence const& buffers,
394 boost::system::error_code& ec)
395 {
396 p_->next_layer().handshake(type, buffers, ec);
397 }
398
399 /** Start an asynchronous SSL handshake.
400
401 This function is used to asynchronously perform an SSL handshake on the
402 stream. This function call always returns immediately.
403
404 @param type The type of handshaking to be performed, i.e. as a client or as
405 a server.
406
407 @param handler The handler to be called when the handshake operation
408 completes. Copies will be made of the handler as required. The equivalent
409 function signature of the handler must be:
410 @code void handler(
411 const boost::system::error_code& error // Result of operation.
412 ); @endcode
413 */
414 template<BOOST_BEAST_ASYNC_TPARAM1 HandshakeHandler = net::default_completion_token_t<executor_type>>
415 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(HandshakeHandler, void(boost::system::error_code))
416 async_handshake(handshake_type type,
417 BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler = net::default_completion_token_t<executor_type>{})
418 {
419 return p_->next_layer().async_handshake(type,
420 BOOST_ASIO_MOVE_CAST(HandshakeHandler)(handler));
421 }
422
423 /** Start an asynchronous SSL handshake.
424
425 This function is used to asynchronously perform an SSL handshake on the
426 stream. This function call always returns immediately.
427
428 @param type The type of handshaking to be performed, i.e. as a client or as
429 a server.
430
431 @param buffers The buffered data to be reused for the handshake. Although
432 the buffers object may be copied as necessary, ownership of the underlying
433 buffers is retained by the caller, which must guarantee that they remain
434 valid until the handler is called.
435
436 @param handler The handler to be called when the handshake operation
437 completes. Copies will be made of the handler as required. The equivalent
438 function signature of the handler must be:
439 @code void handler(
440 const boost::system::error_code& error, // Result of operation.
441 std::size_t bytes_transferred // Amount of buffers used in handshake.
442 ); @endcode
443 */
444 template<class ConstBufferSequence,
445 BOOST_BEAST_ASYNC_TPARAM2 BufferedHandshakeHandler = net::default_completion_token_t<executor_type>>
446 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(BufferedHandshakeHandler, void(boost::system::error_code, std::size_t))
447 async_handshake(handshake_type type, ConstBufferSequence const& buffers,
448 BOOST_ASIO_MOVE_ARG(BufferedHandshakeHandler) handler
449 = net::default_completion_token_t<executor_type>{})
450 {
451 return p_->next_layer().async_handshake(type, buffers,
452 BOOST_ASIO_MOVE_CAST(BufferedHandshakeHandler)(handler));
453 }
454
455 /** Shut down SSL on the stream.
456
457 This function is used to shut down SSL on the stream. The function call
458 will block until SSL has been shut down or an error occurs.
459
460 @throws boost::system::system_error Thrown on failure.
461 */
462 void
463 shutdown()
464 {
465 p_->next_layer().shutdown();
466 }
467
468 /** Shut down SSL on the stream.
469
470 This function is used to shut down SSL on the stream. The function call
471 will block until SSL has been shut down or an error occurs.
472
473 @param ec Set to indicate what error occurred, if any.
474 */
475 void
476 shutdown(boost::system::error_code& ec)
477 {
478 p_->next_layer().shutdown(ec);
479 }
480
481 /** Asynchronously shut down SSL on the stream.
482
483 This function is used to asynchronously shut down SSL on the stream. This
484 function call always returns immediately.
485
486 @param handler The handler to be called when the handshake operation
487 completes. Copies will be made of the handler as required. The equivalent
488 function signature of the handler must be:
489 @code void handler(
490 const boost::system::error_code& error // Result of operation.
491 ); @endcode
492 */
493 template<BOOST_BEAST_ASYNC_TPARAM1 ShutdownHandler = net::default_completion_token_t<executor_type>>
494 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ShutdownHandler, void(boost::system::error_code))
495 async_shutdown(BOOST_ASIO_MOVE_ARG(ShutdownHandler) handler = net::default_completion_token_t<executor_type>{})
496 {
497 return p_->next_layer().async_shutdown(
498 BOOST_ASIO_MOVE_CAST(ShutdownHandler)(handler));
499 }
500
501 /** Write some data to the stream.
502
503 This function is used to write data on the stream. The function call will
504 block until one or more bytes of data has been written successfully, or
505 until an error occurs.
506
507 @param buffers The data to be written.
508
509 @returns The number of bytes written.
510
511 @throws boost::system::system_error Thrown on failure.
512
513 @note The `write_some` operation may not transmit all of the data to the
514 peer. Consider using the `net::write` function if you need to
515 ensure that all data is written before the blocking operation completes.
516 */
517 template<class ConstBufferSequence>
518 std::size_t
519 write_some(ConstBufferSequence const& buffers)
520 {
521 return p_->write_some(buffers);
522 }
523
524 /** Write some data to the stream.
525
526 This function is used to write data on the stream. The function call will
527 block until one or more bytes of data has been written successfully, or
528 until an error occurs.
529
530 @param buffers The data to be written to the stream.
531
532 @param ec Set to indicate what error occurred, if any.
533
534 @returns The number of bytes written. Returns 0 if an error occurred.
535
536 @note The `write_some` operation may not transmit all of the data to the
537 peer. Consider using the `net::write` function if you need to
538 ensure that all data is written before the blocking operation completes.
539 */
540 template<class ConstBufferSequence>
541 std::size_t
542 write_some(ConstBufferSequence const& buffers,
543 boost::system::error_code& ec)
544 {
545 return p_->write_some(buffers, ec);
546 }
547
548 /** Start an asynchronous write.
549
550 This function is used to asynchronously write one or more bytes of data to
551 the stream. The function call always returns immediately.
552
553 @param buffers The data to be written to the stream. Although the buffers
554 object may be copied as necessary, ownership of the underlying buffers is
555 retained by the caller, which must guarantee that they remain valid until
556 the handler is called.
557
558 @param handler The handler to be called when the write operation completes.
559 Copies will be made of the handler as required. The equivalent function
560 signature of the handler must be:
561 @code void handler(
562 const boost::system::error_code& error, // Result of operation.
563 std::size_t bytes_transferred // Number of bytes written.
564 ); @endcode
565
566 @note The `async_write_some` operation may not transmit all of the data to
567 the peer. Consider using the `net::async_write` function if you
568 need to ensure that all data is written before the asynchronous operation
569 completes.
570 */
571 template<class ConstBufferSequence,
572 BOOST_BEAST_ASYNC_TPARAM2 WriteHandler = net::default_completion_token_t<executor_type>>
573 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void(boost::system::error_code, std::size_t))
574 async_write_some(ConstBufferSequence const& buffers,
575 BOOST_ASIO_MOVE_ARG(WriteHandler) handler= net::default_completion_token_t<executor_type>{})
576 {
577 return p_->async_write_some(buffers,
578 BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
579 }
580
581 /** Read some data from the stream.
582
583 This function is used to read data from the stream. The function call will
584 block until one or more bytes of data has been read successfully, or until
585 an error occurs.
586
587 @param buffers The buffers into which the data will be read.
588
589 @returns The number of bytes read.
590
591 @throws boost::system::system_error Thrown on failure.
592
593 @note The `read_some` operation may not read all of the requested number of
594 bytes. Consider using the `net::read` function if you need to ensure
595 that the requested amount of data is read before the blocking operation
596 completes.
597 */
598 template<class MutableBufferSequence>
599 std::size_t
600 read_some(MutableBufferSequence const& buffers)
601 {
602 return p_->read_some(buffers);
603 }
604
605 /** Read some data from the stream.
606
607 This function is used to read data from the stream. The function call will
608 block until one or more bytes of data has been read successfully, or until
609 an error occurs.
610
611 @param buffers The buffers into which the data will be read.
612
613 @param ec Set to indicate what error occurred, if any.
614
615 @returns The number of bytes read. Returns 0 if an error occurred.
616
617 @note The `read_some` operation may not read all of the requested number of
618 bytes. Consider using the `net::read` function if you need to ensure
619 that the requested amount of data is read before the blocking operation
620 completes.
621 */
622 template<class MutableBufferSequence>
623 std::size_t
624 read_some(MutableBufferSequence const& buffers,
625 boost::system::error_code& ec)
626 {
627 return p_->read_some(buffers, ec);
628 }
629
630 /** Start an asynchronous read.
631
632 This function is used to asynchronously read one or more bytes of data from
633 the stream. The function call always returns immediately.
634
635 @param buffers The buffers into which the data will be read. Although the
636 buffers object may be copied as necessary, ownership of the underlying
637 buffers is retained by the caller, which must guarantee that they remain
638 valid until the handler is called.
639
640 @param handler The handler to be called when the read operation completes.
641 Copies will be made of the handler as required. The equivalent function
642 signature of the handler must be:
643 @code void handler(
644 const boost::system::error_code& error, // Result of operation.
645 std::size_t bytes_transferred // Number of bytes read.
646 ); @endcode
647
648 @note The `async_read_some` operation may not read all of the requested
649 number of bytes. Consider using the `net::async_read` function
650 if you need to ensure that the requested amount of data is read before
651 the asynchronous operation completes.
652 */
653 template<class MutableBufferSequence,
654 BOOST_BEAST_ASYNC_TPARAM2 ReadHandler = net::default_completion_token_t<executor_type>>
655 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void(boost::system::error_code, std::size_t))
656 async_read_some(MutableBufferSequence const& buffers,
657 BOOST_ASIO_MOVE_ARG(ReadHandler) handler
658 = net::default_completion_token_t<executor_type>{})
659 {
660 return p_->async_read_some(buffers,
661 BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
662 }
663
664 // These hooks are used to inform boost::beast::websocket::stream on
665 // how to tear down the connection as part of the WebSocket
666 // protocol specifications
667 #if ! BOOST_BEAST_DOXYGEN
668 template<class SyncStream>
669 friend
670 void
671 teardown(
672 boost::beast::role_type role,
673 ssl_stream<SyncStream>& stream,
674 boost::system::error_code& ec);
675
676 template<class AsyncStream, typename TeardownHandler>
677 friend
678 void
679 async_teardown(
680 boost::beast::role_type role,
681 ssl_stream<AsyncStream>& stream,
682 TeardownHandler&& handler);
683 #endif
684};
685
686#if ! BOOST_BEAST_DOXYGEN
687template<class SyncStream>
688void
689teardown(
690 boost::beast::role_type role,
691 ssl_stream<SyncStream>& stream,
692 boost::system::error_code& ec)
693{
694 // Just forward it to the underlying ssl::stream
695 using boost::beast::websocket::teardown;
696 teardown(role, *stream.p_, ec);
697}
698
699template<class AsyncStream,
700 typename TeardownHandler = net::default_completion_token_t<beast::executor_type<AsyncStream>>>
701void
702async_teardown(
703 boost::beast::role_type role,
704 ssl_stream<AsyncStream>& stream,
705 TeardownHandler&& handler = net::default_completion_token_t<beast::executor_type<AsyncStream>>{})
706{
707 // Just forward it to the underlying ssl::stream
708 using boost::beast::websocket::async_teardown;
709 async_teardown(role, *stream.p_,
710 std::forward<TeardownHandler>(handler));
711}
712#endif
713
714} // beast
715} // boost
716
717#endif
718

source code of boost/libs/beast/include/boost/beast/ssl/ssl_stream.hpp