Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 08:29:51

0001 //
0002 // ssl/detail/impl/engine.ipp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_SSL_DETAIL_IMPL_ENGINE_IPP
0012 #define BOOST_ASIO_SSL_DETAIL_IMPL_ENGINE_IPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 
0020 #include <boost/asio/detail/throw_error.hpp>
0021 #include <boost/asio/error.hpp>
0022 #include <boost/asio/ssl/detail/engine.hpp>
0023 #include <boost/asio/ssl/error.hpp>
0024 #include <boost/asio/ssl/verify_context.hpp>
0025 
0026 #include <boost/asio/detail/push_options.hpp>
0027 
0028 namespace boost {
0029 namespace asio {
0030 namespace ssl {
0031 namespace detail {
0032 
0033 engine::engine(SSL_CTX* context)
0034   : ssl_(::SSL_new(context))
0035 {
0036   if (!ssl_)
0037   {
0038     boost::system::error_code ec(
0039         static_cast<int>(::ERR_get_error()),
0040         boost::asio::error::get_ssl_category());
0041     boost::asio::detail::throw_error(ec, "engine");
0042   }
0043 
0044 #if (OPENSSL_VERSION_NUMBER < 0x10000000L)
0045   accept_mutex().init();
0046 #endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
0047 
0048   ::SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE);
0049   ::SSL_set_mode(ssl_, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
0050 #if defined(SSL_MODE_RELEASE_BUFFERS)
0051   ::SSL_set_mode(ssl_, SSL_MODE_RELEASE_BUFFERS);
0052 #endif // defined(SSL_MODE_RELEASE_BUFFERS)
0053 
0054   ::BIO* int_bio = 0;
0055   ::BIO_new_bio_pair(&int_bio, 0, &ext_bio_, 0);
0056   ::SSL_set_bio(ssl_, int_bio, int_bio);
0057 }
0058 
0059 engine::engine(SSL* ssl_impl)
0060   : ssl_(ssl_impl)
0061 {
0062 #if (OPENSSL_VERSION_NUMBER < 0x10000000L)
0063   accept_mutex().init();
0064 #endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
0065 
0066   ::SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE);
0067   ::SSL_set_mode(ssl_, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
0068 #if defined(SSL_MODE_RELEASE_BUFFERS)
0069   ::SSL_set_mode(ssl_, SSL_MODE_RELEASE_BUFFERS);
0070 #endif // defined(SSL_MODE_RELEASE_BUFFERS)
0071 
0072   ::BIO* int_bio = 0;
0073   ::BIO_new_bio_pair(&int_bio, 0, &ext_bio_, 0);
0074   ::SSL_set_bio(ssl_, int_bio, int_bio);
0075 }
0076 
0077 engine::engine(engine&& other) noexcept
0078   : ssl_(other.ssl_),
0079     ext_bio_(other.ext_bio_)
0080 {
0081   other.ssl_ = 0;
0082   other.ext_bio_ = 0;
0083 }
0084 
0085 engine::~engine()
0086 {
0087   if (ssl_ && SSL_get_app_data(ssl_))
0088   {
0089     delete static_cast<verify_callback_base*>(SSL_get_app_data(ssl_));
0090     SSL_set_app_data(ssl_, 0);
0091   }
0092 
0093   if (ext_bio_)
0094     ::BIO_free(ext_bio_);
0095 
0096   if (ssl_)
0097     ::SSL_free(ssl_);
0098 }
0099 
0100 engine& engine::operator=(engine&& other) noexcept
0101 {
0102   if (this != &other)
0103   {
0104     if (ext_bio_)
0105       ::BIO_free(ext_bio_);
0106 
0107     if (ssl_)
0108       ::SSL_free(ssl_);
0109 
0110     ssl_ = other.ssl_;
0111     ext_bio_ = other.ext_bio_;
0112     other.ssl_ = 0;
0113     other.ext_bio_ = 0;
0114   }
0115   return *this;
0116 }
0117 
0118 SSL* engine::native_handle()
0119 {
0120   return ssl_;
0121 }
0122 
0123 boost::system::error_code engine::set_verify_mode(
0124     verify_mode v, boost::system::error_code& ec)
0125 {
0126   ::SSL_set_verify(ssl_, v, ::SSL_get_verify_callback(ssl_));
0127 
0128   ec = boost::system::error_code();
0129   return ec;
0130 }
0131 
0132 boost::system::error_code engine::set_verify_depth(
0133     int depth, boost::system::error_code& ec)
0134 {
0135   ::SSL_set_verify_depth(ssl_, depth);
0136 
0137   ec = boost::system::error_code();
0138   return ec;
0139 }
0140 
0141 boost::system::error_code engine::set_verify_callback(
0142     verify_callback_base* callback, boost::system::error_code& ec)
0143 {
0144   if (SSL_get_app_data(ssl_))
0145     delete static_cast<verify_callback_base*>(SSL_get_app_data(ssl_));
0146 
0147   SSL_set_app_data(ssl_, callback);
0148 
0149   ::SSL_set_verify(ssl_, ::SSL_get_verify_mode(ssl_),
0150       &engine::verify_callback_function);
0151 
0152   ec = boost::system::error_code();
0153   return ec;
0154 }
0155 
0156 int engine::verify_callback_function(int preverified, X509_STORE_CTX* ctx)
0157 {
0158   if (ctx)
0159   {
0160     if (SSL* ssl = static_cast<SSL*>(
0161           ::X509_STORE_CTX_get_ex_data(
0162             ctx, ::SSL_get_ex_data_X509_STORE_CTX_idx())))
0163     {
0164       if (SSL_get_app_data(ssl))
0165       {
0166         verify_callback_base* callback =
0167           static_cast<verify_callback_base*>(
0168               SSL_get_app_data(ssl));
0169 
0170         verify_context verify_ctx(ctx);
0171         return callback->call(preverified != 0, verify_ctx) ? 1 : 0;
0172       }
0173     }
0174   }
0175 
0176   return 0;
0177 }
0178 
0179 engine::want engine::handshake(
0180     stream_base::handshake_type type, boost::system::error_code& ec)
0181 {
0182   return perform((type == boost::asio::ssl::stream_base::client)
0183       ? &engine::do_connect : &engine::do_accept, 0, 0, ec, 0);
0184 }
0185 
0186 engine::want engine::shutdown(boost::system::error_code& ec)
0187 {
0188   return perform(&engine::do_shutdown, 0, 0, ec, 0);
0189 }
0190 
0191 engine::want engine::write(const boost::asio::const_buffer& data,
0192     boost::system::error_code& ec, std::size_t& bytes_transferred)
0193 {
0194   if (data.size() == 0)
0195   {
0196     ec = boost::system::error_code();
0197     return engine::want_nothing;
0198   }
0199 
0200   return perform(&engine::do_write,
0201       const_cast<void*>(data.data()),
0202       data.size(), ec, &bytes_transferred);
0203 }
0204 
0205 engine::want engine::read(const boost::asio::mutable_buffer& data,
0206     boost::system::error_code& ec, std::size_t& bytes_transferred)
0207 {
0208   if (data.size() == 0)
0209   {
0210     ec = boost::system::error_code();
0211     return engine::want_nothing;
0212   }
0213 
0214   return perform(&engine::do_read, data.data(),
0215       data.size(), ec, &bytes_transferred);
0216 }
0217 
0218 boost::asio::mutable_buffer engine::get_output(
0219     const boost::asio::mutable_buffer& data)
0220 {
0221   int length = ::BIO_read(ext_bio_,
0222       data.data(), static_cast<int>(data.size()));
0223 
0224   return boost::asio::buffer(data,
0225       length > 0 ? static_cast<std::size_t>(length) : 0);
0226 }
0227 
0228 boost::asio::const_buffer engine::put_input(
0229     const boost::asio::const_buffer& data)
0230 {
0231   int length = ::BIO_write(ext_bio_,
0232       data.data(), static_cast<int>(data.size()));
0233 
0234   return boost::asio::buffer(data +
0235       (length > 0 ? static_cast<std::size_t>(length) : 0));
0236 }
0237 
0238 const boost::system::error_code& engine::map_error_code(
0239     boost::system::error_code& ec) const
0240 {
0241   // We only want to map the error::eof code.
0242   if (ec != boost::asio::error::eof)
0243     return ec;
0244 
0245   // If there's data yet to be read, it's an error.
0246   if (BIO_wpending(ext_bio_))
0247   {
0248     ec = boost::asio::ssl::error::stream_truncated;
0249     return ec;
0250   }
0251 
0252   // SSL v2 doesn't provide a protocol-level shutdown, so an eof on the
0253   // underlying transport is passed through.
0254 #if (OPENSSL_VERSION_NUMBER < 0x10100000L)
0255   if (SSL_version(ssl_) == SSL2_VERSION)
0256     return ec;
0257 #endif // (OPENSSL_VERSION_NUMBER < 0x10100000L)
0258 
0259   // Otherwise, the peer should have negotiated a proper shutdown.
0260   if ((::SSL_get_shutdown(ssl_) & SSL_RECEIVED_SHUTDOWN) == 0)
0261   {
0262     ec = boost::asio::ssl::error::stream_truncated;
0263   }
0264 
0265   return ec;
0266 }
0267 
0268 #if (OPENSSL_VERSION_NUMBER < 0x10000000L)
0269 boost::asio::detail::static_mutex& engine::accept_mutex()
0270 {
0271   static boost::asio::detail::static_mutex mutex = BOOST_ASIO_STATIC_MUTEX_INIT;
0272   return mutex;
0273 }
0274 #endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
0275 
0276 engine::want engine::perform(int (engine::* op)(void*, std::size_t),
0277     void* data, std::size_t length, boost::system::error_code& ec,
0278     std::size_t* bytes_transferred)
0279 {
0280   std::size_t pending_output_before = ::BIO_ctrl_pending(ext_bio_);
0281   ::ERR_clear_error();
0282   int result = (this->*op)(data, length);
0283   int ssl_error = ::SSL_get_error(ssl_, result);
0284   int sys_error = static_cast<int>(::ERR_get_error());
0285   std::size_t pending_output_after = ::BIO_ctrl_pending(ext_bio_);
0286 
0287   if (ssl_error == SSL_ERROR_SSL)
0288   {
0289     ec = boost::system::error_code(sys_error,
0290         boost::asio::error::get_ssl_category());
0291     return pending_output_after > pending_output_before
0292       ? want_output : want_nothing;
0293   }
0294 
0295   if (ssl_error == SSL_ERROR_SYSCALL)
0296   {
0297     if (sys_error == 0)
0298     {
0299       ec = boost::asio::ssl::error::unspecified_system_error;
0300     }
0301     else
0302     {
0303       ec = boost::system::error_code(sys_error,
0304           boost::asio::error::get_ssl_category());
0305     }
0306     return pending_output_after > pending_output_before
0307       ? want_output : want_nothing;
0308   }
0309 
0310   if (result > 0 && bytes_transferred)
0311     *bytes_transferred = static_cast<std::size_t>(result);
0312 
0313   if (ssl_error == SSL_ERROR_WANT_WRITE)
0314   {
0315     ec = boost::system::error_code();
0316     return want_output_and_retry;
0317   }
0318   else if (pending_output_after > pending_output_before)
0319   {
0320     ec = boost::system::error_code();
0321     return result > 0 ? want_output : want_output_and_retry;
0322   }
0323   else if (ssl_error == SSL_ERROR_WANT_READ)
0324   {
0325     ec = boost::system::error_code();
0326     return want_input_and_retry;
0327   }
0328   else if (ssl_error == SSL_ERROR_ZERO_RETURN)
0329   {
0330     ec = boost::asio::error::eof;
0331     return want_nothing;
0332   }
0333   else if (ssl_error == SSL_ERROR_NONE)
0334   {
0335     ec = boost::system::error_code();
0336     return want_nothing;
0337   }
0338   else
0339   {
0340     ec = boost::asio::ssl::error::unexpected_result;
0341     return want_nothing;
0342   }
0343 }
0344 
0345 int engine::do_accept(void*, std::size_t)
0346 {
0347 #if (OPENSSL_VERSION_NUMBER < 0x10000000L)
0348   boost::asio::detail::static_mutex::scoped_lock lock(accept_mutex());
0349 #endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
0350   return ::SSL_accept(ssl_);
0351 }
0352 
0353 int engine::do_connect(void*, std::size_t)
0354 {
0355   return ::SSL_connect(ssl_);
0356 }
0357 
0358 int engine::do_shutdown(void*, std::size_t)
0359 {
0360   int result = ::SSL_shutdown(ssl_);
0361   if (result == 0)
0362     result = ::SSL_shutdown(ssl_);
0363   return result;
0364 }
0365 
0366 int engine::do_read(void* data, std::size_t length)
0367 {
0368   return ::SSL_read(ssl_, data,
0369       length < INT_MAX ? static_cast<int>(length) : INT_MAX);
0370 }
0371 
0372 int engine::do_write(void* data, std::size_t length)
0373 {
0374   return ::SSL_write(ssl_, data,
0375       length < INT_MAX ? static_cast<int>(length) : INT_MAX);
0376 }
0377 
0378 } // namespace detail
0379 } // namespace ssl
0380 } // namespace asio
0381 } // namespace boost
0382 
0383 #include <boost/asio/detail/pop_options.hpp>
0384 
0385 #endif // BOOST_ASIO_SSL_DETAIL_IMPL_ENGINE_IPP