aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/tls/asio
diff options
context:
space:
mode:
authorRenĂ© Meusel <[email protected]>2019-02-19 15:09:17 +0100
committerHannes Rantzsch <[email protected]>2019-04-16 10:47:44 +0200
commitae8fb39545a8d574fba15b3690093edce93e7b18 (patch)
tree8259a94fc673c12f172e15cb6ef4a1eeec3c3cf6 /src/lib/tls/asio
parent19317c96bde9f2bfe01c692f7e53051ebd0005e8 (diff)
move stream implementation to tls subdir
Diffstat (limited to 'src/lib/tls/asio')
-rw-r--r--src/lib/tls/asio/asio_async_handshake_op.h86
-rw-r--r--src/lib/tls/asio/asio_async_read_op.h74
-rw-r--r--src/lib/tls/asio/asio_async_write_op.h40
-rw-r--r--src/lib/tls/asio/asio_convert_exceptions.h117
-rw-r--r--src/lib/tls/asio/asio_error.h155
-rw-r--r--src/lib/tls/asio/asio_includes.h11
-rw-r--r--src/lib/tls/asio/asio_stream.h465
-rw-r--r--src/lib/tls/asio/asio_stream_base.h64
-rw-r--r--src/lib/tls/asio/asio_stream_core.h104
-rw-r--r--src/lib/tls/asio/info.txt23
10 files changed, 1139 insertions, 0 deletions
diff --git a/src/lib/tls/asio/asio_async_handshake_op.h b/src/lib/tls/asio/asio_async_handshake_op.h
new file mode 100644
index 000000000..6ef7fdf94
--- /dev/null
+++ b/src/lib/tls/asio/asio_async_handshake_op.h
@@ -0,0 +1,86 @@
+#ifndef BOTAN_ASIO_ASYNC_HANDSHAKE_OP_H_
+#define BOTAN_ASIO_ASYNC_HANDSHAKE_OP_H_
+
+#include <botan/internal/asio_async_write_op.h>
+#include <botan/internal/asio_convert_exceptions.h>
+#include <botan/internal/asio_stream_core.h>
+#include <botan/internal/asio_includes.h>
+
+namespace Botan {
+template <class Channel, class StreamLayer, class Handler>
+struct AsyncHandshakeOperation
+ {
+ AsyncHandshakeOperation(Channel* channel, StreamCore& core,
+ StreamLayer& nextLayer, Handler&& handler)
+ : channel_(channel),
+ core_(core),
+ nextLayer_(nextLayer),
+ handler_(std::forward<Handler>(handler)) {}
+
+ AsyncHandshakeOperation(AsyncHandshakeOperation&& right)
+ : channel_(right.channel_),
+ core_(right.core_),
+ nextLayer_(right.nextLayer_),
+ handler_(std::move(right.handler_)) {}
+
+ ~AsyncHandshakeOperation() = default;
+ AsyncHandshakeOperation(AsyncHandshakeOperation const&) = delete;
+
+ void operator()(boost::system::error_code ec,
+ std::size_t bytesTransferred = 0, int start = 0)
+ {
+ // process tls packets from socket first
+ if(bytesTransferred > 0)
+ {
+ auto read_buffer =
+ boost::asio::buffer(core_.input_buffer_, bytesTransferred);
+ try
+ {
+ channel_->received_data(
+ static_cast<const uint8_t*>(read_buffer.data()),
+ read_buffer.size());
+ }
+ catch(...)
+ {
+ ec = convertException();
+ handler_(ec);
+ return;
+ }
+ }
+
+ // send tls packets
+ if(core_.hasDataToSend())
+ {
+ AsyncWriteOperation<AsyncHandshakeOperation<Channel, StreamLayer, Handler>>
+ op{core_, std::move(*this), 0};
+ boost::asio::async_write(nextLayer_, core_.sendBuffer(),
+ std::move(op));
+ return;
+ }
+
+ if(!channel_->is_active() && !ec)
+ {
+ // we need more tls data from the socket
+ nextLayer_.async_read_some(core_.input_buffer_, std::move(*this));
+ return;
+ }
+
+ if(start)
+ {
+ // don't call the handler directly, similar to io_context.post
+ nextLayer_.async_read_some(
+ boost::asio::buffer(core_.input_buffer_, 0), std::move(*this));
+ return;
+ }
+ handler_(ec);
+ }
+
+ private:
+ Channel* channel_;
+ StreamCore& core_;
+ StreamLayer& nextLayer_;
+ Handler handler_;
+ };
+} // namespace Botan
+
+#endif
diff --git a/src/lib/tls/asio/asio_async_read_op.h b/src/lib/tls/asio/asio_async_read_op.h
new file mode 100644
index 000000000..56e5da7b6
--- /dev/null
+++ b/src/lib/tls/asio/asio_async_read_op.h
@@ -0,0 +1,74 @@
+#ifndef BOTAN_ASIO_ASYNC_READ_OP_H_
+#define BOTAN_ASIO_ASYNC_READ_OP_H_
+
+#include <botan/internal/asio_convert_exceptions.h>
+#include <botan/internal/asio_includes.h>
+#include <botan/internal/asio_stream_core.h>
+
+namespace Botan {
+
+template <class Channel, class StreamLayer, class Handler,
+ class MutableBufferSequence>
+struct AsyncReadOperation
+ {
+ AsyncReadOperation(Channel* channel, StreamCore& core, StreamLayer& nextLayer,
+ Handler&& handler, const MutableBufferSequence& buffers)
+ : channel_(channel), core_(core), nextLayer_(nextLayer),
+ handler_(std::forward<Handler>(handler)), buffers_(buffers) {}
+
+ AsyncReadOperation(AsyncReadOperation&& right)
+ : channel_(right.channel_), core_(right.core_),
+ nextLayer_(right.nextLayer_), handler_(std::move(right.handler_)),
+ buffers_(right.buffers_) {}
+
+ ~AsyncReadOperation() = default;
+ AsyncReadOperation(AsyncReadOperation const&) = delete;
+
+ void operator()(boost::system::error_code ec,
+ std::size_t bytes_transferred = ~std::size_t(0))
+ {
+ std::size_t decodedBytes = 0;
+
+ if(bytes_transferred > 0)
+ {
+ auto read_buffer =
+ boost::asio::buffer(core_.input_buffer_, bytes_transferred);
+ try
+ {
+ channel_->received_data(static_cast<const uint8_t*>(read_buffer.data()),
+ read_buffer.size());
+ }
+ catch(...)
+ {
+ // TODO: don't call handler directly
+ handler_(convertException(), 0);
+ return;
+ }
+ }
+
+ if(!core_.hasReceivedData() && !ec)
+ {
+ // we need more tls packets from the socket
+ nextLayer_.async_read_some(core_.input_buffer_, std::move(*this));
+ return;
+ }
+
+ if(core_.hasReceivedData())
+ {
+ decodedBytes = core_.copyReceivedData(buffers_);
+ ec = boost::system::error_code{};
+ }
+
+ handler_(ec, decodedBytes);
+ }
+
+ private:
+ Channel* channel_;
+ StreamCore& core_;
+ StreamLayer& nextLayer_;
+ Handler handler_;
+ MutableBufferSequence buffers_;
+ };
+} // namespace Botan
+
+#endif
diff --git a/src/lib/tls/asio/asio_async_write_op.h b/src/lib/tls/asio/asio_async_write_op.h
new file mode 100644
index 000000000..28611fe1f
--- /dev/null
+++ b/src/lib/tls/asio/asio_async_write_op.h
@@ -0,0 +1,40 @@
+#ifndef BOTAN_ASIO_ASYNC_WRITE_OP_H_
+#define BOTAN_ASIO_ASYNC_WRITE_OP_H_
+
+#include <botan/internal/asio_stream_core.h>
+#include <botan/internal/asio_includes.h>
+
+namespace Botan {
+
+template <typename Handler>
+struct AsyncWriteOperation
+ {
+ AsyncWriteOperation(StreamCore& core, Handler&& handler,
+ std::size_t plainBytesTransferred)
+ : core_(core),
+ handler_(std::forward<Handler>(handler)),
+ plainBytesTransferred_(plainBytesTransferred) {}
+
+ AsyncWriteOperation(AsyncWriteOperation&& right)
+ : core_(right.core_),
+ handler_(std::move(right.handler_)),
+ plainBytesTransferred_(right.plainBytesTransferred_) {}
+
+ ~AsyncWriteOperation() = default;
+ AsyncWriteOperation(AsyncWriteOperation const&) = delete;
+
+ void operator()(boost::system::error_code ec,
+ std::size_t bytes_transferred = ~std::size_t(0))
+ {
+ core_.consumeSendBuffer(bytes_transferred);
+ // TODO: make sure returning 0 in error case is correct here--core has already eaten the data
+ handler_(ec, ec ? 0 : plainBytesTransferred_);
+ }
+
+ StreamCore& core_;
+ Handler handler_;
+ std::size_t plainBytesTransferred_;
+ };
+} // namespace Botan
+
+#endif
diff --git a/src/lib/tls/asio/asio_convert_exceptions.h b/src/lib/tls/asio/asio_convert_exceptions.h
new file mode 100644
index 000000000..3a054be10
--- /dev/null
+++ b/src/lib/tls/asio/asio_convert_exceptions.h
@@ -0,0 +1,117 @@
+#ifndef BOTAN_ASIO_CONVERT_EXCEPTIONS_H_
+#define BOTAN_ASIO_CONVERT_EXCEPTIONS_H_
+
+#include <botan/asio_error.h>
+#include <botan/tls_exceptn.h>
+
+namespace Botan {
+inline boost::system::error_code convertException()
+ {
+ try
+ {
+ throw;
+ }
+ catch(Botan::TLS::Unexpected_Message& e)
+ {
+ return make_error_code(Botan::error::unexpected_message);
+ }
+ catch(Botan::TLS::TLS_Exception& e)
+ {
+ return make_error_code(e.type());
+ }
+ catch(Botan::Unsupported_Argument& e)
+ {
+ return make_error_code(Botan::error::unsupported_argument);
+ }
+ catch(Botan::Invalid_Key_Length& e)
+ {
+ return make_error_code(Botan::error::invalid_key_length);
+ }
+ catch(Botan::Invalid_IV_Length& e)
+ {
+ return make_error_code(Botan::error::invalid_iv_length);
+ }
+ catch(Botan::Invalid_Algorithm_Name& e)
+ {
+ return make_error_code(Botan::error::invalid_algorithm_name);
+ }
+ catch(Botan::Encoding_Error& e)
+ {
+ return make_error_code(Botan::error::encoding_error);
+ }
+ catch(Botan::Invalid_OID& e)
+ {
+ return make_error_code(Botan::error::invalid_oid);
+ }
+ catch(Botan::Decoding_Error& e)
+ {
+ return make_error_code(Botan::error::decoding_error);
+ }
+ catch(Botan::Invalid_Argument& e)
+ {
+ return make_error_code(Botan::error::invalid_argument);
+ }
+ catch(Botan::Key_Not_Set& e)
+ {
+ return make_error_code(Botan::error::key_not_set);
+ }
+ catch(Botan::PRNG_Unseeded& e)
+ {
+ return make_error_code(Botan::error::prng_unseeded);
+ }
+ catch(Botan::Policy_Violation& e)
+ {
+ return make_error_code(Botan::error::policy_violation);
+ }
+ catch(Botan::Invalid_State& e)
+ {
+ return make_error_code(Botan::error::invalid_state);
+ }
+ catch(Botan::Algorithm_Not_Found& e)
+ {
+ return make_error_code(Botan::error::algorithm_not_found);
+ }
+ catch(Botan::Provider_Not_Found& e)
+ {
+ return make_error_code(Botan::error::provider_not_found);
+ }
+ catch(Botan::Lookup_Error& e)
+ {
+ return make_error_code(Botan::error::lookup_error);
+ }
+ catch(Botan::Self_Test_Failure& e)
+ {
+ return make_error_code(Botan::error::self_test_failure);
+ }
+ catch(Botan::Internal_Error& e)
+ {
+ return make_error_code(Botan::error::internal_error);
+ }
+ catch(Botan::No_Provider_Found& e)
+ {
+ return make_error_code(Botan::error::no_provider_found);
+ }
+ catch(Botan::Integrity_Failure& e)
+ {
+ return make_error_code(Botan::error::integrity_failure);
+ }
+ catch(Botan::Stream_IO_Error& e)
+ {
+ return make_error_code(Botan::error::stream_io_error);
+ }
+ catch(Botan::Not_Implemented& e)
+ {
+ return make_error_code(Botan::error::not_implemented);
+ }
+ catch(Botan::Exception& e)
+ {
+ return make_error_code(Botan::error::unknown);
+ }
+ catch(std::exception& e)
+ {
+ return make_error_code(Botan::error::unknown);
+ }
+ }
+}
+
+#endif
diff --git a/src/lib/tls/asio/asio_error.h b/src/lib/tls/asio/asio_error.h
new file mode 100644
index 000000000..a285dff43
--- /dev/null
+++ b/src/lib/tls/asio/asio_error.h
@@ -0,0 +1,155 @@
+#ifndef BOTAN_ASIO_ERROR_H_
+#define BOTAN_ASIO_ERROR_H_
+
+#include <boost/system/system_error.hpp>
+
+#include <botan/tls_alert.h>
+
+namespace Botan {
+
+using error_code = boost::system::error_code;
+using error_category = boost::system::error_category;
+
+// TLS Alerts
+struct BotanAlertCategory : error_category
+ {
+ const char* name() const noexcept override
+ {
+ return "asio.botan.tls.alert";
+ }
+
+ std::string message(int ev) const override
+ {
+ Botan::TLS::Alert alert(static_cast<Botan::TLS::Alert::Type>(ev));
+ return alert.type_string();
+ }
+ };
+
+inline const BotanAlertCategory& botan_alert_category() noexcept
+ {
+ static BotanAlertCategory category;
+ return category;
+ }
+
+inline error_code make_error_code(Botan::TLS::Alert::Type c)
+ {
+ return error_code(static_cast<int>(c), botan_alert_category());
+ }
+
+enum class error
+ {
+ unexpected_message = 1,
+ invalid_argument,
+ unsupported_argument,
+ invalid_state,
+ key_not_set,
+ lookup_error,
+ internal_error,
+ invalid_key_length,
+ invalid_iv_length,
+ prng_unseeded,
+ policy_violation,
+ algorithm_not_found,
+ no_provider_found,
+ provider_not_found,
+ invalid_algorithm_name,
+ encoding_error,
+ decoding_error,
+ integrity_failure,
+ invalid_oid,
+ stream_io_error,
+ self_test_failure,
+ not_implemented,
+ unknown
+ };
+
+struct BotanErrorCategory : error_category
+ {
+ const char* name() const noexcept override
+ {
+ return "asio.botan.tls";
+ }
+
+ std::string message(int ev) const override
+ {
+ switch(static_cast<error>(ev))
+ {
+ case error::unexpected_message:
+ return "unexpected_message";
+ case error::invalid_argument:
+ return "invalid_argument";
+ case error::unsupported_argument:
+ return "unsupported_argument";
+ case error::invalid_state:
+ return "invalid_state";
+ case error::key_not_set:
+ return "key_not_set";
+ case error::lookup_error:
+ return "lookup_error";
+ case error::internal_error:
+ return "internal_error";
+ case error::invalid_key_length:
+ return "invalid_key_length";
+ case error::invalid_iv_length:
+ return "invalid_iv_length";
+ case error::prng_unseeded:
+ return "prng_unseeded";
+ case error::policy_violation:
+ return "policy_violation";
+ case error::algorithm_not_found:
+ return "algorithm_not_found";
+ case error::no_provider_found:
+ return "no_provider_found";
+ case error::provider_not_found:
+ return "provider_not_found";
+ case error::invalid_algorithm_name:
+ return "invalid_algorithm_name";
+ case error::encoding_error:
+ return "encoding_error";
+ case error::decoding_error:
+ return "decoding_error";
+ case error::integrity_failure:
+ return "integrity_failure";
+ case error::invalid_oid:
+ return "invalid_oid";
+ case error::stream_io_error:
+ return "stream_io_error";
+ case error::self_test_failure:
+ return "self_test_failure";
+ case error::not_implemented:
+ return "not_implemented";
+
+ default:
+ return "(unrecognized botan tls error)";
+ }
+ }
+ };
+
+inline const BotanErrorCategory& botan_category() noexcept
+ {
+ static BotanErrorCategory category;
+ return category;
+ }
+
+inline error_code make_error_code(error c)
+ {
+ return error_code(static_cast<int>(c), botan_category());
+ }
+}
+
+namespace boost {
+namespace system {
+
+template<> struct is_error_code_enum<Botan::TLS::Alert::Type>
+ {
+ static const bool value = true;
+ };
+
+template<> struct is_error_code_enum<Botan::error>
+ {
+ static const bool value = true;
+ };
+}
+}
+
+#endif
diff --git a/src/lib/tls/asio/asio_includes.h b/src/lib/tls/asio/asio_includes.h
new file mode 100644
index 000000000..796aca10e
--- /dev/null
+++ b/src/lib/tls/asio/asio_includes.h
@@ -0,0 +1,11 @@
+#ifndef BOTAN_ASIO_INCLUDES_H_
+#define BOTAN_ASIO_INCLUDES_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/buffer.hpp>
+#include <boost/asio/ip/tcp.hpp>
+
+#endif
diff --git a/src/lib/tls/asio/asio_stream.h b/src/lib/tls/asio/asio_stream.h
new file mode 100644
index 000000000..f6bac7b27
--- /dev/null
+++ b/src/lib/tls/asio/asio_stream.h
@@ -0,0 +1,465 @@
+#ifndef BOTAN_ASIO_STREAM_H_
+#define BOTAN_ASIO_STREAM_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_convert_exceptions.h>
+#include <botan/internal/asio_includes.h>
+#include <botan/internal/asio_stream_base.h>
+#include <botan/internal/asio_stream_core.h>
+
+#include <memory>
+#include <thread>
+#include <type_traits>
+
+namespace boost {
+namespace asio {
+namespace ssl {
+class context;
+}
+}
+}
+
+namespace Botan {
+
+/**
+ * boost::asio compatible SSL/TLS stream based on TLS::Client or TLS::Server.
+ */
+template <class StreamLayer, class Channel>
+class Stream : public StreamBase<Channel>
+ {
+ public:
+ using next_layer_type = typename std::remove_reference<StreamLayer>::type;
+ using lowest_layer_type = typename next_layer_type::lowest_layer_type;
+ using executor_type = typename next_layer_type::executor_type;
+ using native_handle_type = typename std::add_pointer<Channel>::type;
+
+ enum handshake_type
+ {
+ client,
+ server
+ };
+
+ private:
+ void validate_handshake_type(handshake_type type)
+ {
+ if(type != handshake_type::client)
+ {
+ throw Not_Implemented("server-side TLS stream is not implemented");
+ }
+ }
+
+ bool validate_handshake_type(handshake_type type, boost::system::error_code& ec)
+ {
+ if(type != handshake_type::client)
+ {
+ ec = make_error_code(Botan::error::not_implemented);
+ return false;
+ }
+
+ return true;
+ }
+
+ public:
+ template <typename... Args>
+ Stream(StreamLayer&& nextLayer, Args&& ... args)
+ : StreamBase<Channel>(std::forward<Args>(args)...),
+ nextLayer_(std::forward<StreamLayer>(nextLayer)) {}
+
+ Stream(StreamLayer&& nextLayer, boost::asio::ssl::context&)
+ : StreamBase<Channel>(Botan::TLS::Session_Manager_Noop(), Botan::Credentials_Manager()),
+ nextLayer_(std::forward<StreamLayer>(nextLayer))
+ {
+ // Configuring a TLS stream via asio::ssl::context is not supported.
+ // The corresponding configuration objects for Botan are:
+ // * TLS::Session_Manager
+ // * Credentials_Manager
+ // * TLS::Policy
+ // * TLS::Server_Information
+ // It would be nice to have a masquarading wrapper that exposes an API
+ // compatible with asio::ssl::context for convenient drop-in replacement.
+ // For now, base your TLS configurations on the above mentioned classes.
+ throw Not_Implemented("cannot handle an asio::ssl::context");
+ }
+
+
+ Stream(Stream&& other) = default;
+ Stream& operator=(Stream&& other) = default;
+
+ Stream(const Stream& other) = delete;
+ Stream& operator=(const Stream& other) = delete;
+
+ //
+ // -- -- accessor methods
+ //
+
+ executor_type get_executor() noexcept { return nextLayer_.get_executor(); }
+
+ const next_layer_type& next_layer() const { return nextLayer_; }
+ next_layer_type& next_layer() { return nextLayer_; }
+
+ lowest_layer_type& lowest_layer() { return nextLayer_.lowest_layer(); }
+ const lowest_layer_type& lowest_layer() const { return nextLayer_.lowest_layer(); }
+
+ native_handle_type native_handle() { return &this->channel_; }
+
+ //
+ // -- -- configuration and callback setters
+ //
+
+ template<
+ typename VerifyCallback>
+ void set_verify_callback(VerifyCallback callback)
+ {
+ BOTAN_UNUSED(callback);
+ throw Not_Implemented("set_verify_callback is not implemented");
+ }
+
+ template<
+ typename VerifyCallback>
+ void set_verify_callback(VerifyCallback callback,
+ boost::system::error_code& ec)
+ {
+ BOTAN_UNUSED(callback);
+ ec = make_error_code(Botan::error::not_implemented);
+ }
+
+ void set_verify_depth(int depth)
+ {
+ BOTAN_UNUSED(depth);
+ throw Not_Implemented("set_verify_depth is not implemented");
+ }
+
+ void set_verify_depth(int depth,
+ boost::system::error_code& ec)
+ {
+ BOTAN_UNUSED(depth);
+ ec = make_error_code(Botan::error::not_implemented);
+ }
+
+ template <typename verify_mode>
+ void set_verify_mode(verify_mode v)
+ {
+ BOTAN_UNUSED(v);
+ throw Not_Implemented("set_verify_mode is not implemented");
+ }
+
+ template <typename verify_mode>
+ void set_verify_mode(verify_mode v,
+ boost::system::error_code& ec)
+ {
+ BOTAN_UNUSED(v);
+ ec = make_error_code(Botan::error::not_implemented);
+ }
+
+ //
+ // -- -- handshake methods
+ //
+
+ void handshake(handshake_type type)
+ {
+ validate_handshake_type(type);
+
+ boost::system::error_code ec;
+ handshake(type, ec);
+ boost::asio::detail::throw_error(ec, "handshake");
+ }
+
+ void handshake(handshake_type type, boost::system::error_code& ec)
+ {
+ if(!validate_handshake_type(type, ec))
+ {
+ return;
+ }
+
+ while(!native_handle()->is_active())
+ {
+ writePendingTlsData(ec);
+ if(ec)
+ {
+ return;
+ }
+
+ auto read_buffer = boost::asio::buffer(
+ this->core_.input_buffer_,
+ nextLayer_.read_some(this->core_.input_buffer_, ec));
+ if(ec)
+ {
+ return;
+ }
+
+ try
+ {
+ native_handle()->received_data(static_cast<const uint8_t*>(read_buffer.data()),
+ read_buffer.size());
+ }
+ catch(...)
+ {
+ ec = Botan::convertException();
+ return;
+ }
+
+ writePendingTlsData(ec);
+ }
+ }
+
+ template<typename ConstBufferSequence>
+ void handshake(handshake_type type, const ConstBufferSequence& buffers)
+ {
+ BOTAN_UNUSED(type, buffers);
+ throw Not_Implemented("server-side TLS stream is not implemented");
+ }
+
+ template<typename ConstBufferSequence>
+ void handshake(handshake_type type,
+ const ConstBufferSequence& buffers,
+ boost::system::error_code& ec)
+ {
+ BOTAN_UNUSED(type, buffers);
+ ec = make_error_code(Botan::error::not_implemented);
+ }
+
+ template <typename HandshakeHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(HandshakeHandler,
+ void(boost::system::error_code))
+ async_handshake(handshake_type type, HandshakeHandler&& handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a HandshakeHandler.
+ BOOST_ASIO_HANDSHAKE_HANDLER_CHECK(HandshakeHandler, handler) type_check;
+
+ validate_handshake_type(type);
+
+ boost::asio::async_completion<HandshakeHandler,
+ void(boost::system::error_code)>
+ init(handler);
+
+ auto op = create_async_handshake_op(std::move(init.completion_handler));
+ op(boost::system::error_code{}, 0, 1);
+
+ return init.result.get();
+ }
+
+ template <typename ConstBufferSequence, typename BufferedHandshakeHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(BufferedHandshakeHandler,
+ void(boost::system::error_code, std::size_t))
+ async_handshake(handshake_type type,
+ const ConstBufferSequence& buffers,
+ BufferedHandshakeHandler&& handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a BufferedHandshakeHandler.
+ BOOST_ASIO_HANDSHAKE_HANDLER_CHECK(BufferedHandshakeHandler, handler) type_check;
+ BOTAN_UNUSED(type, buffers, handler);
+ throw Not_Implemented("buffered async handshake is not implemented");
+ }
+
+ //
+ // -- -- shutdown methods
+ //
+
+ void shutdown(boost::system::error_code& ec)
+ {
+ try
+ {
+ native_handle()->close();
+ }
+ catch(...)
+ {
+ ec = Botan::convertException();
+ return;
+ }
+ writePendingTlsData(ec);
+ }
+
+ void shutdown()
+ {
+ boost::system::error_code ec;
+ shutdown(ec);
+ boost::asio::detail::throw_error(ec, "shutdown");
+ }
+
+ template <typename ShutdownHandler>
+ void async_shutdown(ShutdownHandler&& handler)
+ {
+ // If you get an error on the following line it means that your handler does
+ // not meet the documented type requirements for a ShutdownHandler.
+ BOOST_ASIO_HANDSHAKE_HANDLER_CHECK(ShutdownHandler, handler) type_check;
+ BOTAN_UNUSED(handler);
+ throw Not_Implemented("async shutdown is not implemented");
+ }
+
+ //
+ // -- -- I/O methods
+ //
+
+ template <typename MutableBufferSequence>
+ std::size_t read_some(const MutableBufferSequence& buffers,
+ boost::system::error_code& ec)
+ {
+ if(this->core_.hasReceivedData())
+ {
+ return this->core_.copyReceivedData(buffers);
+ }
+
+ auto read_buffer = boost::asio::buffer(
+ this->core_.input_buffer_,
+ nextLayer_.read_some(this->core_.input_buffer_, ec));
+ if(ec)
+ {
+ return 0;
+ }
+
+ try
+ {
+ native_handle()->received_data(static_cast<const uint8_t*>(read_buffer.data()),
+ read_buffer.size());
+ }
+ catch(...)
+ {
+ ec = Botan::convertException();
+ return 0;
+ }
+
+ return this->core_.copyReceivedData(buffers);
+ }
+
+ template <typename MutableBufferSequence>
+ std::size_t read_some(const MutableBufferSequence& buffers)
+ {
+ boost::system::error_code ec;
+ auto const n = read_some(buffers, ec);
+ boost::asio::detail::throw_error(ec, "read_some");
+ return n;
+ }
+
+ template <typename ConstBufferSequence>
+ std::size_t write_some(const ConstBufferSequence& buffers,
+ boost::system::error_code& ec)
+ {
+ boost::asio::const_buffer buffer =
+ boost::asio::detail::buffer_sequence_adapter<
+ boost::asio::const_buffer, ConstBufferSequence>::first(buffers);
+
+ try
+ {
+ native_handle()->send(static_cast<const uint8_t*>(buffer.data()), buffer.size());
+ }
+ catch(...)
+ {
+ ec = Botan::convertException();
+ return 0;
+ }
+
+ writePendingTlsData(ec);
+ if(ec)
+ {
+ return 0;
+ }
+ return buffer.size();
+ }
+
+ template <typename ConstBufferSequence>
+ std::size_t write_some(const ConstBufferSequence& buffers)
+ {
+ boost::system::error_code ec;
+ auto const n = write_some(buffers, ec);
+ boost::asio::detail::throw_error(ec, "write_some");
+ return n;
+ }
+
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void(boost::system::error_code, std::size_t))
+ async_write_some(const ConstBufferSequence& buffers, WriteHandler&& handler)
+ {
+ BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+ boost::asio::const_buffer buffer =
+ boost::asio::detail::buffer_sequence_adapter<
+ boost::asio::const_buffer, ConstBufferSequence>::first(buffers);
+
+ try
+ {
+ native_handle()->send(static_cast<const uint8_t*>(buffer.data()),
+ buffer.size());
+ }
+ catch(...)
+ {
+ // TODO: don't call directly
+ handler(Botan::convertException(), 0);
+ return;
+ }
+
+ boost::asio::async_completion<WriteHandler,
+ void(boost::system::error_code, std::size_t)>
+ init(handler);
+ auto op = create_async_write_op(std::move(init.completion_handler),
+ buffer.size());
+
+ boost::asio::async_write(nextLayer_, this->core_.sendBuffer(),
+ std::move(op));
+ return init.result.get();
+ }
+
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void(boost::system::error_code, std::size_t))
+ async_read_some(const MutableBufferSequence& buffers, ReadHandler&& handler)
+ {
+ BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
+
+ boost::asio::async_completion<ReadHandler,
+ void(boost::system::error_code, std::size_t)>
+ init(handler);
+
+ auto op = create_async_read_op(std::move(init.completion_handler), buffers);
+ op(boost::system::error_code{}, 0);
+ return init.result.get();
+ }
+
+ protected:
+ size_t writePendingTlsData(boost::system::error_code& ec)
+ {
+ auto writtenBytes =
+ boost::asio::write(nextLayer_, this->core_.sendBuffer(), ec);
+
+ this->core_.consumeSendBuffer(writtenBytes);
+ return writtenBytes;
+ }
+
+ template <typename Handler>
+ Botan::AsyncHandshakeOperation<Channel, StreamLayer, Handler>
+ create_async_handshake_op(Handler&& handler)
+ {
+ return Botan::AsyncHandshakeOperation<Channel, StreamLayer, Handler>(
+ native_handle(), this->core_, nextLayer_, std::forward<Handler>(handler));
+ }
+
+ template <typename Handler, typename MutableBufferSequence>
+ Botan::AsyncReadOperation<Channel, StreamLayer, Handler,
+ MutableBufferSequence>
+ create_async_read_op(Handler&& handler,
+ const MutableBufferSequence& buffers)
+ {
+ return Botan::AsyncReadOperation<Channel, StreamLayer, Handler,
+ MutableBufferSequence>(
+ native_handle(), this->core_, nextLayer_, std::forward<Handler>(handler),
+ buffers);
+ }
+
+ template <typename Handler>
+ Botan::AsyncWriteOperation<Handler>
+ create_async_write_op(Handler&& handler, std::size_t plainBytesTransferred)
+ {
+ return Botan::AsyncWriteOperation<Handler>(
+ this->core_, std::forward<Handler>(handler), plainBytesTransferred);
+ }
+
+ StreamLayer nextLayer_;
+ };
+
+} // namespace Botan
+
+#endif
diff --git a/src/lib/tls/asio/asio_stream_base.h b/src/lib/tls/asio/asio_stream_base.h
new file mode 100644
index 000000000..93a14bd5c
--- /dev/null
+++ b/src/lib/tls/asio/asio_stream_base.h
@@ -0,0 +1,64 @@
+#ifndef BOTAN_ASIO_STREAM_BASE_H_
+#define BOTAN_ASIO_STREAM_BASE_H_
+
+#include <botan/auto_rng.h>
+#include <botan/tls_client.h>
+#include <botan/tls_server.h>
+
+namespace Botan {
+
+template <class Channel>
+class StreamBase
+ {
+ };
+
+template <>
+class StreamBase<Botan::TLS::Client>
+ {
+ public:
+ StreamBase(Botan::TLS::Session_Manager& sessionManager,
+ Botan::Credentials_Manager& credentialsManager,
+ const Botan::TLS::Policy& policy = Botan::TLS::Strict_Policy{},
+ const Botan::TLS::Server_Information& serverInfo =
+ Botan::TLS::Server_Information{})
+ : channel_(core_,
+ sessionManager,
+ credentialsManager,
+ policy,
+ rng_,
+ serverInfo)
+ {
+ }
+
+ StreamBase(const StreamBase&) = delete;
+ StreamBase& operator=(const StreamBase&) = delete;
+
+ protected:
+ Botan::StreamCore core_;
+ Botan::AutoSeeded_RNG rng_;
+ Botan::TLS::Client channel_;
+ };
+
+template <>
+class StreamBase<Botan::TLS::Server>
+ {
+ public:
+ StreamBase(Botan::TLS::Session_Manager& sessionManager,
+ Botan::Credentials_Manager& credentialsManager,
+ const Botan::TLS::Policy& policy = Botan::TLS::Strict_Policy{})
+ : channel_(core_, sessionManager, credentialsManager, policy, rng_)
+ {
+ }
+
+ StreamBase(const StreamBase&) = delete;
+ StreamBase& operator=(const StreamBase&) = delete;
+
+ protected:
+ Botan::StreamCore core_;
+ Botan::AutoSeeded_RNG rng_;
+ Botan::TLS::Server channel_;
+ };
+
+} // namespace botan
+
+#endif
diff --git a/src/lib/tls/asio/asio_stream_core.h b/src/lib/tls/asio/asio_stream_core.h
new file mode 100644
index 000000000..caac6d06a
--- /dev/null
+++ b/src/lib/tls/asio/asio_stream_core.h
@@ -0,0 +1,104 @@
+#ifndef BOTAN_ASIO_STREAM_CORE_H_
+#define BOTAN_ASIO_STREAM_CORE_H_
+
+#include <botan/internal/asio_includes.h>
+#include <botan/tls_callbacks.h>
+#include <mutex>
+#include <vector>
+
+namespace Botan {
+/**
+ * Contains the buffers for reading/sending, and the needed botan callbacks
+ */
+struct StreamCore : public Botan::TLS::Callbacks
+ {
+ struct Buffer
+ {
+ Buffer() : dynamicBuffer(data_buffer) {}
+ std::vector<uint8_t> data_buffer;
+ boost::asio::dynamic_vector_buffer<
+ uint8_t, typename decltype(data_buffer)::allocator_type>
+ dynamicBuffer;
+ };
+
+ StreamCore()
+ : input_buffer_space_(17 * 1024, '\0'), // enough for a TLS Datagram
+ input_buffer_(boost::asio::buffer(input_buffer_space_)) {}
+
+ virtual ~StreamCore() = default;
+
+ void tls_emit_data(const uint8_t data[], size_t size) override
+ {
+ auto buffer = send_buffer_.dynamicBuffer.prepare(size);
+ auto copySize =
+ boost::asio::buffer_copy(buffer, boost::asio::buffer(data, size));
+ send_buffer_.dynamicBuffer.commit(copySize);
+ }
+
+ void tls_record_received(uint64_t, const uint8_t data[],
+ size_t size) override
+ {
+ auto buffer = receive_buffer_.dynamicBuffer.prepare(size);
+ auto copySize =
+ boost::asio::buffer_copy(buffer, boost::asio::buffer(data, size));
+ receive_buffer_.dynamicBuffer.commit(copySize);
+ }
+
+ void tls_alert(Botan::TLS::Alert alert) override
+ {
+ if(alert.type() == Botan::TLS::Alert::CLOSE_NOTIFY)
+ {
+ // TODO
+ }
+ }
+
+ std::chrono::milliseconds
+ tls_verify_cert_chain_ocsp_timeout() const override
+ {
+ return std::chrono::milliseconds(1000);
+ }
+
+ bool tls_session_established(const Botan::TLS::Session&) override
+ {
+ return true;
+ }
+
+ bool hasReceivedData() const
+ {
+ return receive_buffer_.dynamicBuffer.size() > 0;
+ }
+
+ template <typename MutableBufferSequence>
+ std::size_t copyReceivedData(MutableBufferSequence buffers)
+ {
+ const auto copiedBytes =
+ boost::asio::buffer_copy(buffers, receive_buffer_.dynamicBuffer.data());
+ receive_buffer_.dynamicBuffer.consume(copiedBytes);
+ return copiedBytes;
+ }
+
+ bool hasDataToSend() const { return send_buffer_.dynamicBuffer.size() > 0; }
+
+ boost::asio::const_buffer sendBuffer() const
+ {
+ return send_buffer_.dynamicBuffer.data();
+ }
+
+ void consumeSendBuffer(std::size_t bytesConsumed)
+ {
+ send_buffer_.dynamicBuffer.consume(bytesConsumed);
+ }
+
+ // Buffer space used to read input intended for the engine.
+ std::vector<uint8_t> input_buffer_space_;
+
+ // A buffer that may be used to read input intended for the engine.
+ const boost::asio::mutable_buffer input_buffer_;
+
+ private:
+ Buffer receive_buffer_;
+ Buffer send_buffer_;
+ };
+} // namespace Botan
+
+#endif
diff --git a/src/lib/tls/asio/info.txt b/src/lib/tls/asio/info.txt
new file mode 100644
index 000000000..a78f5c85c
--- /dev/null
+++ b/src/lib/tls/asio/info.txt
@@ -0,0 +1,23 @@
+<defines>
+ASIO -> 20181218
+</defines>
+
+<header:public>
+asio_stream.h
+asio_error.h
+</header:public>
+
+<header:internal>
+asio_async_handshake_op.h
+asio_async_read_op.h
+asio_async_write_op.h
+asio_convert_exceptions.h
+asio_stream_base.h
+asio_stream_core.h
+asio_includes.h
+</header:internal>
+
+<requires>
+boost
+tls
+</requires>