Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-06-30 08:08:15

0001 //
0002 // ssl/impl/context.ipp
0003 // ~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
0006 // Copyright (c) 2005-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0007 //
0008 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0009 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0010 //
0011 
0012 #ifndef BOOST_ASIO_SSL_IMPL_CONTEXT_IPP
0013 #define BOOST_ASIO_SSL_IMPL_CONTEXT_IPP
0014 
0015 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0016 # pragma once
0017 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0018 
0019 #include <boost/asio/detail/config.hpp>
0020 
0021 #include <cstring>
0022 #include <boost/asio/detail/throw_error.hpp>
0023 #include <boost/asio/error.hpp>
0024 #include <boost/asio/ssl/context.hpp>
0025 #include <boost/asio/ssl/error.hpp>
0026 
0027 #include <boost/asio/detail/push_options.hpp>
0028 
0029 namespace boost {
0030 namespace asio {
0031 namespace ssl {
0032 
0033 struct context::bio_cleanup
0034 {
0035   BIO* p;
0036   ~bio_cleanup() { if (p) ::BIO_free(p); }
0037 };
0038 
0039 struct context::x509_cleanup
0040 {
0041   X509* p;
0042   ~x509_cleanup() { if (p) ::X509_free(p); }
0043 };
0044 
0045 struct context::evp_pkey_cleanup
0046 {
0047   EVP_PKEY* p;
0048   ~evp_pkey_cleanup() { if (p) ::EVP_PKEY_free(p); }
0049 };
0050 
0051 #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
0052 struct context::rsa_cleanup
0053 {
0054   RSA* p;
0055   ~rsa_cleanup() { if (p) ::RSA_free(p); }
0056 };
0057 
0058 struct context::dh_cleanup
0059 {
0060   DH* p;
0061   ~dh_cleanup() { if (p) ::DH_free(p); }
0062 };
0063 #endif // (OPENSSL_VERSION_NUMBER < 0x30000000L)
0064 
0065 context::context(context::method m)
0066   : handle_(0)
0067 {
0068   ::ERR_clear_error();
0069 
0070   switch (m)
0071   {
0072     // SSL v2.
0073 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(OPENSSL_NO_SSL2)
0074   case context::sslv2:
0075   case context::sslv2_client:
0076   case context::sslv2_server:
0077     boost::asio::detail::throw_error(
0078         boost::asio::error::invalid_argument, "context");
0079     break;
0080 #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(OPENSSL_NO_SSL2)
0081   case context::sslv2:
0082     handle_ = ::SSL_CTX_new(::SSLv2_method());
0083     break;
0084   case context::sslv2_client:
0085     handle_ = ::SSL_CTX_new(::SSLv2_client_method());
0086     break;
0087   case context::sslv2_server:
0088     handle_ = ::SSL_CTX_new(::SSLv2_server_method());
0089     break;
0090 #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(OPENSSL_NO_SSL2)
0091 
0092     // SSL v3.
0093 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
0094   case context::sslv3:
0095     handle_ = ::SSL_CTX_new(::TLS_method());
0096     if (handle_)
0097     {
0098       SSL_CTX_set_min_proto_version(handle_, SSL3_VERSION);
0099       SSL_CTX_set_max_proto_version(handle_, SSL3_VERSION);
0100     }
0101     break;
0102   case context::sslv3_client:
0103     handle_ = ::SSL_CTX_new(::TLS_client_method());
0104     if (handle_)
0105     {
0106       SSL_CTX_set_min_proto_version(handle_, SSL3_VERSION);
0107       SSL_CTX_set_max_proto_version(handle_, SSL3_VERSION);
0108     }
0109     break;
0110   case context::sslv3_server:
0111     handle_ = ::SSL_CTX_new(::TLS_server_method());
0112     if (handle_)
0113     {
0114       SSL_CTX_set_min_proto_version(handle_, SSL3_VERSION);
0115       SSL_CTX_set_max_proto_version(handle_, SSL3_VERSION);
0116     }
0117     break;
0118 #elif defined(OPENSSL_NO_SSL3)
0119   case context::sslv3:
0120   case context::sslv3_client:
0121   case context::sslv3_server:
0122     boost::asio::detail::throw_error(
0123         boost::asio::error::invalid_argument, "context");
0124     break;
0125 #else // defined(OPENSSL_NO_SSL3)
0126   case context::sslv3:
0127     handle_ = ::SSL_CTX_new(::SSLv3_method());
0128     break;
0129   case context::sslv3_client:
0130     handle_ = ::SSL_CTX_new(::SSLv3_client_method());
0131     break;
0132   case context::sslv3_server:
0133     handle_ = ::SSL_CTX_new(::SSLv3_server_method());
0134     break;
0135 #endif // defined(OPENSSL_NO_SSL3)
0136 
0137     // TLS v1.0.
0138 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
0139   case context::tlsv1:
0140     handle_ = ::SSL_CTX_new(::TLS_method());
0141     if (handle_)
0142     {
0143       SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);
0144       SSL_CTX_set_max_proto_version(handle_, TLS1_VERSION);
0145     }
0146     break;
0147   case context::tlsv1_client:
0148     handle_ = ::SSL_CTX_new(::TLS_client_method());
0149     if (handle_)
0150     {
0151       SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);
0152       SSL_CTX_set_max_proto_version(handle_, TLS1_VERSION);
0153     }
0154     break;
0155   case context::tlsv1_server:
0156     handle_ = ::SSL_CTX_new(::TLS_server_method());
0157     if (handle_)
0158     {
0159       SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);
0160       SSL_CTX_set_max_proto_version(handle_, TLS1_VERSION);
0161     }
0162     break;
0163 #elif defined(SSL_TXT_TLSV1)
0164   case context::tlsv1:
0165     handle_ = ::SSL_CTX_new(::TLSv1_method());
0166     break;
0167   case context::tlsv1_client:
0168     handle_ = ::SSL_CTX_new(::TLSv1_client_method());
0169     break;
0170   case context::tlsv1_server:
0171     handle_ = ::SSL_CTX_new(::TLSv1_server_method());
0172     break;
0173 #else // defined(SSL_TXT_TLSV1)
0174   case context::tlsv1:
0175   case context::tlsv1_client:
0176   case context::tlsv1_server:
0177     boost::asio::detail::throw_error(
0178         boost::asio::error::invalid_argument, "context");
0179     break;
0180 #endif // defined(SSL_TXT_TLSV1)
0181 
0182     // TLS v1.1.
0183 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
0184   case context::tlsv11:
0185     handle_ = ::SSL_CTX_new(::TLS_method());
0186     if (handle_)
0187     {
0188       SSL_CTX_set_min_proto_version(handle_, TLS1_1_VERSION);
0189       SSL_CTX_set_max_proto_version(handle_, TLS1_1_VERSION);
0190     }
0191     break;
0192   case context::tlsv11_client:
0193     handle_ = ::SSL_CTX_new(::TLS_client_method());
0194     if (handle_)
0195     {
0196       SSL_CTX_set_min_proto_version(handle_, TLS1_1_VERSION);
0197       SSL_CTX_set_max_proto_version(handle_, TLS1_1_VERSION);
0198     }
0199     break;
0200   case context::tlsv11_server:
0201     handle_ = ::SSL_CTX_new(::TLS_server_method());
0202     if (handle_)
0203     {
0204       SSL_CTX_set_min_proto_version(handle_, TLS1_1_VERSION);
0205       SSL_CTX_set_max_proto_version(handle_, TLS1_1_VERSION);
0206     }
0207     break;
0208 #elif defined(SSL_TXT_TLSV1_1)
0209   case context::tlsv11:
0210     handle_ = ::SSL_CTX_new(::TLSv1_1_method());
0211     break;
0212   case context::tlsv11_client:
0213     handle_ = ::SSL_CTX_new(::TLSv1_1_client_method());
0214     break;
0215   case context::tlsv11_server:
0216     handle_ = ::SSL_CTX_new(::TLSv1_1_server_method());
0217     break;
0218 #else // defined(SSL_TXT_TLSV1_1)
0219   case context::tlsv11:
0220   case context::tlsv11_client:
0221   case context::tlsv11_server:
0222     boost::asio::detail::throw_error(
0223         boost::asio::error::invalid_argument, "context");
0224     break;
0225 #endif // defined(SSL_TXT_TLSV1_1)
0226 
0227     // TLS v1.2.
0228 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
0229   case context::tlsv12:
0230     handle_ = ::SSL_CTX_new(::TLS_method());
0231     if (handle_)
0232     {
0233       SSL_CTX_set_min_proto_version(handle_, TLS1_2_VERSION);
0234       SSL_CTX_set_max_proto_version(handle_, TLS1_2_VERSION);
0235     }
0236     break;
0237   case context::tlsv12_client:
0238     handle_ = ::SSL_CTX_new(::TLS_client_method());
0239     if (handle_)
0240     {
0241       SSL_CTX_set_min_proto_version(handle_, TLS1_2_VERSION);
0242       SSL_CTX_set_max_proto_version(handle_, TLS1_2_VERSION);
0243     }
0244     break;
0245   case context::tlsv12_server:
0246     handle_ = ::SSL_CTX_new(::TLS_server_method());
0247     if (handle_)
0248     {
0249       SSL_CTX_set_min_proto_version(handle_, TLS1_2_VERSION);
0250       SSL_CTX_set_max_proto_version(handle_, TLS1_2_VERSION);
0251     }
0252     break;
0253 #elif defined(SSL_TXT_TLSV1_2)
0254   case context::tlsv12:
0255     handle_ = ::SSL_CTX_new(::TLSv1_2_method());
0256     break;
0257   case context::tlsv12_client:
0258     handle_ = ::SSL_CTX_new(::TLSv1_2_client_method());
0259     break;
0260   case context::tlsv12_server:
0261     handle_ = ::SSL_CTX_new(::TLSv1_2_server_method());
0262     break;
0263 #else // defined(SSL_TXT_TLSV1_2)
0264   case context::tlsv12:
0265   case context::tlsv12_client:
0266   case context::tlsv12_server:
0267     boost::asio::detail::throw_error(
0268         boost::asio::error::invalid_argument, "context");
0269     break;
0270 #endif // defined(SSL_TXT_TLSV1_2)
0271 
0272     // TLS v1.3.
0273 #if ((OPENSSL_VERSION_NUMBER >= 0x10101000L) \
0274       && !defined(LIBRESSL_VERSION_NUMBER)) \
0275     || defined(BOOST_ASIO_USE_WOLFSSL)
0276   case context::tlsv13:
0277     handle_ = ::SSL_CTX_new(::TLS_method());
0278     if (handle_)
0279     {
0280       SSL_CTX_set_min_proto_version(handle_, TLS1_3_VERSION);
0281       SSL_CTX_set_max_proto_version(handle_, TLS1_3_VERSION);
0282     }
0283     break;
0284   case context::tlsv13_client:
0285     handle_ = ::SSL_CTX_new(::TLS_client_method());
0286     if (handle_)
0287     {
0288       SSL_CTX_set_min_proto_version(handle_, TLS1_3_VERSION);
0289       SSL_CTX_set_max_proto_version(handle_, TLS1_3_VERSION);
0290     }
0291     break;
0292   case context::tlsv13_server:
0293     handle_ = ::SSL_CTX_new(::TLS_server_method());
0294     if (handle_)
0295     {
0296       SSL_CTX_set_min_proto_version(handle_, TLS1_3_VERSION);
0297       SSL_CTX_set_max_proto_version(handle_, TLS1_3_VERSION);
0298     }
0299     break;
0300 #else // ((OPENSSL_VERSION_NUMBER >= 0x10101000L)
0301       //     && !defined(LIBRESSL_VERSION_NUMBER))
0302       //   || defined(BOOST_ASIO_USE_WOLFSSL)
0303   case context::tlsv13:
0304   case context::tlsv13_client:
0305   case context::tlsv13_server:
0306     boost::asio::detail::throw_error(
0307         boost::asio::error::invalid_argument, "context");
0308     break;
0309 #endif // ((OPENSSL_VERSION_NUMBER >= 0x10101000L)
0310        //     && !defined(LIBRESSL_VERSION_NUMBER))
0311        //   || defined(BOOST_ASIO_USE_WOLFSSL)
0312 
0313     // Any supported SSL/TLS version.
0314   case context::sslv23:
0315     handle_ = ::SSL_CTX_new(::SSLv23_method());
0316     break;
0317   case context::sslv23_client:
0318     handle_ = ::SSL_CTX_new(::SSLv23_client_method());
0319     break;
0320   case context::sslv23_server:
0321     handle_ = ::SSL_CTX_new(::SSLv23_server_method());
0322     break;
0323 
0324     // Any supported TLS version.
0325 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
0326   case context::tls:
0327     handle_ = ::SSL_CTX_new(::TLS_method());
0328     if (handle_)
0329       SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);
0330     break;
0331   case context::tls_client:
0332     handle_ = ::SSL_CTX_new(::TLS_client_method());
0333     if (handle_)
0334       SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);
0335     break;
0336   case context::tls_server:
0337     handle_ = ::SSL_CTX_new(::TLS_server_method());
0338     if (handle_)
0339       SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);
0340     break;
0341 #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0342   case context::tls:
0343     handle_ = ::SSL_CTX_new(::SSLv23_method());
0344     if (handle_)
0345       SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
0346     break;
0347   case context::tls_client:
0348     handle_ = ::SSL_CTX_new(::SSLv23_client_method());
0349     if (handle_)
0350       SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
0351     break;
0352   case context::tls_server:
0353     handle_ = ::SSL_CTX_new(::SSLv23_server_method());
0354     if (handle_)
0355       SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
0356     break;
0357 #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0358 
0359   default:
0360     handle_ = ::SSL_CTX_new(0);
0361     break;
0362   }
0363 
0364   if (handle_ == 0)
0365   {
0366     boost::system::error_code ec = translate_error(::ERR_get_error());
0367     boost::asio::detail::throw_error(ec, "context");
0368   }
0369 
0370   set_options(no_compression);
0371 }
0372 
0373 context::context(context::native_handle_type native_handle)
0374   : handle_(native_handle)
0375 {
0376   if (!handle_)
0377   {
0378     boost::asio::detail::throw_error(
0379         boost::asio::error::invalid_argument, "context");
0380   }
0381 }
0382 
0383 context::context(context&& other)
0384 {
0385   handle_ = other.handle_;
0386   other.handle_ = 0;
0387 }
0388 
0389 context& context::operator=(context&& other)
0390 {
0391   context tmp(static_cast<context&&>(*this));
0392   handle_ = other.handle_;
0393   other.handle_ = 0;
0394   return *this;
0395 }
0396 
0397 context::~context()
0398 {
0399   if (handle_)
0400   {
0401 #if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \
0402       && (!defined(LIBRESSL_VERSION_NUMBER) \
0403         || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)) \
0404     || defined(BOOST_ASIO_USE_WOLFSSL)
0405     void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
0406 #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0407     void* cb_userdata = handle_->default_passwd_callback_userdata;
0408 #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0409     if (cb_userdata)
0410     {
0411       detail::password_callback_base* callback =
0412         static_cast<detail::password_callback_base*>(
0413             cb_userdata);
0414       delete callback;
0415 #if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \
0416       && (!defined(LIBRESSL_VERSION_NUMBER) \
0417         || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)) \
0418     || defined(BOOST_ASIO_USE_WOLFSSL)
0419       ::SSL_CTX_set_default_passwd_cb_userdata(handle_, 0);
0420 #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0421       handle_->default_passwd_callback_userdata = 0;
0422 #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0423     }
0424 
0425     if (SSL_CTX_get_app_data(handle_))
0426     {
0427       detail::verify_callback_base* callback =
0428         static_cast<detail::verify_callback_base*>(
0429             SSL_CTX_get_app_data(handle_));
0430       delete callback;
0431       SSL_CTX_set_app_data(handle_, 0);
0432     }
0433 
0434     ::SSL_CTX_free(handle_);
0435   }
0436 }
0437 
0438 context::native_handle_type context::native_handle()
0439 {
0440   return handle_;
0441 }
0442 
0443 void context::clear_options(context::options o)
0444 {
0445   boost::system::error_code ec;
0446   clear_options(o, ec);
0447   boost::asio::detail::throw_error(ec, "clear_options");
0448 }
0449 
0450 BOOST_ASIO_SYNC_OP_VOID context::clear_options(
0451     context::options o, boost::system::error_code& ec)
0452 {
0453 #if (OPENSSL_VERSION_NUMBER >= 0x009080DFL) \
0454   && (OPENSSL_VERSION_NUMBER != 0x00909000L)
0455 # if !defined(SSL_OP_NO_COMPRESSION)
0456   if ((o & context::no_compression) != 0)
0457   {
0458 # if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
0459     handle_->comp_methods = SSL_COMP_get_compression_methods();
0460 # endif // (OPENSSL_VERSION_NUMBER >= 0x00908000L)
0461     o ^= context::no_compression;
0462   }
0463 # endif // !defined(SSL_OP_NO_COMPRESSION)
0464 
0465   ::SSL_CTX_clear_options(handle_, o);
0466 
0467   ec = boost::system::error_code();
0468 #else // (OPENSSL_VERSION_NUMBER >= 0x009080DFL)
0469       //   && (OPENSSL_VERSION_NUMBER != 0x00909000L)
0470   (void)o;
0471   ec = boost::asio::error::operation_not_supported;
0472 #endif // (OPENSSL_VERSION_NUMBER >= 0x009080DFL)
0473        //   && (OPENSSL_VERSION_NUMBER != 0x00909000L)
0474   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0475 }
0476 
0477 void context::set_options(context::options o)
0478 {
0479   boost::system::error_code ec;
0480   set_options(o, ec);
0481   boost::asio::detail::throw_error(ec, "set_options");
0482 }
0483 
0484 BOOST_ASIO_SYNC_OP_VOID context::set_options(
0485     context::options o, boost::system::error_code& ec)
0486 {
0487 #if !defined(SSL_OP_NO_COMPRESSION)
0488   if ((o & context::no_compression) != 0)
0489   {
0490 #if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
0491     handle_->comp_methods =
0492       boost::asio::ssl::detail::openssl_init<>::get_null_compression_methods();
0493 #endif // (OPENSSL_VERSION_NUMBER >= 0x00908000L)
0494     o ^= context::no_compression;
0495   }
0496 #endif // !defined(SSL_OP_NO_COMPRESSION)
0497 
0498   ::SSL_CTX_set_options(handle_, o);
0499 
0500   ec = boost::system::error_code();
0501   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0502 }
0503 
0504 void context::set_verify_mode(verify_mode v)
0505 {
0506   boost::system::error_code ec;
0507   set_verify_mode(v, ec);
0508   boost::asio::detail::throw_error(ec, "set_verify_mode");
0509 }
0510 
0511 BOOST_ASIO_SYNC_OP_VOID context::set_verify_mode(
0512     verify_mode v, boost::system::error_code& ec)
0513 {
0514   ::SSL_CTX_set_verify(handle_, v, ::SSL_CTX_get_verify_callback(handle_));
0515 
0516   ec = boost::system::error_code();
0517   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0518 }
0519 
0520 void context::set_verify_depth(int depth)
0521 {
0522   boost::system::error_code ec;
0523   set_verify_depth(depth, ec);
0524   boost::asio::detail::throw_error(ec, "set_verify_depth");
0525 }
0526 
0527 BOOST_ASIO_SYNC_OP_VOID context::set_verify_depth(
0528     int depth, boost::system::error_code& ec)
0529 {
0530   ::SSL_CTX_set_verify_depth(handle_, depth);
0531 
0532   ec = boost::system::error_code();
0533   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0534 }
0535 
0536 void context::load_verify_file(const std::string& filename)
0537 {
0538   boost::system::error_code ec;
0539   load_verify_file(filename, ec);
0540   boost::asio::detail::throw_error(ec, "load_verify_file");
0541 }
0542 
0543 BOOST_ASIO_SYNC_OP_VOID context::load_verify_file(
0544     const std::string& filename, boost::system::error_code& ec)
0545 {
0546   ::ERR_clear_error();
0547 
0548   if (::SSL_CTX_load_verify_locations(handle_, filename.c_str(), 0) != 1)
0549   {
0550     ec = translate_error(::ERR_get_error());
0551     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0552   }
0553 
0554   ec = boost::system::error_code();
0555   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0556 }
0557 
0558 void context::add_certificate_authority(const const_buffer& ca)
0559 {
0560   boost::system::error_code ec;
0561   add_certificate_authority(ca, ec);
0562   boost::asio::detail::throw_error(ec, "add_certificate_authority");
0563 }
0564 
0565 BOOST_ASIO_SYNC_OP_VOID context::add_certificate_authority(
0566     const const_buffer& ca, boost::system::error_code& ec)
0567 {
0568   ::ERR_clear_error();
0569 
0570   bio_cleanup bio = { make_buffer_bio(ca) };
0571   if (bio.p)
0572   {
0573     if (X509_STORE* store = ::SSL_CTX_get_cert_store(handle_))
0574     {
0575       for (bool added = false;; added = true)
0576       {
0577         x509_cleanup cert = { ::PEM_read_bio_X509(bio.p, 0, 0, 0) };
0578         if (!cert.p)
0579         {
0580           unsigned long err = ::ERR_get_error();
0581           if (added && ERR_GET_LIB(err) == ERR_LIB_PEM
0582               && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)
0583             break;
0584 
0585           ec = translate_error(err);
0586           BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0587         }
0588 
0589         if (::X509_STORE_add_cert(store, cert.p) != 1)
0590         {
0591           ec = translate_error(::ERR_get_error());
0592           BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0593         }
0594       }
0595     }
0596   }
0597 
0598   ec = boost::system::error_code();
0599   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0600 }
0601 
0602 void context::set_default_verify_paths()
0603 {
0604   boost::system::error_code ec;
0605   set_default_verify_paths(ec);
0606   boost::asio::detail::throw_error(ec, "set_default_verify_paths");
0607 }
0608 
0609 BOOST_ASIO_SYNC_OP_VOID context::set_default_verify_paths(
0610     boost::system::error_code& ec)
0611 {
0612   ::ERR_clear_error();
0613 
0614   if (::SSL_CTX_set_default_verify_paths(handle_) != 1)
0615   {
0616     ec = translate_error(::ERR_get_error());
0617     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0618   }
0619 
0620   ec = boost::system::error_code();
0621   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0622 }
0623 
0624 void context::add_verify_path(const std::string& path)
0625 {
0626   boost::system::error_code ec;
0627   add_verify_path(path, ec);
0628   boost::asio::detail::throw_error(ec, "add_verify_path");
0629 }
0630 
0631 BOOST_ASIO_SYNC_OP_VOID context::add_verify_path(
0632     const std::string& path, boost::system::error_code& ec)
0633 {
0634   ::ERR_clear_error();
0635 
0636   if (::SSL_CTX_load_verify_locations(handle_, 0, path.c_str()) != 1)
0637   {
0638     ec = translate_error(::ERR_get_error());
0639     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0640   }
0641 
0642   ec = boost::system::error_code();
0643   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0644 }
0645 
0646 void context::use_certificate(
0647     const const_buffer& certificate, file_format format)
0648 {
0649   boost::system::error_code ec;
0650   use_certificate(certificate, format, ec);
0651   boost::asio::detail::throw_error(ec, "use_certificate");
0652 }
0653 
0654 BOOST_ASIO_SYNC_OP_VOID context::use_certificate(
0655     const const_buffer& certificate, file_format format,
0656     boost::system::error_code& ec)
0657 {
0658   ::ERR_clear_error();
0659 
0660   if (format == context_base::asn1)
0661   {
0662     if (::SSL_CTX_use_certificate_ASN1(handle_,
0663           static_cast<int>(certificate.size()),
0664           static_cast<const unsigned char*>(certificate.data())) == 1)
0665     {
0666       ec = boost::system::error_code();
0667       BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0668     }
0669   }
0670   else if (format == context_base::pem)
0671   {
0672     bio_cleanup bio = { make_buffer_bio(certificate) };
0673     if (bio.p)
0674     {
0675       x509_cleanup cert = { ::PEM_read_bio_X509(bio.p, 0, 0, 0) };
0676       if (cert.p)
0677       {
0678         if (::SSL_CTX_use_certificate(handle_, cert.p) == 1)
0679         {
0680           ec = boost::system::error_code();
0681           BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0682         }
0683       }
0684     }
0685   }
0686   else
0687   {
0688     ec = boost::asio::error::invalid_argument;
0689     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0690   }
0691 
0692   ec = translate_error(::ERR_get_error());
0693   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0694 }
0695 
0696 void context::use_certificate_file(
0697     const std::string& filename, file_format format)
0698 {
0699   boost::system::error_code ec;
0700   use_certificate_file(filename, format, ec);
0701   boost::asio::detail::throw_error(ec, "use_certificate_file");
0702 }
0703 
0704 BOOST_ASIO_SYNC_OP_VOID context::use_certificate_file(
0705     const std::string& filename, file_format format,
0706     boost::system::error_code& ec)
0707 {
0708   int file_type;
0709   switch (format)
0710   {
0711   case context_base::asn1:
0712     file_type = SSL_FILETYPE_ASN1;
0713     break;
0714   case context_base::pem:
0715     file_type = SSL_FILETYPE_PEM;
0716     break;
0717   default:
0718     {
0719       ec = boost::asio::error::invalid_argument;
0720       BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0721     }
0722   }
0723 
0724   ::ERR_clear_error();
0725 
0726   if (::SSL_CTX_use_certificate_file(handle_, filename.c_str(), file_type) != 1)
0727   {
0728     ec = translate_error(::ERR_get_error());
0729     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0730   }
0731 
0732   ec = boost::system::error_code();
0733   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0734 }
0735 
0736 void context::use_certificate_chain(const const_buffer& chain)
0737 {
0738   boost::system::error_code ec;
0739   use_certificate_chain(chain, ec);
0740   boost::asio::detail::throw_error(ec, "use_certificate_chain");
0741 }
0742 
0743 BOOST_ASIO_SYNC_OP_VOID context::use_certificate_chain(
0744     const const_buffer& chain, boost::system::error_code& ec)
0745 {
0746   ::ERR_clear_error();
0747 
0748   bio_cleanup bio = { make_buffer_bio(chain) };
0749   if (bio.p)
0750   {
0751 #if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \
0752       && (!defined(LIBRESSL_VERSION_NUMBER) \
0753         || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)) \
0754     || defined(BOOST_ASIO_USE_WOLFSSL)
0755     pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_);
0756     void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
0757 #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0758     pem_password_cb* callback = handle_->default_passwd_callback;
0759     void* cb_userdata = handle_->default_passwd_callback_userdata;
0760 #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0761     x509_cleanup cert = {
0762       ::PEM_read_bio_X509_AUX(bio.p, 0,
0763           callback,
0764           cb_userdata) };
0765     if (!cert.p)
0766     {
0767       ec = translate_error(ERR_R_PEM_LIB);
0768       BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0769     }
0770 
0771     int result = ::SSL_CTX_use_certificate(handle_, cert.p);
0772     if (result == 0 || ::ERR_peek_error() != 0)
0773     {
0774       ec = translate_error(::ERR_get_error());
0775       BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0776     }
0777 
0778 #if ((OPENSSL_VERSION_NUMBER >= 0x10002000L) \
0779       && (!defined(LIBRESSL_VERSION_NUMBER) \
0780         || LIBRESSL_VERSION_NUMBER >= 0x2090100fL)) \
0781     || defined(BOOST_ASIO_USE_WOLFSSL)
0782     ::SSL_CTX_clear_chain_certs(handle_);
0783 #else
0784     if (handle_->extra_certs)
0785     {
0786       ::sk_X509_pop_free(handle_->extra_certs, X509_free);
0787       handle_->extra_certs = 0;
0788     }
0789 #endif // (OPENSSL_VERSION_NUMBER >= 0x10002000L)
0790 
0791     while (X509* cacert = ::PEM_read_bio_X509(bio.p, 0,
0792           callback,
0793           cb_userdata))
0794     {
0795       if (!::SSL_CTX_add_extra_chain_cert(handle_, cacert))
0796       {
0797         ec = translate_error(::ERR_get_error());
0798         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0799       }
0800     }
0801 
0802     result = ::ERR_peek_last_error();
0803     if ((ERR_GET_LIB(result) == ERR_LIB_PEM)
0804         && (ERR_GET_REASON(result) == PEM_R_NO_START_LINE))
0805     {
0806       ::ERR_clear_error();
0807       ec = boost::system::error_code();
0808       BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0809     }
0810   }
0811 
0812   ec = translate_error(::ERR_get_error());
0813   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0814 }
0815 
0816 void context::use_certificate_chain_file(const std::string& filename)
0817 {
0818   boost::system::error_code ec;
0819   use_certificate_chain_file(filename, ec);
0820   boost::asio::detail::throw_error(ec, "use_certificate_chain_file");
0821 }
0822 
0823 BOOST_ASIO_SYNC_OP_VOID context::use_certificate_chain_file(
0824     const std::string& filename, boost::system::error_code& ec)
0825 {
0826   ::ERR_clear_error();
0827 
0828   if (::SSL_CTX_use_certificate_chain_file(handle_, filename.c_str()) != 1)
0829   {
0830     ec = translate_error(::ERR_get_error());
0831     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0832   }
0833 
0834   ec = boost::system::error_code();
0835   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0836 }
0837 
0838 void context::use_private_key(
0839     const const_buffer& private_key, context::file_format format)
0840 {
0841   boost::system::error_code ec;
0842   use_private_key(private_key, format, ec);
0843   boost::asio::detail::throw_error(ec, "use_private_key");
0844 }
0845 
0846 BOOST_ASIO_SYNC_OP_VOID context::use_private_key(
0847     const const_buffer& private_key, context::file_format format,
0848     boost::system::error_code& ec)
0849 {
0850   ::ERR_clear_error();
0851 
0852 #if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \
0853       && (!defined(LIBRESSL_VERSION_NUMBER) \
0854         || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)) \
0855     || defined(BOOST_ASIO_USE_WOLFSSL)
0856     pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_);
0857     void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
0858 #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0859     pem_password_cb* callback = handle_->default_passwd_callback;
0860     void* cb_userdata = handle_->default_passwd_callback_userdata;
0861 #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0862 
0863   bio_cleanup bio = { make_buffer_bio(private_key) };
0864   if (bio.p)
0865   {
0866     evp_pkey_cleanup evp_private_key = { 0 };
0867     switch (format)
0868     {
0869     case context_base::asn1:
0870       evp_private_key.p = ::d2i_PrivateKey_bio(bio.p, 0);
0871       break;
0872     case context_base::pem:
0873       evp_private_key.p = ::PEM_read_bio_PrivateKey(
0874           bio.p, 0, callback,
0875           cb_userdata);
0876       break;
0877     default:
0878       {
0879         ec = boost::asio::error::invalid_argument;
0880         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0881       }
0882     }
0883 
0884     if (evp_private_key.p)
0885     {
0886       if (::SSL_CTX_use_PrivateKey(handle_, evp_private_key.p) == 1)
0887       {
0888         ec = boost::system::error_code();
0889         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0890       }
0891     }
0892   }
0893 
0894   ec = translate_error(::ERR_get_error());
0895   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0896 }
0897 
0898 void context::use_private_key_file(
0899     const std::string& filename, context::file_format format)
0900 {
0901   boost::system::error_code ec;
0902   use_private_key_file(filename, format, ec);
0903   boost::asio::detail::throw_error(ec, "use_private_key_file");
0904 }
0905 
0906 void context::use_rsa_private_key(
0907     const const_buffer& private_key, context::file_format format)
0908 {
0909   boost::system::error_code ec;
0910   use_rsa_private_key(private_key, format, ec);
0911   boost::asio::detail::throw_error(ec, "use_rsa_private_key");
0912 }
0913 
0914 BOOST_ASIO_SYNC_OP_VOID context::use_rsa_private_key(
0915     const const_buffer& private_key, context::file_format format,
0916     boost::system::error_code& ec)
0917 {
0918   ::ERR_clear_error();
0919 
0920 #if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \
0921       && (!defined(LIBRESSL_VERSION_NUMBER) \
0922         || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)) \
0923     || defined(BOOST_ASIO_USE_WOLFSSL)
0924   pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_);
0925   void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
0926 #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0927   pem_password_cb* callback = handle_->default_passwd_callback;
0928   void* cb_userdata = handle_->default_passwd_callback_userdata;
0929 #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0930 
0931   bio_cleanup bio = { make_buffer_bio(private_key) };
0932   if (bio.p)
0933   {
0934 #if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
0935     evp_pkey_cleanup evp_private_key = { 0 };
0936     switch (format)
0937     {
0938     case context_base::asn1:
0939       evp_private_key.p = ::d2i_PrivateKey_bio(bio.p, 0);
0940       break;
0941     case context_base::pem:
0942       evp_private_key.p = ::PEM_read_bio_PrivateKey(
0943           bio.p, 0, callback,
0944           cb_userdata);
0945       break;
0946     default:
0947       {
0948         ec = boost::asio::error::invalid_argument;
0949         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0950       }
0951     }
0952 
0953     if (evp_private_key.p)
0954     {
0955       if (::EVP_PKEY_is_a(evp_private_key.p, "RSA") == 0)
0956       {
0957         ec = translate_error(
0958             ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_AN_RSA_KEY));
0959         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0960       }
0961 
0962       if (::SSL_CTX_use_PrivateKey(handle_, evp_private_key.p) == 1)
0963       {
0964         ec = boost::system::error_code();
0965         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0966       }
0967     }
0968 #else // (OPENSSL_VERSION_NUMBER >= 0x30000000L)
0969     rsa_cleanup rsa_private_key = { 0 };
0970     switch (format)
0971     {
0972     case context_base::asn1:
0973       rsa_private_key.p = ::d2i_RSAPrivateKey_bio(bio.p, 0);
0974       break;
0975     case context_base::pem:
0976       rsa_private_key.p = ::PEM_read_bio_RSAPrivateKey(
0977           bio.p, 0, callback,
0978           cb_userdata);
0979       break;
0980     default:
0981       {
0982         ec = boost::asio::error::invalid_argument;
0983         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0984       }
0985     }
0986 
0987     if (rsa_private_key.p)
0988     {
0989       if (::SSL_CTX_use_RSAPrivateKey(handle_, rsa_private_key.p) == 1)
0990       {
0991         ec = boost::system::error_code();
0992         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0993       }
0994     }
0995 #endif // (OPENSSL_VERSION_NUMBER >= 0x30000000L)
0996   }
0997 
0998   ec = translate_error(::ERR_get_error());
0999   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1000 }
1001 
1002 BOOST_ASIO_SYNC_OP_VOID context::use_private_key_file(
1003     const std::string& filename, context::file_format format,
1004     boost::system::error_code& ec)
1005 {
1006   int file_type;
1007   switch (format)
1008   {
1009   case context_base::asn1:
1010     file_type = SSL_FILETYPE_ASN1;
1011     break;
1012   case context_base::pem:
1013     file_type = SSL_FILETYPE_PEM;
1014     break;
1015   default:
1016     {
1017       ec = boost::asio::error::invalid_argument;
1018       BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1019     }
1020   }
1021 
1022   ::ERR_clear_error();
1023 
1024   if (::SSL_CTX_use_PrivateKey_file(handle_, filename.c_str(), file_type) != 1)
1025   {
1026     ec = translate_error(::ERR_get_error());
1027     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1028   }
1029 
1030   ec = boost::system::error_code();
1031   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1032 }
1033 
1034 void context::use_rsa_private_key_file(
1035     const std::string& filename, context::file_format format)
1036 {
1037   boost::system::error_code ec;
1038   use_rsa_private_key_file(filename, format, ec);
1039   boost::asio::detail::throw_error(ec, "use_rsa_private_key_file");
1040 }
1041 
1042 BOOST_ASIO_SYNC_OP_VOID context::use_rsa_private_key_file(
1043     const std::string& filename, context::file_format format,
1044     boost::system::error_code& ec)
1045 {
1046 #if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1047   ::ERR_clear_error();
1048 
1049   pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_);
1050   void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
1051 
1052   bio_cleanup bio = { ::BIO_new_file(filename.c_str(), "r") };
1053   if (bio.p)
1054   {
1055     evp_pkey_cleanup evp_private_key = { 0 };
1056     switch (format)
1057     {
1058     case context_base::asn1:
1059       evp_private_key.p = ::d2i_PrivateKey_bio(bio.p, 0);
1060       break;
1061     case context_base::pem:
1062       evp_private_key.p = ::PEM_read_bio_PrivateKey(
1063           bio.p, 0, callback,
1064           cb_userdata);
1065       break;
1066     default:
1067       {
1068         ec = boost::asio::error::invalid_argument;
1069         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1070       }
1071     }
1072 
1073     if (evp_private_key.p)
1074     {
1075       if (::EVP_PKEY_is_a(evp_private_key.p, "RSA") == 0)
1076       {
1077         ec = translate_error(
1078             ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_AN_RSA_KEY));
1079         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1080       }
1081 
1082       if (::SSL_CTX_use_PrivateKey(handle_, evp_private_key.p) == 1)
1083       {
1084         ec = boost::system::error_code();
1085         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1086       }
1087     }
1088   }
1089 
1090   ec = translate_error(::ERR_get_error());
1091   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1092 #else // (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1093   int file_type;
1094   switch (format)
1095   {
1096   case context_base::asn1:
1097     file_type = SSL_FILETYPE_ASN1;
1098     break;
1099   case context_base::pem:
1100     file_type = SSL_FILETYPE_PEM;
1101     break;
1102   default:
1103     {
1104       ec = boost::asio::error::invalid_argument;
1105       BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1106     }
1107   }
1108 
1109   ::ERR_clear_error();
1110 
1111   if (::SSL_CTX_use_RSAPrivateKey_file(
1112         handle_, filename.c_str(), file_type) != 1)
1113   {
1114     ec = translate_error(::ERR_get_error());
1115     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1116   }
1117 
1118   ec = boost::system::error_code();
1119   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1120 #endif // (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1121 }
1122 
1123 void context::use_tmp_dh(const const_buffer& dh)
1124 {
1125   boost::system::error_code ec;
1126   use_tmp_dh(dh, ec);
1127   boost::asio::detail::throw_error(ec, "use_tmp_dh");
1128 }
1129 
1130 BOOST_ASIO_SYNC_OP_VOID context::use_tmp_dh(
1131     const const_buffer& dh, boost::system::error_code& ec)
1132 {
1133   ::ERR_clear_error();
1134 
1135   bio_cleanup bio = { make_buffer_bio(dh) };
1136   if (bio.p)
1137   {
1138     return do_use_tmp_dh(bio.p, ec);
1139   }
1140 
1141   ec = translate_error(::ERR_get_error());
1142   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1143 }
1144 
1145 void context::use_tmp_dh_file(const std::string& filename)
1146 {
1147   boost::system::error_code ec;
1148   use_tmp_dh_file(filename, ec);
1149   boost::asio::detail::throw_error(ec, "use_tmp_dh_file");
1150 }
1151 
1152 BOOST_ASIO_SYNC_OP_VOID context::use_tmp_dh_file(
1153     const std::string& filename, boost::system::error_code& ec)
1154 {
1155   ::ERR_clear_error();
1156 
1157   bio_cleanup bio = { ::BIO_new_file(filename.c_str(), "r") };
1158   if (bio.p)
1159   {
1160     return do_use_tmp_dh(bio.p, ec);
1161   }
1162 
1163   ec = translate_error(::ERR_get_error());
1164   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1165 }
1166 
1167 BOOST_ASIO_SYNC_OP_VOID context::do_use_tmp_dh(
1168     BIO* bio, boost::system::error_code& ec)
1169 {
1170   ::ERR_clear_error();
1171 
1172 #if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1173   EVP_PKEY* p = ::PEM_read_bio_Parameters(bio, 0);
1174   if (p)
1175   {
1176     if (::SSL_CTX_set0_tmp_dh_pkey(handle_, p) == 1)
1177     {
1178       ec = boost::system::error_code();
1179       BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1180     }
1181     else
1182       ::EVP_PKEY_free(p);
1183   }
1184 #else // (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1185   dh_cleanup dh = { ::PEM_read_bio_DHparams(bio, 0, 0, 0) };
1186   if (dh.p)
1187   {
1188     if (::SSL_CTX_set_tmp_dh(handle_, dh.p) == 1)
1189     {
1190       ec = boost::system::error_code();
1191       BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1192     }
1193   }
1194 #endif // (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1195 
1196   ec = translate_error(::ERR_get_error());
1197   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1198 }
1199 
1200 BOOST_ASIO_SYNC_OP_VOID context::do_set_verify_callback(
1201     detail::verify_callback_base* callback, boost::system::error_code& ec)
1202 {
1203   if (SSL_CTX_get_app_data(handle_))
1204   {
1205     delete static_cast<detail::verify_callback_base*>(
1206         SSL_CTX_get_app_data(handle_));
1207   }
1208 
1209   SSL_CTX_set_app_data(handle_, callback);
1210 
1211   ::SSL_CTX_set_verify(handle_,
1212       ::SSL_CTX_get_verify_mode(handle_),
1213       &context::verify_callback_function);
1214 
1215   ec = boost::system::error_code();
1216   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1217 }
1218 
1219 int context::verify_callback_function(int preverified, X509_STORE_CTX* ctx)
1220 {
1221   if (ctx)
1222   {
1223     if (SSL* ssl = static_cast<SSL*>(
1224           ::X509_STORE_CTX_get_ex_data(
1225             ctx, ::SSL_get_ex_data_X509_STORE_CTX_idx())))
1226     {
1227       if (SSL_CTX* handle = ::SSL_get_SSL_CTX(ssl))
1228       {
1229         if (SSL_CTX_get_app_data(handle))
1230         {
1231           detail::verify_callback_base* callback =
1232             static_cast<detail::verify_callback_base*>(
1233                 SSL_CTX_get_app_data(handle));
1234 
1235           verify_context verify_ctx(ctx);
1236           return callback->call(preverified != 0, verify_ctx) ? 1 : 0;
1237         }
1238       }
1239     }
1240   }
1241 
1242   return 0;
1243 }
1244 
1245 BOOST_ASIO_SYNC_OP_VOID context::do_set_password_callback(
1246     detail::password_callback_base* callback, boost::system::error_code& ec)
1247 {
1248 #if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \
1249       && (!defined(LIBRESSL_VERSION_NUMBER) \
1250         || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)) \
1251     || defined(BOOST_ASIO_USE_WOLFSSL)
1252   void* old_callback = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
1253   ::SSL_CTX_set_default_passwd_cb_userdata(handle_, callback);
1254 #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
1255   void* old_callback = handle_->default_passwd_callback_userdata;
1256   handle_->default_passwd_callback_userdata = callback;
1257 #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
1258 
1259   if (old_callback)
1260     delete static_cast<detail::password_callback_base*>(
1261         old_callback);
1262 
1263   SSL_CTX_set_default_passwd_cb(handle_, &context::password_callback_function);
1264 
1265   ec = boost::system::error_code();
1266   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1267 }
1268 
1269 int context::password_callback_function(
1270     char* buf, int size, int purpose, void* data)
1271 {
1272   using namespace std; // For strncat and strlen.
1273 
1274   if (data)
1275   {
1276     detail::password_callback_base* callback =
1277       static_cast<detail::password_callback_base*>(data);
1278 
1279     std::string passwd = callback->call(static_cast<std::size_t>(size),
1280         purpose ? context_base::for_writing : context_base::for_reading);
1281 
1282 #if defined(BOOST_ASIO_HAS_SECURE_RTL)
1283     strcpy_s(buf, size, passwd.c_str());
1284 #else // defined(BOOST_ASIO_HAS_SECURE_RTL)
1285     *buf = '\0';
1286     if (size > 0)
1287       strncat(buf, passwd.c_str(), size - 1);
1288 #endif // defined(BOOST_ASIO_HAS_SECURE_RTL)
1289 
1290     return static_cast<int>(strlen(buf));
1291   }
1292 
1293   return 0;
1294 }
1295 
1296 BIO* context::make_buffer_bio(const const_buffer& b)
1297 {
1298   return ::BIO_new_mem_buf(
1299       const_cast<void*>(b.data()),
1300       static_cast<int>(b.size()));
1301 }
1302 
1303 boost::system::error_code context::translate_error(long error)
1304 {
1305 #if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1306   if (ERR_SYSTEM_ERROR(error))
1307   {
1308     return boost::system::error_code(
1309         static_cast<int>(ERR_GET_REASON(error)),
1310         boost::asio::error::get_system_category());
1311   }
1312 #endif // (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1313 
1314   return boost::system::error_code(static_cast<int>(error),
1315       boost::asio::error::get_ssl_category());
1316 }
1317 
1318 } // namespace ssl
1319 } // namespace asio
1320 } // namespace boost
1321 
1322 #include <boost/asio/detail/pop_options.hpp>
1323 
1324 #endif // BOOST_ASIO_SSL_IMPL_CONTEXT_IPP