annotate DEPENDENCIES/generic/include/boost/asio/ssl/detail/impl/engine.ipp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
Chris@16 1 //
Chris@16 2 // ssl/detail/impl/engine.ipp
Chris@16 3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
Chris@16 4 //
Chris@101 5 // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
Chris@16 6 //
Chris@16 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
Chris@16 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Chris@16 9 //
Chris@16 10
Chris@16 11 #ifndef BOOST_ASIO_SSL_DETAIL_IMPL_ENGINE_IPP
Chris@16 12 #define BOOST_ASIO_SSL_DETAIL_IMPL_ENGINE_IPP
Chris@16 13
Chris@16 14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
Chris@16 15 # pragma once
Chris@16 16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
Chris@16 17
Chris@16 18 #include <boost/asio/detail/config.hpp>
Chris@16 19
Chris@16 20 #if !defined(BOOST_ASIO_ENABLE_OLD_SSL)
Chris@16 21 # include <boost/asio/detail/throw_error.hpp>
Chris@16 22 # include <boost/asio/error.hpp>
Chris@16 23 # include <boost/asio/ssl/detail/engine.hpp>
Chris@16 24 # include <boost/asio/ssl/error.hpp>
Chris@16 25 # include <boost/asio/ssl/verify_context.hpp>
Chris@16 26 #endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL)
Chris@16 27
Chris@16 28 #include <boost/asio/detail/push_options.hpp>
Chris@16 29
Chris@16 30 namespace boost {
Chris@16 31 namespace asio {
Chris@16 32 namespace ssl {
Chris@16 33 namespace detail {
Chris@16 34
Chris@16 35 #if !defined(BOOST_ASIO_ENABLE_OLD_SSL)
Chris@16 36
Chris@16 37 engine::engine(SSL_CTX* context)
Chris@16 38 : ssl_(::SSL_new(context))
Chris@16 39 {
Chris@16 40 if (!ssl_)
Chris@16 41 {
Chris@16 42 boost::system::error_code ec(
Chris@16 43 static_cast<int>(::ERR_get_error()),
Chris@16 44 boost::asio::error::get_ssl_category());
Chris@16 45 boost::asio::detail::throw_error(ec, "engine");
Chris@16 46 }
Chris@16 47
Chris@16 48 accept_mutex().init();
Chris@16 49
Chris@16 50 ::SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE);
Chris@16 51 ::SSL_set_mode(ssl_, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
Chris@16 52 #if defined(SSL_MODE_RELEASE_BUFFERS)
Chris@16 53 ::SSL_set_mode(ssl_, SSL_MODE_RELEASE_BUFFERS);
Chris@16 54 #endif // defined(SSL_MODE_RELEASE_BUFFERS)
Chris@16 55
Chris@16 56 ::BIO* int_bio = 0;
Chris@16 57 ::BIO_new_bio_pair(&int_bio, 0, &ext_bio_, 0);
Chris@16 58 ::SSL_set_bio(ssl_, int_bio, int_bio);
Chris@16 59 }
Chris@16 60
Chris@16 61 engine::~engine()
Chris@16 62 {
Chris@16 63 if (SSL_get_app_data(ssl_))
Chris@16 64 {
Chris@16 65 delete static_cast<verify_callback_base*>(SSL_get_app_data(ssl_));
Chris@16 66 SSL_set_app_data(ssl_, 0);
Chris@16 67 }
Chris@16 68
Chris@16 69 ::BIO_free(ext_bio_);
Chris@16 70 ::SSL_free(ssl_);
Chris@16 71 }
Chris@16 72
Chris@16 73 SSL* engine::native_handle()
Chris@16 74 {
Chris@16 75 return ssl_;
Chris@16 76 }
Chris@16 77
Chris@16 78 boost::system::error_code engine::set_verify_mode(
Chris@16 79 verify_mode v, boost::system::error_code& ec)
Chris@16 80 {
Chris@16 81 ::SSL_set_verify(ssl_, v, ::SSL_get_verify_callback(ssl_));
Chris@16 82
Chris@16 83 ec = boost::system::error_code();
Chris@16 84 return ec;
Chris@16 85 }
Chris@16 86
Chris@16 87 boost::system::error_code engine::set_verify_depth(
Chris@16 88 int depth, boost::system::error_code& ec)
Chris@16 89 {
Chris@16 90 ::SSL_set_verify_depth(ssl_, depth);
Chris@16 91
Chris@16 92 ec = boost::system::error_code();
Chris@16 93 return ec;
Chris@16 94 }
Chris@16 95
Chris@16 96 boost::system::error_code engine::set_verify_callback(
Chris@16 97 verify_callback_base* callback, boost::system::error_code& ec)
Chris@16 98 {
Chris@16 99 if (SSL_get_app_data(ssl_))
Chris@16 100 delete static_cast<verify_callback_base*>(SSL_get_app_data(ssl_));
Chris@16 101
Chris@16 102 SSL_set_app_data(ssl_, callback);
Chris@16 103
Chris@16 104 ::SSL_set_verify(ssl_, ::SSL_get_verify_mode(ssl_),
Chris@16 105 &engine::verify_callback_function);
Chris@16 106
Chris@16 107 ec = boost::system::error_code();
Chris@16 108 return ec;
Chris@16 109 }
Chris@16 110
Chris@16 111 int engine::verify_callback_function(int preverified, X509_STORE_CTX* ctx)
Chris@16 112 {
Chris@16 113 if (ctx)
Chris@16 114 {
Chris@16 115 if (SSL* ssl = static_cast<SSL*>(
Chris@16 116 ::X509_STORE_CTX_get_ex_data(
Chris@16 117 ctx, ::SSL_get_ex_data_X509_STORE_CTX_idx())))
Chris@16 118 {
Chris@16 119 if (SSL_get_app_data(ssl))
Chris@16 120 {
Chris@16 121 verify_callback_base* callback =
Chris@16 122 static_cast<verify_callback_base*>(
Chris@16 123 SSL_get_app_data(ssl));
Chris@16 124
Chris@16 125 verify_context verify_ctx(ctx);
Chris@16 126 return callback->call(preverified != 0, verify_ctx) ? 1 : 0;
Chris@16 127 }
Chris@16 128 }
Chris@16 129 }
Chris@16 130
Chris@16 131 return 0;
Chris@16 132 }
Chris@16 133
Chris@16 134 engine::want engine::handshake(
Chris@16 135 stream_base::handshake_type type, boost::system::error_code& ec)
Chris@16 136 {
Chris@16 137 return perform((type == boost::asio::ssl::stream_base::client)
Chris@16 138 ? &engine::do_connect : &engine::do_accept, 0, 0, ec, 0);
Chris@16 139 }
Chris@16 140
Chris@16 141 engine::want engine::shutdown(boost::system::error_code& ec)
Chris@16 142 {
Chris@16 143 return perform(&engine::do_shutdown, 0, 0, ec, 0);
Chris@16 144 }
Chris@16 145
Chris@16 146 engine::want engine::write(const boost::asio::const_buffer& data,
Chris@16 147 boost::system::error_code& ec, std::size_t& bytes_transferred)
Chris@16 148 {
Chris@16 149 if (boost::asio::buffer_size(data) == 0)
Chris@16 150 {
Chris@16 151 ec = boost::system::error_code();
Chris@16 152 return engine::want_nothing;
Chris@16 153 }
Chris@16 154
Chris@16 155 return perform(&engine::do_write,
Chris@16 156 const_cast<void*>(boost::asio::buffer_cast<const void*>(data)),
Chris@16 157 boost::asio::buffer_size(data), ec, &bytes_transferred);
Chris@16 158 }
Chris@16 159
Chris@16 160 engine::want engine::read(const boost::asio::mutable_buffer& data,
Chris@16 161 boost::system::error_code& ec, std::size_t& bytes_transferred)
Chris@16 162 {
Chris@16 163 if (boost::asio::buffer_size(data) == 0)
Chris@16 164 {
Chris@16 165 ec = boost::system::error_code();
Chris@16 166 return engine::want_nothing;
Chris@16 167 }
Chris@16 168
Chris@16 169 return perform(&engine::do_read,
Chris@16 170 boost::asio::buffer_cast<void*>(data),
Chris@16 171 boost::asio::buffer_size(data), ec, &bytes_transferred);
Chris@16 172 }
Chris@16 173
Chris@16 174 boost::asio::mutable_buffers_1 engine::get_output(
Chris@16 175 const boost::asio::mutable_buffer& data)
Chris@16 176 {
Chris@16 177 int length = ::BIO_read(ext_bio_,
Chris@16 178 boost::asio::buffer_cast<void*>(data),
Chris@16 179 static_cast<int>(boost::asio::buffer_size(data)));
Chris@16 180
Chris@16 181 return boost::asio::buffer(data,
Chris@16 182 length > 0 ? static_cast<std::size_t>(length) : 0);
Chris@16 183 }
Chris@16 184
Chris@16 185 boost::asio::const_buffer engine::put_input(
Chris@16 186 const boost::asio::const_buffer& data)
Chris@16 187 {
Chris@16 188 int length = ::BIO_write(ext_bio_,
Chris@16 189 boost::asio::buffer_cast<const void*>(data),
Chris@16 190 static_cast<int>(boost::asio::buffer_size(data)));
Chris@16 191
Chris@16 192 return boost::asio::buffer(data +
Chris@16 193 (length > 0 ? static_cast<std::size_t>(length) : 0));
Chris@16 194 }
Chris@16 195
Chris@16 196 const boost::system::error_code& engine::map_error_code(
Chris@16 197 boost::system::error_code& ec) const
Chris@16 198 {
Chris@16 199 // We only want to map the error::eof code.
Chris@16 200 if (ec != boost::asio::error::eof)
Chris@16 201 return ec;
Chris@16 202
Chris@16 203 // If there's data yet to be read, it's an error.
Chris@16 204 if (BIO_wpending(ext_bio_))
Chris@16 205 {
Chris@16 206 ec = boost::system::error_code(
Chris@16 207 ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ),
Chris@16 208 boost::asio::error::get_ssl_category());
Chris@16 209 return ec;
Chris@16 210 }
Chris@16 211
Chris@16 212 // SSL v2 doesn't provide a protocol-level shutdown, so an eof on the
Chris@16 213 // underlying transport is passed through.
Chris@101 214 if (ssl_->version == SSL2_VERSION)
Chris@16 215 return ec;
Chris@16 216
Chris@16 217 // Otherwise, the peer should have negotiated a proper shutdown.
Chris@16 218 if ((::SSL_get_shutdown(ssl_) & SSL_RECEIVED_SHUTDOWN) == 0)
Chris@16 219 {
Chris@16 220 ec = boost::system::error_code(
Chris@16 221 ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ),
Chris@16 222 boost::asio::error::get_ssl_category());
Chris@16 223 }
Chris@16 224
Chris@16 225 return ec;
Chris@16 226 }
Chris@16 227
Chris@16 228 boost::asio::detail::static_mutex& engine::accept_mutex()
Chris@16 229 {
Chris@16 230 static boost::asio::detail::static_mutex mutex = BOOST_ASIO_STATIC_MUTEX_INIT;
Chris@16 231 return mutex;
Chris@16 232 }
Chris@16 233
Chris@16 234 engine::want engine::perform(int (engine::* op)(void*, std::size_t),
Chris@16 235 void* data, std::size_t length, boost::system::error_code& ec,
Chris@16 236 std::size_t* bytes_transferred)
Chris@16 237 {
Chris@16 238 std::size_t pending_output_before = ::BIO_ctrl_pending(ext_bio_);
Chris@101 239 ::ERR_clear_error();
Chris@16 240 int result = (this->*op)(data, length);
Chris@16 241 int ssl_error = ::SSL_get_error(ssl_, result);
Chris@16 242 int sys_error = static_cast<int>(::ERR_get_error());
Chris@16 243 std::size_t pending_output_after = ::BIO_ctrl_pending(ext_bio_);
Chris@16 244
Chris@16 245 if (ssl_error == SSL_ERROR_SSL)
Chris@16 246 {
Chris@16 247 ec = boost::system::error_code(sys_error,
Chris@16 248 boost::asio::error::get_ssl_category());
Chris@16 249 return want_nothing;
Chris@16 250 }
Chris@16 251
Chris@16 252 if (ssl_error == SSL_ERROR_SYSCALL)
Chris@16 253 {
Chris@16 254 ec = boost::system::error_code(sys_error,
Chris@16 255 boost::asio::error::get_system_category());
Chris@16 256 return want_nothing;
Chris@16 257 }
Chris@16 258
Chris@16 259 if (result > 0 && bytes_transferred)
Chris@16 260 *bytes_transferred = static_cast<std::size_t>(result);
Chris@16 261
Chris@16 262 if (ssl_error == SSL_ERROR_WANT_WRITE)
Chris@16 263 {
Chris@16 264 ec = boost::system::error_code();
Chris@16 265 return want_output_and_retry;
Chris@16 266 }
Chris@16 267 else if (pending_output_after > pending_output_before)
Chris@16 268 {
Chris@16 269 ec = boost::system::error_code();
Chris@16 270 return result > 0 ? want_output : want_output_and_retry;
Chris@16 271 }
Chris@16 272 else if (ssl_error == SSL_ERROR_WANT_READ)
Chris@16 273 {
Chris@16 274 ec = boost::system::error_code();
Chris@16 275 return want_input_and_retry;
Chris@16 276 }
Chris@16 277 else if (::SSL_get_shutdown(ssl_) & SSL_RECEIVED_SHUTDOWN)
Chris@16 278 {
Chris@16 279 ec = boost::asio::error::eof;
Chris@16 280 return want_nothing;
Chris@16 281 }
Chris@16 282 else
Chris@16 283 {
Chris@16 284 ec = boost::system::error_code();
Chris@16 285 return want_nothing;
Chris@16 286 }
Chris@16 287 }
Chris@16 288
Chris@16 289 int engine::do_accept(void*, std::size_t)
Chris@16 290 {
Chris@16 291 boost::asio::detail::static_mutex::scoped_lock lock(accept_mutex());
Chris@16 292 return ::SSL_accept(ssl_);
Chris@16 293 }
Chris@16 294
Chris@16 295 int engine::do_connect(void*, std::size_t)
Chris@16 296 {
Chris@16 297 return ::SSL_connect(ssl_);
Chris@16 298 }
Chris@16 299
Chris@16 300 int engine::do_shutdown(void*, std::size_t)
Chris@16 301 {
Chris@16 302 int result = ::SSL_shutdown(ssl_);
Chris@16 303 if (result == 0)
Chris@16 304 result = ::SSL_shutdown(ssl_);
Chris@16 305 return result;
Chris@16 306 }
Chris@16 307
Chris@16 308 int engine::do_read(void* data, std::size_t length)
Chris@16 309 {
Chris@16 310 return ::SSL_read(ssl_, data,
Chris@16 311 length < INT_MAX ? static_cast<int>(length) : INT_MAX);
Chris@16 312 }
Chris@16 313
Chris@16 314 int engine::do_write(void* data, std::size_t length)
Chris@16 315 {
Chris@16 316 return ::SSL_write(ssl_, data,
Chris@16 317 length < INT_MAX ? static_cast<int>(length) : INT_MAX);
Chris@16 318 }
Chris@16 319
Chris@16 320 #endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL)
Chris@16 321
Chris@16 322 } // namespace detail
Chris@16 323 } // namespace ssl
Chris@16 324 } // namespace asio
Chris@16 325 } // namespace boost
Chris@16 326
Chris@16 327 #include <boost/asio/detail/pop_options.hpp>
Chris@16 328
Chris@16 329 #endif // BOOST_ASIO_SSL_DETAIL_IMPL_ENGINE_IPP