File indexing completed on 2025-01-18 09:29:01
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 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
0236 if (ec != boost::asio::error::eof)
0237 return ec;
0238
0239
0240 if (BIO_wpending(ext_bio_))
0241 {
0242 ec = boost::asio::ssl::error::stream_truncated;
0243 return ec;
0244 }
0245
0246
0247
0248 #if (OPENSSL_VERSION_NUMBER < 0x10100000L)
0249 if (SSL_version(ssl_) == SSL2_VERSION)
0250 return ec;
0251 #endif
0252
0253
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
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
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 }
0373 }
0374 }
0375 }
0376
0377 #include <boost/asio/detail/pop_options.hpp>
0378
0379 #endif