File indexing completed on 2025-09-15 08:29:51
0001
0002
0003
0004
0005
0006
0007
0008
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
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
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
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
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
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
0242 if (ec != boost::asio::error::eof)
0243 return ec;
0244
0245
0246 if (BIO_wpending(ext_bio_))
0247 {
0248 ec = boost::asio::ssl::error::stream_truncated;
0249 return ec;
0250 }
0251
0252
0253
0254 #if (OPENSSL_VERSION_NUMBER < 0x10100000L)
0255 if (SSL_version(ssl_) == SSL2_VERSION)
0256 return ec;
0257 #endif
0258
0259
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
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
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 }
0379 }
0380 }
0381 }
0382
0383 #include <boost/asio/detail/pop_options.hpp>
0384
0385 #endif