aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/tls/asio/asio_async_base.h109
-rw-r--r--src/lib/tls/asio/asio_async_handshake_op.h129
-rw-r--r--src/lib/tls/asio/asio_async_ops.h368
-rw-r--r--src/lib/tls/asio/asio_async_read_op.h124
-rw-r--r--src/lib/tls/asio/asio_async_write_op.h99
-rw-r--r--src/lib/tls/asio/asio_error.h22
-rw-r--r--src/lib/tls/asio/asio_includes.h25
-rw-r--r--src/lib/tls/asio/asio_stream.h188
-rw-r--r--src/lib/tls/asio/info.txt9
-rw-r--r--src/tests/unit_asio_stream.cpp6
10 files changed, 476 insertions, 603 deletions
diff --git a/src/lib/tls/asio/asio_async_base.h b/src/lib/tls/asio/asio_async_base.h
deleted file mode 100644
index 6585ded55..000000000
--- a/src/lib/tls/asio/asio_async_base.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
-* TLS ASIO Stream Helper
-* (C) 2018-2019 Jack Lloyd
-* 2018-2019 Hannes Rantzsch, Tim Oesterreich, Rene Meusel
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_ASIO_ASYNC_BASE_H_
-#define BOTAN_ASIO_ASYNC_BASE_H_
-
-#include <botan/build.h>
-
-#include <boost/version.hpp>
-#if BOOST_VERSION >= 106600
-
-#include <botan/internal/asio_includes.h>
-
-namespace Botan {
-
-namespace TLS {
-
-/**
- * Base class for asynchronous stream operations.
- *
- * Asynchronous operations, used for example to implement an interface for boost::asio::async_read_some and
- * boost::asio::async_write_some, are based on boost::asio::coroutines.
- * Derived operations should implement a call operator and invoke it with the correct parameters upon construction. The
- * call operator needs to make sure that the user-provided handler is not called directly. Typically, yield / reenter is
- * used for this in the following fashion:
- *
- * ```
- * void operator()(boost::system::error_code ec, std::size_t bytes_transferred, bool isContinuation = true)
- * {
- * reenter(this)
- * {
- * // operation specific logic, repeatedly interacting with the stream_core and the next_layer (socket)
- *
- * // make sure intermediate initiating function is called
- * if(!isContinuation)
- * {
- * yield next_layer.async_operation(empty_buffer, this);
- * }
- *
- * // call the completion handler
- * complete_now(error_code, bytes_transferred);
- * }
- * }
- * ```
- *
- * Once the operation is completed and ready to call the completion handler it checks if an intermediate initiating
- * function has been called using the `isContinuation` parameter. If not, it will call an asynchronous operation, such
- * as `async_read_some`, with and empty buffer, set the object itself as the handler, and `yield`. As a result, the call
- * operator will be invoked again, this time as a continuation, and will jump to the location where it yielded before
- * using `reenter`. It is now safe to call the handler function via `complete_now`.
- *
- * \tparam Handler Type of the completion handler
- * \tparam Executor1 Type of the asio executor (usually derived from the lower layer)
- * \tparam Allocator Type of the allocator to be used
- */
-template <class Handler, class Executor1, class Allocator>
-class AsyncBase : public boost::asio::coroutine
- {
- public:
- using allocator_type = boost::asio::associated_allocator_t<Handler, Allocator>;
- using executor_type = boost::asio::associated_executor_t<Handler, Executor1>;
-
- allocator_type get_allocator() const noexcept
- {
- return boost::asio::get_associated_allocator(m_handler);
- }
-
- executor_type get_executor() const noexcept
- {
- return boost::asio::get_associated_executor(m_handler, m_work_guard_1.get_executor());
- }
-
- protected:
- template <class HandlerT>
- AsyncBase(HandlerT&& handler, const Executor1& executor)
- : m_handler(std::forward<HandlerT>(handler))
- , m_work_guard_1(executor)
- {
- }
-
- /**
- * Call the completion handler.
- *
- * This function should only be called after an intermediate initiating function has been called.
- *
- * @param args Arguments forwarded to the completion handler function.
- */
- template<class... Args>
- void complete_now(Args&& ... args)
- {
- m_work_guard_1.reset();
- m_handler(std::forward<Args>(args)...);
- }
-
- Handler m_handler;
- boost::asio::executor_work_guard<Executor1> m_work_guard_1;
- };
-
-} // namespace TLS
-
-} // namespace Botan
-
-#endif // BOOST_VERSION
-#endif // BOTAN_ASIO_ASYNC_BASE_H_
diff --git a/src/lib/tls/asio/asio_async_handshake_op.h b/src/lib/tls/asio/asio_async_handshake_op.h
deleted file mode 100644
index e209c91da..000000000
--- a/src/lib/tls/asio/asio_async_handshake_op.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
-* TLS Stream Helper
-* (C) 2018-2019 Jack Lloyd
-* 2018-2019 Hannes Rantzsch, Tim Oesterreich, Rene Meusel
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_ASIO_ASYNC_HANDSHAKE_OP_H_
-#define BOTAN_ASIO_ASYNC_HANDSHAKE_OP_H_
-
-#include <botan/build.h>
-
-#include <boost/version.hpp>
-#if BOOST_VERSION >= 106600
-
-#include <botan/asio_error.h>
-#include <botan/internal/asio_async_write_op.h>
-#include <botan/internal/asio_includes.h>
-
-#include <boost/asio/yield.hpp>
-
-namespace Botan {
-
-namespace TLS {
-
-template <class Handler, class Stream, class Allocator = std::allocator<void>>
-class AsyncHandshakeOperation : public AsyncBase<Handler, typename Stream::executor_type, Allocator>
- {
- public:
- /**
- * Construct and invoke an AsyncHandshakeOperation.
- *
- * @param handler Handler function to be called upon completion.
- * @param stream The stream from which the data will be read
- * @param ec Optional error code; used to report an error to the handler function.
- */
- template<class HandlerT>
- AsyncHandshakeOperation(
- HandlerT&& handler,
- Stream& stream,
- const boost::system::error_code& ec = {})
- : AsyncBase<Handler, typename Stream::executor_type, Allocator>(
- std::forward<HandlerT>(handler),
- stream.get_executor())
- , m_stream(stream)
- {
- this->operator()(ec, std::size_t(0), false);
- }
-
- AsyncHandshakeOperation(AsyncHandshakeOperation&&) = default;
-
- void operator()(boost::system::error_code ec, std::size_t bytesTransferred, bool isContinuation = true)
- {
- reenter(this)
- {
- if(bytesTransferred > 0 && !ec)
- {
- // Provide encrypted TLS data received from the network to TLS::Channel for decryption
- boost::asio::const_buffer read_buffer {m_stream.input_buffer().data(), bytesTransferred};
- try
- {
- m_stream.native_handle()->received_data(
- static_cast<const uint8_t*>(read_buffer.data()), read_buffer.size()
- );
- }
- catch(const TLS_Exception& e)
- {
- ec = e.type();
- }
- catch(const Botan::Exception& e)
- {
- ec = e.error_type();
- }
- catch(...)
- {
- ec = Botan::ErrorType::Unknown;
- }
- }
-
- if(m_stream.hasDataToSend() && !ec)
- {
- // Write encrypted TLS data provided by the TLS::Channel on the wire
-
- // Note: we construct `AsyncWriteOperation` with 0 as its last parameter (`plainBytesTransferred`). This
- // operation will eventually call `*this` as its own handler, passing the 0 back to this call operator.
- // This is necessary because the check of `bytesTransferred > 0` assumes that `bytesTransferred` bytes
- // were just read and are available in input_buffer for further processing.
- AsyncWriteOperation<
- AsyncHandshakeOperation<typename std::decay<Handler>::type, Stream, Allocator>,
- Stream,
- Allocator>
- op{std::move(*this), m_stream, 0};
- return;
- }
-
- if(!m_stream.native_handle()->is_active() && !ec)
- {
- // Read more encrypted TLS data from the network
- m_stream.next_layer().async_read_some(m_stream.input_buffer(), std::move(*this));
- return;
- }
-
- if(!isContinuation)
- {
- // Make sure the handler is not called without an intermediate initiating function.
- // "Reading" into a zero-byte buffer will complete immediately.
- m_ec = ec;
- yield m_stream.next_layer().async_read_some(boost::asio::mutable_buffer(), std::move(*this));
- ec = m_ec;
- }
-
- this->complete_now(ec);
- }
- }
-
- private:
- Stream& m_stream;
- boost::system::error_code m_ec;
- };
-
-} // namespace TLS
-
-} // namespace Botan
-
-#include <boost/asio/unyield.hpp>
-
-#endif // BOOST_VERSION
-#endif // BOTAN_ASIO_ASYNC_HANDSHAKE_OP_H_
diff --git a/src/lib/tls/asio/asio_async_ops.h b/src/lib/tls/asio/asio_async_ops.h
new file mode 100644
index 000000000..c94e48fd3
--- /dev/null
+++ b/src/lib/tls/asio/asio_async_ops.h
@@ -0,0 +1,368 @@
+/*
+* Helpers for TLS ASIO Stream
+* (C) 2018-2019 Jack Lloyd
+* 2018-2019 Hannes Rantzsch, Tim Oesterreich, Rene Meusel
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_ASIO_ASYNC_OPS_H_
+#define BOTAN_ASIO_ASYNC_OPS_H_
+
+#include <botan/build.h>
+
+#include <boost/version.hpp>
+#if BOOST_VERSION >= 106600
+
+#include <botan/asio_error.h>
+
+// We need to define BOOST_ASIO_DISABLE_SERIAL_PORT before any asio imports. Otherwise asio will include <termios.h>,
+// which interferes with Botan's amalgamation by defining macros like 'B0' and 'FF1'.
+#define BOOST_ASIO_DISABLE_SERIAL_PORT
+#include <boost/asio.hpp>
+#include <boost/asio/yield.hpp>
+
+namespace Botan {
+namespace TLS {
+namespace detail {
+
+/**
+ * Base class for asynchronous stream operations.
+ *
+ * Asynchronous operations, used for example to implement an interface for boost::asio::async_read_some and
+ * boost::asio::async_write_some, are based on boost::asio::coroutines.
+ * Derived operations should implement a call operator and invoke it with the correct parameters upon construction. The
+ * call operator needs to make sure that the user-provided handler is not called directly. Typically, yield / reenter is
+ * used for this in the following fashion:
+ *
+ * ```
+ * void operator()(boost::system::error_code ec, std::size_t bytes_transferred, bool isContinuation = true)
+ * {
+ * reenter(this)
+ * {
+ * // operation specific logic, repeatedly interacting with the stream_core and the next_layer (socket)
+ *
+ * // make sure intermediate initiating function is called
+ * if(!isContinuation)
+ * {
+ * yield next_layer.async_operation(empty_buffer, this);
+ * }
+ *
+ * // call the completion handler
+ * complete_now(error_code, bytes_transferred);
+ * }
+ * }
+ * ```
+ *
+ * Once the operation is completed and ready to call the completion handler it checks if an intermediate initiating
+ * function has been called using the `isContinuation` parameter. If not, it will call an asynchronous operation, such
+ * as `async_read_some`, with and empty buffer, set the object itself as the handler, and `yield`. As a result, the call
+ * operator will be invoked again, this time as a continuation, and will jump to the location where it yielded before
+ * using `reenter`. It is now safe to call the handler function via `complete_now`.
+ *
+ * \tparam Handler Type of the completion handler
+ * \tparam Executor1 Type of the asio executor (usually derived from the lower layer)
+ * \tparam Allocator Type of the allocator to be used
+ */
+template <class Handler, class Executor1, class Allocator>
+class AsyncBase : public boost::asio::coroutine
+ {
+ public:
+ using allocator_type = boost::asio::associated_allocator_t<Handler, Allocator>;
+ using executor_type = boost::asio::associated_executor_t<Handler, Executor1>;
+
+ allocator_type get_allocator() const noexcept
+ {
+ return boost::asio::get_associated_allocator(m_handler);
+ }
+
+ executor_type get_executor() const noexcept
+ {
+ return boost::asio::get_associated_executor(m_handler, m_work_guard_1.get_executor());
+ }
+
+ protected:
+ template <class HandlerT>
+ AsyncBase(HandlerT&& handler, const Executor1& executor)
+ : m_handler(std::forward<HandlerT>(handler))
+ , m_work_guard_1(executor)
+ {
+ }
+
+ /**
+ * Call the completion handler.
+ *
+ * This function should only be called after an intermediate initiating function has been called.
+ *
+ * @param args Arguments forwarded to the completion handler function.
+ */
+ template<class... Args>
+ void complete_now(Args&& ... args)
+ {
+ m_work_guard_1.reset();
+ m_handler(std::forward<Args>(args)...);
+ }
+
+ Handler m_handler;
+ boost::asio::executor_work_guard<Executor1> m_work_guard_1;
+ };
+
+template <class Handler, class Stream, class MutableBufferSequence, class Allocator = std::allocator<void>>
+class AsyncReadOperation : public AsyncBase<Handler, typename Stream::executor_type, Allocator>
+ {
+ public:
+ /**
+ * Construct and invoke an AsyncWriteOperation.
+ *
+ * @param handler Handler function to be called upon completion.
+ * @param stream The stream from which the data will be read
+ * @param buffers The buffers into which the data will be read.
+ * @param ec Optional error code; used to report an error to the handler function.
+ */
+ template <class HandlerT>
+ AsyncReadOperation(HandlerT&& handler,
+ Stream& stream,
+ const MutableBufferSequence& buffers,
+ const boost::system::error_code& ec = {})
+ : AsyncBase<Handler, typename Stream::executor_type, Allocator>(
+ std::forward<HandlerT>(handler),
+ stream.get_executor())
+ , m_stream(stream)
+ , m_buffers(buffers)
+ , m_decodedBytes(0)
+ {
+ this->operator()(ec, std::size_t(0), false);
+ }
+
+ AsyncReadOperation(AsyncReadOperation&&) = default;
+
+ void operator()(boost::system::error_code ec, std::size_t bytes_transferred, bool isContinuation = true)
+ {
+ reenter(this)
+ {
+ if(bytes_transferred > 0 && !ec)
+ {
+ // We have received encrypted data from the network, now hand it to TLS::Channel for decryption.
+ boost::asio::const_buffer read_buffer{m_stream.input_buffer().data(), bytes_transferred};
+ try
+ {
+ m_stream.native_handle()->received_data(
+ static_cast<const uint8_t*>(read_buffer.data()), read_buffer.size()
+ );
+ }
+ catch(const TLS_Exception& e)
+ {
+ ec = e.type();
+ }
+ catch(const Botan::Exception& e)
+ {
+ ec = e.error_type();
+ }
+ catch(...)
+ {
+ ec = Botan::ErrorType::Unknown;
+ }
+ }
+
+ if(!m_stream.hasReceivedData() && !ec && boost::asio::buffer_size(m_buffers) > 0)
+ {
+ // The channel did not decrypt a complete record yet, we need more data from the socket.
+ m_stream.next_layer().async_read_some(m_stream.input_buffer(), std::move(*this));
+ return;
+ }
+
+ if(m_stream.hasReceivedData() && !ec)
+ {
+ // The channel has decrypted a TLS record, now copy it to the output buffers.
+ m_decodedBytes = m_stream.copyReceivedData(m_buffers);
+ }
+
+ if(!isContinuation)
+ {
+ // Make sure the handler is not called without an intermediate initiating function.
+ // "Reading" into a zero-byte buffer will complete immediately.
+ m_ec = ec;
+ yield m_stream.next_layer().async_read_some(boost::asio::mutable_buffer(), std::move(*this));
+ ec = m_ec;
+ }
+
+ this->complete_now(ec, m_decodedBytes);
+ }
+ }
+
+ private:
+ Stream& m_stream;
+ MutableBufferSequence m_buffers;
+ std::size_t m_decodedBytes;
+ boost::system::error_code m_ec;
+ };
+
+template <typename Handler, class Stream, class Allocator = std::allocator<void>>
+class AsyncWriteOperation : public AsyncBase<Handler, typename Stream::executor_type, Allocator>
+ {
+ public:
+ /**
+ * Construct and invoke an AsyncWriteOperation.
+ *
+ * @param handler Handler function to be called upon completion.
+ * @param stream The stream from which the data will be read
+ * @param plainBytesTransferred Number of bytes to be reported to the user-provided handler function as
+ * bytes_transferred. This needs to be provided since the amount of plaintext data
+ * consumed from the input buffer can differ from the amount of encrypted data written
+ * to the next layer.
+ * @param ec Optional error code; used to report an error to the handler function.
+ */
+ template <class HandlerT>
+ AsyncWriteOperation(HandlerT&& handler,
+ Stream& stream,
+ std::size_t plainBytesTransferred,
+ const boost::system::error_code& ec = {})
+ : AsyncBase<Handler, typename Stream::executor_type, Allocator>(
+ std::forward<HandlerT>(handler),
+ stream.get_executor())
+ , m_stream(stream)
+ , m_plainBytesTransferred(plainBytesTransferred)
+ {
+ this->operator()(ec, std::size_t(0), false);
+ }
+
+ AsyncWriteOperation(AsyncWriteOperation&&) = default;
+
+ void operator()(boost::system::error_code ec, std::size_t bytes_transferred, bool isContinuation = true)
+ {
+ reenter(this)
+ {
+ // mark the number of encrypted bytes sent to the network as "consumed"
+ // Note: bytes_transferred will be zero on first call
+ m_stream.consumeSendBuffer(bytes_transferred);
+
+ if(m_stream.hasDataToSend() && !ec)
+ {
+ m_stream.next_layer().async_write_some(m_stream.sendBuffer(), std::move(*this));
+ return;
+ }
+
+ if(!isContinuation)
+ {
+ // Make sure the handler is not called without an intermediate initiating function.
+ // "Writing" to a zero-byte buffer will complete immediately.
+ m_ec = ec;
+ yield m_stream.next_layer().async_write_some(boost::asio::const_buffer(), std::move(*this));
+ ec = m_ec;
+ }
+
+ // The size of the sent TLS record can differ from the size of the payload due to TLS encryption. We need to
+ // tell the handler how many bytes of the original data we already processed.
+ this->complete_now(ec, m_plainBytesTransferred);
+ }
+ }
+
+ private:
+ Stream& m_stream;
+ std::size_t m_plainBytesTransferred;
+ boost::system::error_code m_ec;
+ };
+
+template <class Handler, class Stream, class Allocator = std::allocator<void>>
+class AsyncHandshakeOperation : public AsyncBase<Handler, typename Stream::executor_type, Allocator>
+ {
+ public:
+ /**
+ * Construct and invoke an AsyncHandshakeOperation.
+ *
+ * @param handler Handler function to be called upon completion.
+ * @param stream The stream from which the data will be read
+ * @param ec Optional error code; used to report an error to the handler function.
+ */
+ template<class HandlerT>
+ AsyncHandshakeOperation(
+ HandlerT&& handler,
+ Stream& stream,
+ const boost::system::error_code& ec = {})
+ : AsyncBase<Handler, typename Stream::executor_type, Allocator>(
+ std::forward<HandlerT>(handler),
+ stream.get_executor())
+ , m_stream(stream)
+ {
+ this->operator()(ec, std::size_t(0), false);
+ }
+
+ AsyncHandshakeOperation(AsyncHandshakeOperation&&) = default;
+
+ void operator()(boost::system::error_code ec, std::size_t bytesTransferred, bool isContinuation = true)
+ {
+ reenter(this)
+ {
+ if(bytesTransferred > 0 && !ec)
+ {
+ // Provide encrypted TLS data received from the network to TLS::Channel for decryption
+ boost::asio::const_buffer read_buffer {m_stream.input_buffer().data(), bytesTransferred};
+ try
+ {
+ m_stream.native_handle()->received_data(
+ static_cast<const uint8_t*>(read_buffer.data()), read_buffer.size()
+ );
+ }
+ catch(const TLS_Exception& e)
+ {
+ ec = e.type();
+ }
+ catch(const Botan::Exception& e)
+ {
+ ec = e.error_type();
+ }
+ catch(...)
+ {
+ ec = Botan::ErrorType::Unknown;
+ }
+ }
+
+ if(m_stream.hasDataToSend() && !ec)
+ {
+ // Write encrypted TLS data provided by the TLS::Channel on the wire
+
+ // Note: we construct `AsyncWriteOperation` with 0 as its last parameter (`plainBytesTransferred`). This
+ // operation will eventually call `*this` as its own handler, passing the 0 back to this call operator.
+ // This is necessary because the check of `bytesTransferred > 0` assumes that `bytesTransferred` bytes
+ // were just read and are available in input_buffer for further processing.
+ AsyncWriteOperation<
+ AsyncHandshakeOperation<typename std::decay<Handler>::type, Stream, Allocator>,
+ Stream,
+ Allocator>
+ op{std::move(*this), m_stream, 0};
+ return;
+ }
+
+ if(!m_stream.native_handle()->is_active() && !ec)
+ {
+ // Read more encrypted TLS data from the network
+ m_stream.next_layer().async_read_some(m_stream.input_buffer(), std::move(*this));
+ return;
+ }
+
+ if(!isContinuation)
+ {
+ // Make sure the handler is not called without an intermediate initiating function.
+ // "Reading" into a zero-byte buffer will complete immediately.
+ m_ec = ec;
+ yield m_stream.next_layer().async_read_some(boost::asio::mutable_buffer(), std::move(*this));
+ ec = m_ec;
+ }
+
+ this->complete_now(ec);
+ }
+ }
+
+ private:
+ Stream& m_stream;
+ boost::system::error_code m_ec;
+ };
+
+} // namespace detail
+} // namespace TLS
+} // namespace Botan
+
+#include <boost/asio/unyield.hpp>
+
+#endif // BOOST_VERSION
+#endif // BOTAN_ASIO_ASYNC_OPS_H_
diff --git a/src/lib/tls/asio/asio_async_read_op.h b/src/lib/tls/asio/asio_async_read_op.h
deleted file mode 100644
index 778977011..000000000
--- a/src/lib/tls/asio/asio_async_read_op.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
-* TLS Stream Helper
-* (C) 2018-2019 Jack Lloyd
-* 2018-2019 Hannes Rantzsch, Tim Oesterreich, Rene Meusel
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_ASIO_ASYNC_READ_OP_H_
-#define BOTAN_ASIO_ASYNC_READ_OP_H_
-
-#include <botan/build.h>
-
-#include <boost/version.hpp>
-#if BOOST_VERSION >= 106600
-
-#include <botan/asio_error.h>
-#include <botan/internal/asio_async_base.h>
-#include <botan/internal/asio_includes.h>
-
-#include <boost/asio/yield.hpp>
-
-namespace Botan {
-
-namespace TLS {
-
-template <class Handler, class Stream, class MutableBufferSequence, class Allocator = std::allocator<void>>
-class AsyncReadOperation : public AsyncBase<Handler, typename Stream::executor_type, Allocator>
- {
- public:
- /**
- * Construct and invoke an AsyncWriteOperation.
- *
- * @param handler Handler function to be called upon completion.
- * @param stream The stream from which the data will be read
- * @param buffers The buffers into which the data will be read.
- * @param ec Optional error code; used to report an error to the handler function.
- */
- template <class HandlerT>
- AsyncReadOperation(HandlerT&& handler,
- Stream& stream,
- const MutableBufferSequence& buffers,
- const boost::system::error_code& ec = {})
- : AsyncBase<Handler, typename Stream::executor_type, Allocator>(
- std::forward<HandlerT>(handler),
- stream.get_executor())
- , m_stream(stream)
- , m_buffers(buffers)
- , m_decodedBytes(0)
- {
- this->operator()(ec, std::size_t(0), false);
- }
-
- AsyncReadOperation(AsyncReadOperation&&) = default;
-
- void operator()(boost::system::error_code ec, std::size_t bytes_transferred, bool isContinuation = true)
- {
- reenter(this)
- {
- if(bytes_transferred > 0 && !ec)
- {
- // We have received encrypted data from the network, now hand it to TLS::Channel for decryption.
- boost::asio::const_buffer read_buffer{m_stream.input_buffer().data(), bytes_transferred};
- try
- {
- m_stream.native_handle()->received_data(
- static_cast<const uint8_t*>(read_buffer.data()), read_buffer.size()
- );
- }
- catch(const TLS_Exception& e)
- {
- ec = e.type();
- }
- catch(const Botan::Exception& e)
- {
- ec = e.error_type();
- }
- catch(...)
- {
- ec = Botan::ErrorType::Unknown;
- }
- }
-
- if(!m_stream.hasReceivedData() && !ec && boost::asio::buffer_size(m_buffers) > 0)
- {
- // The channel did not decrypt a complete record yet, we need more data from the socket.
- m_stream.next_layer().async_read_some(m_stream.input_buffer(), std::move(*this));
- return;
- }
-
- if(m_stream.hasReceivedData() && !ec)
- {
- // The channel has decrypted a TLS record, now copy it to the output buffers.
- m_decodedBytes = m_stream.copyReceivedData(m_buffers);
- }
-
- if(!isContinuation)
- {
- // Make sure the handler is not called without an intermediate initiating function.
- // "Reading" into a zero-byte buffer will complete immediately.
- m_ec = ec;
- yield m_stream.next_layer().async_read_some(boost::asio::mutable_buffer(), std::move(*this));
- ec = m_ec;
- }
-
- this->complete_now(ec, m_decodedBytes);
- }
- }
-
- private:
- Stream& m_stream;
- MutableBufferSequence m_buffers;
- std::size_t m_decodedBytes;
- boost::system::error_code m_ec;
- };
-
-} // namespace TLS
-
-} // namespace Botan
-
-#include <boost/asio/unyield.hpp>
-
-#endif // BOOST_VERSION
-#endif // BOTAN_ASIO_ASYNC_READ_OP_H_
diff --git a/src/lib/tls/asio/asio_async_write_op.h b/src/lib/tls/asio/asio_async_write_op.h
deleted file mode 100644
index b14d4ab44..000000000
--- a/src/lib/tls/asio/asio_async_write_op.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
-* TLS Stream Helper
-* (C) 2018-2019 Jack Lloyd
-* 2018-2019 Hannes Rantzsch, Tim Oesterreich, Rene Meusel
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_ASIO_ASYNC_WRITE_OP_H_
-#define BOTAN_ASIO_ASYNC_WRITE_OP_H_
-
-#include <botan/build.h>
-
-#include <boost/version.hpp>
-#if BOOST_VERSION >= 106600
-
-#include <botan/internal/asio_async_base.h>
-#include <botan/internal/asio_includes.h>
-
-#include <boost/asio/yield.hpp>
-
-namespace Botan {
-
-namespace TLS {
-
-template <typename Handler, class Stream, class Allocator = std::allocator<void>>
-class AsyncWriteOperation : public AsyncBase<Handler, typename Stream::executor_type, Allocator>
- {
- public:
- /**
- * Construct and invoke an AsyncWriteOperation.
- *
- * @param handler Handler function to be called upon completion.
- * @param stream The stream from which the data will be read
- * @param plainBytesTransferred Number of bytes to be reported to the user-provided handler function as
- * bytes_transferred. This needs to be provided since the amount of plaintext data
- * consumed from the input buffer can differ from the amount of encrypted data written
- * to the next layer.
- * @param ec Optional error code; used to report an error to the handler function.
- */
- template <class HandlerT>
- AsyncWriteOperation(HandlerT&& handler,
- Stream& stream,
- std::size_t plainBytesTransferred,
- const boost::system::error_code& ec = {})
- : AsyncBase<Handler, typename Stream::executor_type, Allocator>(
- std::forward<HandlerT>(handler),
- stream.get_executor())
- , m_stream(stream)
- , m_plainBytesTransferred(plainBytesTransferred)
- {
- this->operator()(ec, std::size_t(0), false);
- }
-
- AsyncWriteOperation(AsyncWriteOperation&&) = default;
-
- void operator()(boost::system::error_code ec, std::size_t bytes_transferred, bool isContinuation = true)
- {
- reenter(this)
- {
- // mark the number of encrypted bytes sent to the network as "consumed"
- // Note: bytes_transferred will be zero on first call
- m_stream.consumeSendBuffer(bytes_transferred);
-
- if(m_stream.hasDataToSend() && !ec)
- {
- m_stream.next_layer().async_write_some(m_stream.sendBuffer(), std::move(*this));
- return;
- }
-
- if(!isContinuation)
- {
- // Make sure the handler is not called without an intermediate initiating function.
- // "Writing" to a zero-byte buffer will complete immediately.
- m_ec = ec;
- yield m_stream.next_layer().async_write_some(boost::asio::const_buffer(), std::move(*this));
- ec = m_ec;
- }
-
- // The size of the sent TLS record can differ from the size of the payload due to TLS encryption. We need to
- // tell the handler how many bytes of the original data we already processed.
- this->complete_now(ec, m_plainBytesTransferred);
- }
- }
-
- private:
- Stream& m_stream;
- std::size_t m_plainBytesTransferred;
- boost::system::error_code m_ec;
- };
-
-} // namespace TLS
-
-} // namespace Botan
-
-#include <boost/asio/unyield.hpp>
-
-#endif // BOOST_VERSION
-#endif // BOTAN_ASIO_ASYNC_WRITE_OP_H_
diff --git a/src/lib/tls/asio/asio_error.h b/src/lib/tls/asio/asio_error.h
index 4e59a6906..7356ab3d7 100644
--- a/src/lib/tls/asio/asio_error.h
+++ b/src/lib/tls/asio/asio_error.h
@@ -23,8 +23,7 @@
namespace Botan {
namespace TLS {
-namespace detail {
-// TLS Alerts
+//! @brief An error category for TLS alerts
struct BotanAlertCategory : boost::system::error_category
{
const char* name() const noexcept override
@@ -45,6 +44,14 @@ inline const BotanAlertCategory& botan_alert_category() noexcept
return category;
}
+inline boost::system::error_code make_error_code(Botan::TLS::Alert::Type c)
+ {
+ return boost::system::error_code(static_cast<int>(c), Botan::TLS::botan_alert_category());
+ }
+
+} // namespace TLS
+
+//! @brief An error category for errors from Botan (other than TLS alerts)
struct BotanErrorCategory : boost::system::error_category
{
const char* name() const noexcept override
@@ -64,18 +71,9 @@ inline const BotanErrorCategory& botan_category() noexcept
return category;
}
-} // namespace detail
-
-inline boost::system::error_code make_error_code(Botan::TLS::Alert::Type c)
- {
- return boost::system::error_code(static_cast<int>(c), detail::botan_alert_category());
- }
-
-} // namespace TLS
-
inline boost::system::error_code make_error_code(Botan::ErrorType e)
{
- return boost::system::error_code(static_cast<int>(e), Botan::TLS::detail::botan_category());
+ return boost::system::error_code(static_cast<int>(e), Botan::botan_category());
}
} // namespace Botan
diff --git a/src/lib/tls/asio/asio_includes.h b/src/lib/tls/asio/asio_includes.h
deleted file mode 100644
index 494233d55..000000000
--- a/src/lib/tls/asio/asio_includes.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
-* TLS Stream Helper
-* (C) 2018-2019 Jack Lloyd
-* 2018-2019 Hannes Rantzsch, Tim Oesterreich, Rene Meusel
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_ASIO_INCLUDES_H_
-#define BOTAN_ASIO_INCLUDES_H_
-
-#include <botan/build.h>
-
-#ifdef BOTAN_HAS_BOOST_ASIO
-
- // We need to define BOOST_ASIO_DISABLE_SERIAL_PORT before any asio imports. Otherwise asio will include <termios.h>,
- // which interferes with Botan's amalgamation by defining macros like 'B0' and 'FF1'.
- #define BOOST_ASIO_DISABLE_SERIAL_PORT
- #include <boost/asio.hpp>
- #include <boost/asio/buffer.hpp>
- #include <boost/asio/coroutine.hpp>
- #include <boost/asio/ip/tcp.hpp>
-
-#endif // BOTAN_HAS_BOOST_ASIO
-#endif // BOTAN_ASIO_INCLUDES_H_
diff --git a/src/lib/tls/asio/asio_stream.h b/src/lib/tls/asio/asio_stream.h
index 9b501a01a..971d80b58 100644
--- a/src/lib/tls/asio/asio_stream.h
+++ b/src/lib/tls/asio/asio_stream.h
@@ -1,5 +1,5 @@
/*
-* TLS ASIO Stream Wrapper
+* TLS ASIO Stream
* (C) 2018-2019 Jack Lloyd
* 2018-2019 Hannes Rantzsch, Tim Oesterreich, Rene Meusel
*
@@ -15,32 +15,30 @@
#include <boost/version.hpp>
#if BOOST_VERSION >= 106600
-#include <botan/asio_error.h>
-
-#include <botan/internal/asio_async_handshake_op.h>
-#include <botan/internal/asio_async_read_op.h>
-#include <botan/internal/asio_async_write_op.h>
-#include <botan/internal/asio_includes.h>
+#include <botan/asio_async_ops.h>
#include <botan/asio_context.h>
+#include <botan/asio_error.h>
#include <botan/tls_callbacks.h>
#include <botan/tls_channel.h>
#include <botan/tls_client.h>
#include <botan/tls_magic.h>
+// We need to define BOOST_ASIO_DISABLE_SERIAL_PORT before any asio imports. Otherwise asio will include <termios.h>,
+// which interferes with Botan's amalgamation by defining macros like 'B0' and 'FF1'.
+#define BOOST_ASIO_DISABLE_SERIAL_PORT
+#include <boost/asio.hpp>
#include <boost/beast/core/flat_buffer.hpp>
#include <algorithm>
#include <memory>
-#include <thread>
#include <type_traits>
namespace Botan {
-
namespace TLS {
/**
- * boost::asio compatible SSL/TLS stream
+ * @brief boost::asio compatible SSL/TLS stream
*
* Currently only the TLS::Client specialization is implemented.
*
@@ -99,15 +97,13 @@ class Stream
lowest_layer_type& lowest_layer() { return m_nextLayer.lowest_layer(); }
const lowest_layer_type& lowest_layer() const { return m_nextLayer.lowest_layer(); }
- native_handle_type native_handle() { return m_channel.get(); }
+ native_handle_type native_handle() { return m_native_handle.get(); }
//
// -- -- configuration and callback setters
//
- /**
- * @throws Not_Implemented
- */
+ //! @throws Not_Implemented
template<typename VerifyCallback>
void set_verify_callback(VerifyCallback callback)
{
@@ -127,9 +123,7 @@ class Stream
ec = Botan::ErrorType::NotImplemented;
}
- /**
- * @throws Not_Implemented
- */
+ //! @throws Not_Implemented
void set_verify_depth(int depth)
{
BOTAN_UNUSED(depth);
@@ -147,9 +141,7 @@ class Stream
ec = Botan::ErrorType::NotImplemented;
}
- /**
- * @throws Not_Implemented
- */
+ //! @throws Not_Implemented
template <typename verify_mode>
void set_verify_mode(verify_mode v)
{
@@ -176,14 +168,10 @@ class Stream
const boost::asio::mutable_buffer& input_buffer() { return m_input_buffer; }
boost::asio::const_buffer sendBuffer() const { return m_send_buffer.data(); } // TODO: really .data() ?
- /**
- * Check if decrypted data is available in the receive buffer
- */
+ //! @brief Check if decrypted data is available in the receive buffer
bool hasReceivedData() const { return m_receive_buffer.size() > 0; }
- /**
- * Copy decrypted data into the user-provided buffer
- */
+ //! @brief Copy decrypted data into the user-provided buffer
template <typename MutableBufferSequence>
std::size_t copyReceivedData(MutableBufferSequence buffers)
{
@@ -196,14 +184,10 @@ class Stream
return copiedBytes;
}
- /**
- * Check if encrypted data is available in the send buffer
- */
+ //! @brief Check if encrypted data is available in the send buffer
bool hasDataToSend() const { return m_send_buffer.size() > 0; }
- /**
- * Mark bytes in the send buffer as consumed, removing them from the buffer
- */
+ //! @brief Mark bytes in the send buffer as consumed, removing them from the buffer
void consumeSendBuffer(std::size_t bytesConsumed) { m_send_buffer.consume(bytesConsumed); }
//
@@ -211,11 +195,12 @@ class Stream
//
/**
- * Performs SSL handshaking.
+ * @brief Performs SSL handshaking.
+ *
* The function call will block until handshaking is complete or an error occurs.
+ *
* @param type The type of handshaking to be performed, i.e. as a client or as a server.
- * @throws boost::system::system_error if error occured
- * @throws Invalid_Argument if Connection_Side could not be validated
+ * @throws boost::system::system_error if error occured, or if the chosen Connection_Side is not available
*/
void handshake(Connection_Side side)
{
@@ -225,14 +210,18 @@ class Stream
}
/**
- * Performs SSL handshaking.
+ * @brief Performs SSL handshaking.
+ *
* The function call will block until handshaking is complete or an error occurs.
+ *
* @param type The type of handshaking to be performed, i.e. as a client or as a server.
* @param ec Set to indicate what error occurred, if any.
*/
void handshake(Connection_Side side, boost::system::error_code& ec)
{
- setup_channel(side);
+ setup_native_handle(side, ec);
+ if(ec)
+ { return; }
while(!native_handle()->is_active())
{
@@ -241,14 +230,12 @@ class Stream
{ return; }
boost::asio::const_buffer read_buffer{input_buffer().data(), m_nextLayer.read_some(input_buffer(), ec)};
-
if(ec)
{ return; }
try
{
- native_handle()->received_data(static_cast<const uint8_t*>(read_buffer.data()),
- read_buffer.size());
+ native_handle()->received_data(static_cast<const uint8_t*>(read_buffer.data()), read_buffer.size());
}
catch(const TLS_Exception& e)
{
@@ -271,8 +258,10 @@ class Stream
}
/**
- * Starts an asynchronous SSL handshake.
+ * @brief Starts an asynchronous SSL handshake.
+ *
* This function call always returns immediately.
+ *
* @param type The type of handshaking to be performed, i.e. as a client or as a server.
* @param handler The handler to be called when the handshake operation completes.
* The equivalent function signature of the handler must be: void(boost::system::error_code)
@@ -285,19 +274,20 @@ class Stream
{
BOOST_ASIO_HANDSHAKE_HANDLER_CHECK(HandshakeHandler, handler) type_check;
- setup_channel(side);
+ boost::system::error_code ec;
+ setup_native_handle(side, ec);
+ // If ec is set by setup_native_handle, the AsyncHandshakeOperation created below will do nothing but call the
+ // handler with the error_code set appropriately - no need to early return here.
boost::asio::async_completion<HandshakeHandler, void(boost::system::error_code)> init(handler);
- AsyncHandshakeOperation<typename std::decay<HandshakeHandler>::type, Stream>
- op{std::move(init.completion_handler), *this};
+ detail::AsyncHandshakeOperation<typename std::decay<HandshakeHandler>::type, Stream>
+ op{std::move(init.completion_handler), *this, ec};
return init.result.get();
}
- /**
- * @throws Not_Implemented
- */
+ //! @throws Not_Implemented
template <typename ConstBufferSequence, typename BufferedHandshakeHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(BufferedHandshakeHandler,
void(boost::system::error_code, std::size_t))
@@ -306,7 +296,6 @@ class Stream
{
BOTAN_UNUSED(buffers, handler);
BOOST_ASIO_HANDSHAKE_HANDLER_CHECK(BufferedHandshakeHandler, handler) type_check;
- validate_connection_side(side);
throw Not_Implemented("buffered async handshake is not implemented");
}
@@ -315,8 +304,10 @@ class Stream
//
/**
- * Shut down SSL on the stream.
+ * @brief Shut down SSL on the stream.
+ *
* The function call will block until SSL has been shut down or an error occurs.
+ *
* @param ec Set to indicate what error occured, if any.
*/
void shutdown(boost::system::error_code& ec)
@@ -345,8 +336,10 @@ class Stream
}
/**
- * Shut down SSL on the stream.
+ * @brief Shut down SSL on the stream.
+ *
* The function call will block until SSL has been shut down or an error occurs.
+ *
* @throws boost::system::system_error if error occured
*/
void shutdown()
@@ -357,8 +350,10 @@ class Stream
}
/**
- * Asynchronously shut down SSL on the stream.
+ * @brief Asynchronously shut down SSL on the stream.
+ *
* This function call always returns immediately.
+ *
* @param handler The handler to be called when the handshake operation completes.
* The equivalent function signature of the handler must be: void(boost::system::error_code)
*/
@@ -377,8 +372,11 @@ class Stream
//
/**
- * Read some data from the stream. The function call will block until one or more bytes of data has
- * been read successfully, or until an error occurs.
+ * @brief Read some data from the stream.
+ *
+ * The function call will block until one or more bytes of data has been read successfully, or until an error
+ * occurs.
+ *
* @param buffers The buffers into which the data will be read.
* @param ec Set to indicate what error occured, if any.
* @return The number of bytes read. Returns 0 if an error occurred.
@@ -398,8 +396,10 @@ class Stream
}
/**
- * Read some data from the stream. The function call will block until one or more bytes of data has
- * been read successfully, or until an error occurs.
+ * @brief Read some data from the stream.
+ *
+ * The function call will block until one or more bytes of data has been read successfully, or until an error
+ * occurs.
*
* @param buffers The buffers into which the data will be read.
* @return The number of bytes read. Returns 0 if an error occurred.
@@ -415,8 +415,10 @@ class Stream
}
/**
- * Write some data to the stream. The function call will block until one or more bytes of data has been written
- * successfully, or until an error occurs.
+ * @brief Write some data to the stream.
+ *
+ * The function call will block until one or more bytes of data has been written successfully, or until an error
+ * occurs.
*
* @param buffers The data to be written.
* @param ec Set to indicate what error occurred, if any.
@@ -438,8 +440,10 @@ class Stream
}
/**
- * Write some data to the stream. The function call will block until one or more bytes of data has been written
- * successfully, or until an error occurs.
+ * @brief Write some data to the stream.
+ *
+ * The function call will block until one or more bytes of data has been written successfully, or until an error
+ * occurs.
*
* @param buffers The data to be written.
* @return The number of bytes written.
@@ -455,7 +459,7 @@ class Stream
}
/**
- * Start an asynchronous write. The function call always returns immediately.
+ * @brief Start an asynchronous write. The function call always returns immediately.
*
* @param buffers The data to be written.
* @param handler The handler to be called when the write operation completes. Copies will be made of the handler
@@ -478,19 +482,19 @@ class Stream
// we cannot be sure how many bytes were committed here so clear the send_buffer and let the
// AsyncWriteOperation call the handler with the error_code set
consumeSendBuffer(m_send_buffer.size());
- Botan::TLS::AsyncWriteOperation<typename std::decay<WriteHandler>::type, Stream>
+ detail::AsyncWriteOperation<typename std::decay<WriteHandler>::type, Stream>
op{std::move(init.completion_handler), *this, std::size_t(0), ec};
return init.result.get();
}
- Botan::TLS::AsyncWriteOperation<typename std::decay<WriteHandler>::type, Stream>
+ detail::AsyncWriteOperation<typename std::decay<WriteHandler>::type, Stream>
op{std::move(init.completion_handler), *this, sent};
return init.result.get();
}
/**
- * Start an asynchronous read. The function call always returns immediately.
+ * @brief Start an asynchronous read. The function call always returns immediately.
*
* @param buffers The buffers into which the data will be read. Although the buffers object may be copied as
* necessary, ownership of the underlying buffers is retained by the caller, which must guarantee
@@ -508,14 +512,14 @@ class Stream
boost::asio::async_completion<ReadHandler, void(boost::system::error_code, std::size_t)> init(handler);
- AsyncReadOperation<typename std::decay<ReadHandler>::type, Stream, MutableBufferSequence>
+ detail::AsyncReadOperation<typename std::decay<ReadHandler>::type, Stream, MutableBufferSequence>
op{std::move(init.completion_handler), *this, buffers};
return init.result.get();
}
protected:
/**
- * Helper class that implements Botan::TLS::Callbacks
+ * @brief Helper class that implements Botan::TLS::Callbacks
*
* This class is provided to the stream's native_handle (Botan::TLS::Channel) and implements the callback
* functions triggered by the native_handle.
@@ -568,43 +572,40 @@ class Stream
boost::beast::flat_buffer& m_send_buffer;
};
- // TODO: explain, note: c++17 makes this much better with constexpr if
+ // This is a helper construct to allow mocking the native_handle in test code. It is activated by explicitly
+ // specifying a (mocked) channel type template parameter when constructing the stream and does not attempt to
+ // instantiate the native_handle.
+ // Note: once we have C++17 we can achieve this much more elegantly using constexpr if.
template<class T = ChannelT>
typename std::enable_if<!std::is_same<Channel, T>::value>::type
- setup_channel(Connection_Side) {}
+ setup_native_handle(Connection_Side, boost::system::error_code&) {}
+ /**
+ * @brief Create the native handle.
+ *
+ * Depending on the desired connection side, this function will create a Botan::TLS::Client or a
+ * Botan::TLS::Server.
+ *
+ * @param side The desired connection side (client or server)
+ * @param ec Set to NotImplemented when side is SERVER - currently only CLIENT is implemented
+ */
template<class T = ChannelT>
typename std::enable_if<std::is_same<Channel, T>::value>::type
- setup_channel(Connection_Side side)
+ setup_native_handle(Connection_Side side, boost::system::error_code& ec)
{
- assert(side == CLIENT);
- m_channel = std::unique_ptr<Client>(new Client(m_core,
- *m_context.sessionManager,
- *m_context.credentialsManager,
- *m_context.policy,
- *m_context.randomNumberGenerator,
- m_context.serverInfo));
- }
-
- //! \brief validate the connection side (OpenSSL compatibility)
- void validate_connection_side(Connection_Side side)
- {
- if(side != CLIENT)
+ if(side == CLIENT)
{
- throw Invalid_Argument("wrong connection_side");
+ m_native_handle = std::unique_ptr<Client>(new Client(m_core,
+ *m_context.sessionManager,
+ *m_context.credentialsManager,
+ *m_context.policy,
+ *m_context.randomNumberGenerator,
+ m_context.serverInfo));
}
- }
-
- //! \brief validate the connection side (OpenSSL compatibility)
- bool validate_connection_side(Connection_Side side, boost::system::error_code& ec)
- {
- if(side != CLIENT)
+ else
{
- ec = Botan::ErrorType::InvalidArgument;
- return false;
+ ec = Botan::ErrorType::NotImplemented;
}
-
- return true;
}
size_t sendPendingEncryptedData(boost::system::error_code& ec)
@@ -693,7 +694,7 @@ class Stream
boost::beast::flat_buffer m_send_buffer;
StreamCore m_core;
- std::unique_ptr<ChannelT> m_channel;
+ std::unique_ptr<ChannelT> m_native_handle;
// Buffer space used to read input intended for the core
std::vector<uint8_t> m_input_buffer_space;
@@ -701,7 +702,6 @@ class Stream
};
} // namespace TLS
-
} // namespace Botan
#endif // BOOST_VERSION
diff --git a/src/lib/tls/asio/info.txt b/src/lib/tls/asio/info.txt
index 1e37ea2a3..7862a1c28 100644
--- a/src/lib/tls/asio/info.txt
+++ b/src/lib/tls/asio/info.txt
@@ -6,16 +6,9 @@ TLS_ASIO_STREAM -> 20181218
asio_context.h
asio_stream.h
asio_error.h
+asio_async_ops.h
</header:public>
-<header:internal>
-asio_async_base.h
-asio_async_handshake_op.h
-asio_async_read_op.h
-asio_async_write_op.h
-asio_includes.h
-</header:internal>
-
<requires>
boost
tls
diff --git a/src/tests/unit_asio_stream.cpp b/src/tests/unit_asio_stream.cpp
index a2d423785..704c4f305 100644
--- a/src/tests/unit_asio_stream.cpp
+++ b/src/tests/unit_asio_stream.cpp
@@ -1,5 +1,5 @@
/*
-* TLS ASIO Stream Wrapper
+* TLS ASIO Stream Unit Tests
* (C) 2018-2019 Jack Lloyd
* 2018-2019 Hannes Rantzsch, Tim Oesterreich, Rene Meusel
*
@@ -101,7 +101,7 @@ class AsioStream : public Botan::TLS::Stream<TestStream, MockChannel>
AsioStream(Botan::TLS::Context& context, Args&& ... args)
: Stream(context, args...)
{
- m_channel = std::unique_ptr<MockChannel>(new MockChannel(m_core));
+ m_native_handle = std::unique_ptr<MockChannel>(new MockChannel(m_core));
}
virtual ~AsioStream() = default;
@@ -114,7 +114,7 @@ class ThrowingAsioStream : public Botan::TLS::Stream<TestStream, ThrowingMockCha
ThrowingAsioStream(Botan::TLS::Context& context, Args&& ... args)
: Stream(context, args...)
{
- m_channel = std::unique_ptr<ThrowingMockChannel>(new ThrowingMockChannel(m_core));
+ m_native_handle = std::unique_ptr<ThrowingMockChannel>(new ThrowingMockChannel(m_core));
}
virtual ~ThrowingAsioStream() = default;