Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:01

0001 //
0002 // ssl/detail/impl/engine.ipp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 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     ssl_ = other.ssl_;
0105     ext_bio_ = other.ext_bio_;
0106     other.ssl_ = 0;
0107     other.ext_bio_ = 0;
0108   }
0109   return *this;
0110 }
0111 
0112 SSL* engine::native_handle()
0113 {
0114   return ssl_;
0115 }
0116 
0117 boost::system::error_code engine::set_verify_mode(
0118     verify_mode v, boost::system::error_code& ec)
0119 {
0120   ::SSL_set_verify(ssl_, v, ::SSL_get_verify_callback(ssl_));
0121 
0122   ec = boost::system::error_code();
0123   return ec;
0124 }
0125 
0126 boost::system::error_code engine::set_verify_depth(
0127     int depth, boost::system::error_code& ec)
0128 {
0129   ::SSL_set_verify_depth(ssl_, depth);
0130 
0131   ec = boost::system::error_code();
0132   return ec;
0133 }
0134 
0135 boost::system::error_code engine::set_verify_callback(
0136     verify_callback_base* callback, boost::system::error_code& ec)
0137 {
0138   if (SSL_get_app_data(ssl_))
0139     delete static_cast<verify_callback_base*>(SSL_get_app_data(ssl_));
0140 
0141   SSL_set_app_data(ssl_, callback);
0142 
0143   ::SSL_set_verify(ssl_, ::SSL_get_verify_mode(ssl_),
0144       &engine::verify_callback_function);
0145 
0146   ec = boost::system::error_code();
0147   return ec;
0148 }
0149 
0150 int engine::verify_callback_function(int preverified, X509_STORE_CTX* ctx)
0151 {
0152   if (ctx)
0153   {
0154     if (SSL* ssl = static_cast<SSL*>(
0155           ::X509_STORE_CTX_get_ex_data(
0156             ctx, ::SSL_get_ex_data_X509_STORE_CTX_idx())))
0157     {
0158       if (SSL_get_app_data(ssl))
0159       {
0160         verify_callback_base* callback =
0161           static_cast<verify_callback_base*>(
0162               SSL_get_app_data(ssl));
0163 
0164         verify_context verify_ctx(ctx);
0165         return callback->call(preverified != 0, verify_ctx) ? 1 : 0;
0166       }
0167     }
0168   }
0169 
0170   return 0;
0171 }
0172 
0173 engine::want engine::handshake(
0174     stream_base::handshake_type type, boost::system::error_code& ec)
0175 {
0176   return perform((type == boost::asio::ssl::stream_base::client)
0177       ? &engine::do_connect : &engine::do_accept, 0, 0, ec, 0);
0178 }
0179 
0180 engine::want engine::shutdown(boost::system::error_code& ec)
0181 {
0182   return perform(&engine::do_shutdown, 0, 0, ec, 0);
0183 }
0184 
0185 engine::want engine::write(const boost::asio::const_buffer& data,
0186     boost::system::error_code& ec, std::size_t& bytes_transferred)
0187 {
0188   if (data.size() == 0)
0189   {
0190     ec = boost::system::error_code();
0191     return engine::want_nothing;
0192   }
0193 
0194   return perform(&engine::do_write,
0195       const_cast<void*>(data.data()),
0196       data.size(), ec, &bytes_transferred);
0197 }
0198 
0199 engine::want engine::read(const boost::asio::mutable_buffer& data,
0200     boost::system::error_code& ec, std::size_t& bytes_transferred)
0201 {
0202   if (data.size() == 0)
0203   {
0204     ec = boost::system::error_code();
0205     return engine::want_nothing;
0206   }
0207 
0208   return perform(&engine::do_read, data.data(),
0209       data.size(), ec, &bytes_transferred);
0210 }
0211 
0212 boost::asio::mutable_buffer engine::get_output(
0213     const boost::asio::mutable_buffer& data)
0214 {
0215   int length = ::BIO_read(ext_bio_,
0216       data.data(), static_cast<int>(data.size()));
0217 
0218   return boost::asio::buffer(data,
0219       length > 0 ? static_cast<std::size_t>(length) : 0);
0220 }
0221 
0222 boost::asio::const_buffer engine::put_input(
0223     const boost::asio::const_buffer& data)
0224 {
0225   int length = ::BIO_write(ext_bio_,
0226       data.data(), static_cast<int>(data.size()));
0227 
0228   return boost::asio::buffer(data +
0229       (length > 0 ? static_cast<std::size_t>(length) : 0));
0230 }
0231 
0232 const boost::system::error_code& engine::map_error_code(
0233     boost::system::error_code& ec) const
0234 {
0235   // We only want to map the error::eof code.
0236   if (ec != boost::asio::error::eof)
0237     return ec;
0238 
0239   // If there's data yet to be read, it's an error.
0240   if (BIO_wpending(ext_bio_))
0241   {
0242     ec = boost::asio::ssl::error::stream_truncated;
0243     return ec;
0244   }
0245 
0246   // SSL v2 doesn't provide a protocol-level shutdown, so an eof on the
0247   // underlying transport is passed through.
0248 #if (OPENSSL_VERSION_NUMBER < 0x10100000L)
0249   if (SSL_version(ssl_) == SSL2_VERSION)
0250     return ec;
0251 #endif // (OPENSSL_VERSION_NUMBER < 0x10100000L)
0252 
0253   // Otherwise, the peer should have negotiated a proper shutdown.
0254   if ((::SSL_get_shutdown(ssl_) & SSL_RECEIVED_SHUTDOWN) == 0)
0255   {
0256     ec = boost::asio::ssl::error::stream_truncated;
0257   }
0258 
0259   return ec;
0260 }
0261 
0262 #if (OPENSSL_VERSION_NUMBER < 0x10000000L)
0263 boost::asio::detail::static_mutex& engine::accept_mutex()
0264 {
0265   static boost::asio::detail::static_mutex mutex = BOOST_ASIO_STATIC_MUTEX_INIT;
0266   return mutex;
0267 }
0268 #endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
0269 
0270 engine::want engine::perform(int (engine::* op)(void*, std::size_t),
0271     void* data, std::size_t length, boost::system::error_code& ec,
0272     std::size_t* bytes_transferred)
0273 {
0274   std::size_t pending_output_before = ::BIO_ctrl_pending(ext_bio_);
0275   ::ERR_clear_error();
0276   int result = (this->*op)(data, length);
0277   int ssl_error = ::SSL_get_error(ssl_, result);
0278   int sys_error = static_cast<int>(::ERR_get_error());
0279   std::size_t pending_output_after = ::BIO_ctrl_pending(ext_bio_);
0280 
0281   if (ssl_error == SSL_ERROR_SSL)
0282   {
0283     ec = boost::system::error_code(sys_error,
0284         boost::asio::error::get_ssl_category());
0285     return pending_output_after > pending_output_before
0286       ? want_output : want_nothing;
0287   }
0288 
0289   if (ssl_error == SSL_ERROR_SYSCALL)
0290   {
0291     if (sys_error == 0)
0292     {
0293       ec = boost::asio::ssl::error::unspecified_system_error;
0294     }
0295     else
0296     {
0297       ec = boost::system::error_code(sys_error,
0298           boost::asio::error::get_ssl_category());
0299     }
0300     return pending_output_after > pending_output_before
0301       ? want_output : want_nothing;
0302   }
0303 
0304   if (result > 0 && bytes_transferred)
0305     *bytes_transferred = static_cast<std::size_t>(result);
0306 
0307   if (ssl_error == SSL_ERROR_WANT_WRITE)
0308   {
0309     ec = boost::system::error_code();
0310     return want_output_and_retry;
0311   }
0312   else if (pending_output_after > pending_output_before)
0313   {
0314     ec = boost::system::error_code();
0315     return result > 0 ? want_output : want_output_and_retry;
0316   }
0317   else if (ssl_error == SSL_ERROR_WANT_READ)
0318   {
0319     ec = boost::system::error_code();
0320     return want_input_and_retry;
0321   }
0322   else if (ssl_error == SSL_ERROR_ZERO_RETURN)
0323   {
0324     ec = boost::asio::error::eof;
0325     return want_nothing;
0326   }
0327   else if (ssl_error == SSL_ERROR_NONE)
0328   {
0329     ec = boost::system::error_code();
0330     return want_nothing;
0331   }
0332   else
0333   {
0334     ec = boost::asio::ssl::error::unexpected_result;
0335     return want_nothing;
0336   }
0337 }
0338 
0339 int engine::do_accept(void*, std::size_t)
0340 {
0341 #if (OPENSSL_VERSION_NUMBER < 0x10000000L)
0342   boost::asio::detail::static_mutex::scoped_lock lock(accept_mutex());
0343 #endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
0344   return ::SSL_accept(ssl_);
0345 }
0346 
0347 int engine::do_connect(void*, std::size_t)
0348 {
0349   return ::SSL_connect(ssl_);
0350 }
0351 
0352 int engine::do_shutdown(void*, std::size_t)
0353 {
0354   int result = ::SSL_shutdown(ssl_);
0355   if (result == 0)
0356     result = ::SSL_shutdown(ssl_);
0357   return result;
0358 }
0359 
0360 int engine::do_read(void* data, std::size_t length)
0361 {
0362   return ::SSL_read(ssl_, data,
0363       length < INT_MAX ? static_cast<int>(length) : INT_MAX);
0364 }
0365 
0366 int engine::do_write(void* data, std::size_t length)
0367 {
0368   return ::SSL_write(ssl_, data,
0369       length < INT_MAX ? static_cast<int>(length) : INT_MAX);
0370 }
0371 
0372 } // namespace detail
0373 } // namespace ssl
0374 } // namespace asio
0375 } // namespace boost
0376 
0377 #include <boost/asio/detail/pop_options.hpp>
0378 
0379 #endif // BOOST_ASIO_SSL_DETAIL_IMPL_ENGINE_IPP