Back to home page

EIC code displayed by LXR

 
 

    


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

0001 //
0002 // ssl/impl/context.ipp
0003 // ~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
0006 // Copyright (c) 2005-2023 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   case context::tlsv13:
0276     handle_ = ::SSL_CTX_new(::TLS_method());
0277     if (handle_)
0278     {
0279       SSL_CTX_set_min_proto_version(handle_, TLS1_3_VERSION);
0280       SSL_CTX_set_max_proto_version(handle_, TLS1_3_VERSION);
0281     }
0282     break;
0283   case context::tlsv13_client:
0284     handle_ = ::SSL_CTX_new(::TLS_client_method());
0285     if (handle_)
0286     {
0287       SSL_CTX_set_min_proto_version(handle_, TLS1_3_VERSION);
0288       SSL_CTX_set_max_proto_version(handle_, TLS1_3_VERSION);
0289     }
0290     break;
0291   case context::tlsv13_server:
0292     handle_ = ::SSL_CTX_new(::TLS_server_method());
0293     if (handle_)
0294     {
0295       SSL_CTX_set_min_proto_version(handle_, TLS1_3_VERSION);
0296       SSL_CTX_set_max_proto_version(handle_, TLS1_3_VERSION);
0297     }
0298     break;
0299 #else // (OPENSSL_VERSION_NUMBER >= 0x10101000L)
0300       //   && !defined(LIBRESSL_VERSION_NUMBER)
0301   case context::tlsv13:
0302   case context::tlsv13_client:
0303   case context::tlsv13_server:
0304     boost::asio::detail::throw_error(
0305         boost::asio::error::invalid_argument, "context");
0306     break;
0307 #endif // (OPENSSL_VERSION_NUMBER >= 0x10101000L)
0308        //   && !defined(LIBRESSL_VERSION_NUMBER)
0309 
0310     // Any supported SSL/TLS version.
0311   case context::sslv23:
0312     handle_ = ::SSL_CTX_new(::SSLv23_method());
0313     break;
0314   case context::sslv23_client:
0315     handle_ = ::SSL_CTX_new(::SSLv23_client_method());
0316     break;
0317   case context::sslv23_server:
0318     handle_ = ::SSL_CTX_new(::SSLv23_server_method());
0319     break;
0320 
0321     // Any supported TLS version.
0322 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
0323   case context::tls:
0324     handle_ = ::SSL_CTX_new(::TLS_method());
0325     if (handle_)
0326       SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);
0327     break;
0328   case context::tls_client:
0329     handle_ = ::SSL_CTX_new(::TLS_client_method());
0330     if (handle_)
0331       SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);
0332     break;
0333   case context::tls_server:
0334     handle_ = ::SSL_CTX_new(::TLS_server_method());
0335     if (handle_)
0336       SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);
0337     break;
0338 #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0339   case context::tls:
0340     handle_ = ::SSL_CTX_new(::SSLv23_method());
0341     if (handle_)
0342       SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
0343     break;
0344   case context::tls_client:
0345     handle_ = ::SSL_CTX_new(::SSLv23_client_method());
0346     if (handle_)
0347       SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
0348     break;
0349   case context::tls_server:
0350     handle_ = ::SSL_CTX_new(::SSLv23_server_method());
0351     if (handle_)
0352       SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
0353     break;
0354 #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0355 
0356   default:
0357     handle_ = ::SSL_CTX_new(0);
0358     break;
0359   }
0360 
0361   if (handle_ == 0)
0362   {
0363     boost::system::error_code ec = translate_error(::ERR_get_error());
0364     boost::asio::detail::throw_error(ec, "context");
0365   }
0366 
0367   set_options(no_compression);
0368 }
0369 
0370 context::context(context::native_handle_type native_handle)
0371   : handle_(native_handle)
0372 {
0373   if (!handle_)
0374   {
0375     boost::asio::detail::throw_error(
0376         boost::asio::error::invalid_argument, "context");
0377   }
0378 }
0379 
0380 context::context(context&& other)
0381 {
0382   handle_ = other.handle_;
0383   other.handle_ = 0;
0384 }
0385 
0386 context& context::operator=(context&& other)
0387 {
0388   context tmp(static_cast<context&&>(*this));
0389   handle_ = other.handle_;
0390   other.handle_ = 0;
0391   return *this;
0392 }
0393 
0394 context::~context()
0395 {
0396   if (handle_)
0397   {
0398 #if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \
0399       && (!defined(LIBRESSL_VERSION_NUMBER) \
0400         || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)) \
0401     || defined(BOOST_ASIO_USE_WOLFSSL)
0402     void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
0403 #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0404     void* cb_userdata = handle_->default_passwd_callback_userdata;
0405 #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0406     if (cb_userdata)
0407     {
0408       detail::password_callback_base* callback =
0409         static_cast<detail::password_callback_base*>(
0410             cb_userdata);
0411       delete callback;
0412 #if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \
0413       && (!defined(LIBRESSL_VERSION_NUMBER) \
0414         || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)) \
0415     || defined(BOOST_ASIO_USE_WOLFSSL)
0416       ::SSL_CTX_set_default_passwd_cb_userdata(handle_, 0);
0417 #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0418       handle_->default_passwd_callback_userdata = 0;
0419 #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0420     }
0421 
0422     if (SSL_CTX_get_app_data(handle_))
0423     {
0424       detail::verify_callback_base* callback =
0425         static_cast<detail::verify_callback_base*>(
0426             SSL_CTX_get_app_data(handle_));
0427       delete callback;
0428       SSL_CTX_set_app_data(handle_, 0);
0429     }
0430 
0431     ::SSL_CTX_free(handle_);
0432   }
0433 }
0434 
0435 context::native_handle_type context::native_handle()
0436 {
0437   return handle_;
0438 }
0439 
0440 void context::clear_options(context::options o)
0441 {
0442   boost::system::error_code ec;
0443   clear_options(o, ec);
0444   boost::asio::detail::throw_error(ec, "clear_options");
0445 }
0446 
0447 BOOST_ASIO_SYNC_OP_VOID context::clear_options(
0448     context::options o, boost::system::error_code& ec)
0449 {
0450 #if (OPENSSL_VERSION_NUMBER >= 0x009080DFL) \
0451   && (OPENSSL_VERSION_NUMBER != 0x00909000L)
0452 # if !defined(SSL_OP_NO_COMPRESSION)
0453   if ((o & context::no_compression) != 0)
0454   {
0455 # if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
0456     handle_->comp_methods = SSL_COMP_get_compression_methods();
0457 # endif // (OPENSSL_VERSION_NUMBER >= 0x00908000L)
0458     o ^= context::no_compression;
0459   }
0460 # endif // !defined(SSL_OP_NO_COMPRESSION)
0461 
0462   ::SSL_CTX_clear_options(handle_, o);
0463 
0464   ec = boost::system::error_code();
0465 #else // (OPENSSL_VERSION_NUMBER >= 0x009080DFL)
0466       //   && (OPENSSL_VERSION_NUMBER != 0x00909000L)
0467   (void)o;
0468   ec = boost::asio::error::operation_not_supported;
0469 #endif // (OPENSSL_VERSION_NUMBER >= 0x009080DFL)
0470        //   && (OPENSSL_VERSION_NUMBER != 0x00909000L)
0471   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0472 }
0473 
0474 void context::set_options(context::options o)
0475 {
0476   boost::system::error_code ec;
0477   set_options(o, ec);
0478   boost::asio::detail::throw_error(ec, "set_options");
0479 }
0480 
0481 BOOST_ASIO_SYNC_OP_VOID context::set_options(
0482     context::options o, boost::system::error_code& ec)
0483 {
0484 #if !defined(SSL_OP_NO_COMPRESSION)
0485   if ((o & context::no_compression) != 0)
0486   {
0487 #if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
0488     handle_->comp_methods =
0489       boost::asio::ssl::detail::openssl_init<>::get_null_compression_methods();
0490 #endif // (OPENSSL_VERSION_NUMBER >= 0x00908000L)
0491     o ^= context::no_compression;
0492   }
0493 #endif // !defined(SSL_OP_NO_COMPRESSION)
0494 
0495   ::SSL_CTX_set_options(handle_, o);
0496 
0497   ec = boost::system::error_code();
0498   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0499 }
0500 
0501 void context::set_verify_mode(verify_mode v)
0502 {
0503   boost::system::error_code ec;
0504   set_verify_mode(v, ec);
0505   boost::asio::detail::throw_error(ec, "set_verify_mode");
0506 }
0507 
0508 BOOST_ASIO_SYNC_OP_VOID context::set_verify_mode(
0509     verify_mode v, boost::system::error_code& ec)
0510 {
0511   ::SSL_CTX_set_verify(handle_, v, ::SSL_CTX_get_verify_callback(handle_));
0512 
0513   ec = boost::system::error_code();
0514   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0515 }
0516 
0517 void context::set_verify_depth(int depth)
0518 {
0519   boost::system::error_code ec;
0520   set_verify_depth(depth, ec);
0521   boost::asio::detail::throw_error(ec, "set_verify_depth");
0522 }
0523 
0524 BOOST_ASIO_SYNC_OP_VOID context::set_verify_depth(
0525     int depth, boost::system::error_code& ec)
0526 {
0527   ::SSL_CTX_set_verify_depth(handle_, depth);
0528 
0529   ec = boost::system::error_code();
0530   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0531 }
0532 
0533 void context::load_verify_file(const std::string& filename)
0534 {
0535   boost::system::error_code ec;
0536   load_verify_file(filename, ec);
0537   boost::asio::detail::throw_error(ec, "load_verify_file");
0538 }
0539 
0540 BOOST_ASIO_SYNC_OP_VOID context::load_verify_file(
0541     const std::string& filename, boost::system::error_code& ec)
0542 {
0543   ::ERR_clear_error();
0544 
0545   if (::SSL_CTX_load_verify_locations(handle_, filename.c_str(), 0) != 1)
0546   {
0547     ec = translate_error(::ERR_get_error());
0548     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0549   }
0550 
0551   ec = boost::system::error_code();
0552   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0553 }
0554 
0555 void context::add_certificate_authority(const const_buffer& ca)
0556 {
0557   boost::system::error_code ec;
0558   add_certificate_authority(ca, ec);
0559   boost::asio::detail::throw_error(ec, "add_certificate_authority");
0560 }
0561 
0562 BOOST_ASIO_SYNC_OP_VOID context::add_certificate_authority(
0563     const const_buffer& ca, boost::system::error_code& ec)
0564 {
0565   ::ERR_clear_error();
0566 
0567   bio_cleanup bio = { make_buffer_bio(ca) };
0568   if (bio.p)
0569   {
0570     if (X509_STORE* store = ::SSL_CTX_get_cert_store(handle_))
0571     {
0572       for (bool added = false;; added = true)
0573       {
0574         x509_cleanup cert = { ::PEM_read_bio_X509(bio.p, 0, 0, 0) };
0575         if (!cert.p)
0576         {
0577           unsigned long err = ::ERR_get_error();
0578           if (added && ERR_GET_LIB(err) == ERR_LIB_PEM
0579               && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)
0580             break;
0581 
0582           ec = translate_error(err);
0583           BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0584         }
0585 
0586         if (::X509_STORE_add_cert(store, cert.p) != 1)
0587         {
0588           ec = translate_error(::ERR_get_error());
0589           BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0590         }
0591       }
0592     }
0593   }
0594 
0595   ec = boost::system::error_code();
0596   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0597 }
0598 
0599 void context::set_default_verify_paths()
0600 {
0601   boost::system::error_code ec;
0602   set_default_verify_paths(ec);
0603   boost::asio::detail::throw_error(ec, "set_default_verify_paths");
0604 }
0605 
0606 BOOST_ASIO_SYNC_OP_VOID context::set_default_verify_paths(
0607     boost::system::error_code& ec)
0608 {
0609   ::ERR_clear_error();
0610 
0611   if (::SSL_CTX_set_default_verify_paths(handle_) != 1)
0612   {
0613     ec = translate_error(::ERR_get_error());
0614     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0615   }
0616 
0617   ec = boost::system::error_code();
0618   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0619 }
0620 
0621 void context::add_verify_path(const std::string& path)
0622 {
0623   boost::system::error_code ec;
0624   add_verify_path(path, ec);
0625   boost::asio::detail::throw_error(ec, "add_verify_path");
0626 }
0627 
0628 BOOST_ASIO_SYNC_OP_VOID context::add_verify_path(
0629     const std::string& path, boost::system::error_code& ec)
0630 {
0631   ::ERR_clear_error();
0632 
0633   if (::SSL_CTX_load_verify_locations(handle_, 0, path.c_str()) != 1)
0634   {
0635     ec = translate_error(::ERR_get_error());
0636     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0637   }
0638 
0639   ec = boost::system::error_code();
0640   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0641 }
0642 
0643 void context::use_certificate(
0644     const const_buffer& certificate, file_format format)
0645 {
0646   boost::system::error_code ec;
0647   use_certificate(certificate, format, ec);
0648   boost::asio::detail::throw_error(ec, "use_certificate");
0649 }
0650 
0651 BOOST_ASIO_SYNC_OP_VOID context::use_certificate(
0652     const const_buffer& certificate, file_format format,
0653     boost::system::error_code& ec)
0654 {
0655   ::ERR_clear_error();
0656 
0657   if (format == context_base::asn1)
0658   {
0659     if (::SSL_CTX_use_certificate_ASN1(handle_,
0660           static_cast<int>(certificate.size()),
0661           static_cast<const unsigned char*>(certificate.data())) == 1)
0662     {
0663       ec = boost::system::error_code();
0664       BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0665     }
0666   }
0667   else if (format == context_base::pem)
0668   {
0669     bio_cleanup bio = { make_buffer_bio(certificate) };
0670     if (bio.p)
0671     {
0672       x509_cleanup cert = { ::PEM_read_bio_X509(bio.p, 0, 0, 0) };
0673       if (cert.p)
0674       {
0675         if (::SSL_CTX_use_certificate(handle_, cert.p) == 1)
0676         {
0677           ec = boost::system::error_code();
0678           BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0679         }
0680       }
0681     }
0682   }
0683   else
0684   {
0685     ec = boost::asio::error::invalid_argument;
0686     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0687   }
0688 
0689   ec = translate_error(::ERR_get_error());
0690   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0691 }
0692 
0693 void context::use_certificate_file(
0694     const std::string& filename, file_format format)
0695 {
0696   boost::system::error_code ec;
0697   use_certificate_file(filename, format, ec);
0698   boost::asio::detail::throw_error(ec, "use_certificate_file");
0699 }
0700 
0701 BOOST_ASIO_SYNC_OP_VOID context::use_certificate_file(
0702     const std::string& filename, file_format format,
0703     boost::system::error_code& ec)
0704 {
0705   int file_type;
0706   switch (format)
0707   {
0708   case context_base::asn1:
0709     file_type = SSL_FILETYPE_ASN1;
0710     break;
0711   case context_base::pem:
0712     file_type = SSL_FILETYPE_PEM;
0713     break;
0714   default:
0715     {
0716       ec = boost::asio::error::invalid_argument;
0717       BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0718     }
0719   }
0720 
0721   ::ERR_clear_error();
0722 
0723   if (::SSL_CTX_use_certificate_file(handle_, filename.c_str(), file_type) != 1)
0724   {
0725     ec = translate_error(::ERR_get_error());
0726     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0727   }
0728 
0729   ec = boost::system::error_code();
0730   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0731 }
0732 
0733 void context::use_certificate_chain(const const_buffer& chain)
0734 {
0735   boost::system::error_code ec;
0736   use_certificate_chain(chain, ec);
0737   boost::asio::detail::throw_error(ec, "use_certificate_chain");
0738 }
0739 
0740 BOOST_ASIO_SYNC_OP_VOID context::use_certificate_chain(
0741     const const_buffer& chain, boost::system::error_code& ec)
0742 {
0743   ::ERR_clear_error();
0744 
0745   bio_cleanup bio = { make_buffer_bio(chain) };
0746   if (bio.p)
0747   {
0748 #if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \
0749       && (!defined(LIBRESSL_VERSION_NUMBER) \
0750         || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)) \
0751     || defined(BOOST_ASIO_USE_WOLFSSL)
0752     pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_);
0753     void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
0754 #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0755     pem_password_cb* callback = handle_->default_passwd_callback;
0756     void* cb_userdata = handle_->default_passwd_callback_userdata;
0757 #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0758     x509_cleanup cert = {
0759       ::PEM_read_bio_X509_AUX(bio.p, 0,
0760           callback,
0761           cb_userdata) };
0762     if (!cert.p)
0763     {
0764       ec = translate_error(ERR_R_PEM_LIB);
0765       BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0766     }
0767 
0768     int result = ::SSL_CTX_use_certificate(handle_, cert.p);
0769     if (result == 0 || ::ERR_peek_error() != 0)
0770     {
0771       ec = translate_error(::ERR_get_error());
0772       BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0773     }
0774 
0775 #if ((OPENSSL_VERSION_NUMBER >= 0x10002000L) \
0776       && (!defined(LIBRESSL_VERSION_NUMBER) \
0777         || LIBRESSL_VERSION_NUMBER >= 0x2090100fL)) \
0778     || defined(BOOST_ASIO_USE_WOLFSSL)
0779     ::SSL_CTX_clear_chain_certs(handle_);
0780 #else
0781     if (handle_->extra_certs)
0782     {
0783       ::sk_X509_pop_free(handle_->extra_certs, X509_free);
0784       handle_->extra_certs = 0;
0785     }
0786 #endif // (OPENSSL_VERSION_NUMBER >= 0x10002000L)
0787 
0788     while (X509* cacert = ::PEM_read_bio_X509(bio.p, 0,
0789           callback,
0790           cb_userdata))
0791     {
0792       if (!::SSL_CTX_add_extra_chain_cert(handle_, cacert))
0793       {
0794         ec = translate_error(::ERR_get_error());
0795         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0796       }
0797     }
0798   
0799     result = ::ERR_peek_last_error();
0800     if ((ERR_GET_LIB(result) == ERR_LIB_PEM)
0801         && (ERR_GET_REASON(result) == PEM_R_NO_START_LINE))
0802     {
0803       ::ERR_clear_error();
0804       ec = boost::system::error_code();
0805       BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0806     }
0807   }
0808 
0809   ec = translate_error(::ERR_get_error());
0810   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0811 }
0812 
0813 void context::use_certificate_chain_file(const std::string& filename)
0814 {
0815   boost::system::error_code ec;
0816   use_certificate_chain_file(filename, ec);
0817   boost::asio::detail::throw_error(ec, "use_certificate_chain_file");
0818 }
0819 
0820 BOOST_ASIO_SYNC_OP_VOID context::use_certificate_chain_file(
0821     const std::string& filename, boost::system::error_code& ec)
0822 {
0823   ::ERR_clear_error();
0824 
0825   if (::SSL_CTX_use_certificate_chain_file(handle_, filename.c_str()) != 1)
0826   {
0827     ec = translate_error(::ERR_get_error());
0828     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0829   }
0830 
0831   ec = boost::system::error_code();
0832   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0833 }
0834 
0835 void context::use_private_key(
0836     const const_buffer& private_key, context::file_format format)
0837 {
0838   boost::system::error_code ec;
0839   use_private_key(private_key, format, ec);
0840   boost::asio::detail::throw_error(ec, "use_private_key");
0841 }
0842 
0843 BOOST_ASIO_SYNC_OP_VOID context::use_private_key(
0844     const const_buffer& private_key, context::file_format format,
0845     boost::system::error_code& ec)
0846 {
0847   ::ERR_clear_error();
0848 
0849 #if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \
0850       && (!defined(LIBRESSL_VERSION_NUMBER) \
0851         || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)) \
0852     || defined(BOOST_ASIO_USE_WOLFSSL)
0853     pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_);
0854     void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
0855 #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0856     pem_password_cb* callback = handle_->default_passwd_callback;
0857     void* cb_userdata = handle_->default_passwd_callback_userdata;
0858 #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0859 
0860   bio_cleanup bio = { make_buffer_bio(private_key) };
0861   if (bio.p)
0862   {
0863     evp_pkey_cleanup evp_private_key = { 0 };
0864     switch (format)
0865     {
0866     case context_base::asn1:
0867       evp_private_key.p = ::d2i_PrivateKey_bio(bio.p, 0);
0868       break;
0869     case context_base::pem:
0870       evp_private_key.p = ::PEM_read_bio_PrivateKey(
0871           bio.p, 0, callback,
0872           cb_userdata);
0873       break;
0874     default:
0875       {
0876         ec = boost::asio::error::invalid_argument;
0877         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0878       }
0879     }
0880 
0881     if (evp_private_key.p)
0882     {
0883       if (::SSL_CTX_use_PrivateKey(handle_, evp_private_key.p) == 1)
0884       {
0885         ec = boost::system::error_code();
0886         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0887       }
0888     }
0889   }
0890 
0891   ec = translate_error(::ERR_get_error());
0892   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0893 }
0894 
0895 void context::use_private_key_file(
0896     const std::string& filename, context::file_format format)
0897 {
0898   boost::system::error_code ec;
0899   use_private_key_file(filename, format, ec);
0900   boost::asio::detail::throw_error(ec, "use_private_key_file");
0901 }
0902 
0903 void context::use_rsa_private_key(
0904     const const_buffer& private_key, context::file_format format)
0905 {
0906   boost::system::error_code ec;
0907   use_rsa_private_key(private_key, format, ec);
0908   boost::asio::detail::throw_error(ec, "use_rsa_private_key");
0909 }
0910 
0911 BOOST_ASIO_SYNC_OP_VOID context::use_rsa_private_key(
0912     const const_buffer& private_key, context::file_format format,
0913     boost::system::error_code& ec)
0914 {
0915   ::ERR_clear_error();
0916 
0917 #if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \
0918       && (!defined(LIBRESSL_VERSION_NUMBER) \
0919         || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)) \
0920     || defined(BOOST_ASIO_USE_WOLFSSL)
0921   pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_);
0922   void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
0923 #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0924   pem_password_cb* callback = handle_->default_passwd_callback;
0925   void* cb_userdata = handle_->default_passwd_callback_userdata;
0926 #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
0927 
0928   bio_cleanup bio = { make_buffer_bio(private_key) };
0929   if (bio.p)
0930   {
0931 #if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
0932     evp_pkey_cleanup evp_private_key = { 0 };
0933     switch (format)
0934     {
0935     case context_base::asn1:
0936       evp_private_key.p = ::d2i_PrivateKey_bio(bio.p, 0);
0937       break;
0938     case context_base::pem:
0939       evp_private_key.p = ::PEM_read_bio_PrivateKey(
0940           bio.p, 0, callback,
0941           cb_userdata);
0942       break;
0943     default:
0944       {
0945         ec = boost::asio::error::invalid_argument;
0946         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0947       }
0948     }
0949 
0950     if (evp_private_key.p)
0951     {
0952       if (::EVP_PKEY_is_a(evp_private_key.p, "RSA") == 0)
0953       {
0954         ec = translate_error(
0955             ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_AN_RSA_KEY));
0956         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0957       }
0958 
0959       if (::SSL_CTX_use_PrivateKey(handle_, evp_private_key.p) == 1)
0960       {
0961         ec = boost::system::error_code();
0962         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0963       }
0964     }
0965 #else // (OPENSSL_VERSION_NUMBER >= 0x30000000L)
0966     rsa_cleanup rsa_private_key = { 0 };
0967     switch (format)
0968     {
0969     case context_base::asn1:
0970       rsa_private_key.p = ::d2i_RSAPrivateKey_bio(bio.p, 0);
0971       break;
0972     case context_base::pem:
0973       rsa_private_key.p = ::PEM_read_bio_RSAPrivateKey(
0974           bio.p, 0, callback,
0975           cb_userdata);
0976       break;
0977     default:
0978       {
0979         ec = boost::asio::error::invalid_argument;
0980         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0981       }
0982     }
0983 
0984     if (rsa_private_key.p)
0985     {
0986       if (::SSL_CTX_use_RSAPrivateKey(handle_, rsa_private_key.p) == 1)
0987       {
0988         ec = boost::system::error_code();
0989         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0990       }
0991     }
0992 #endif // (OPENSSL_VERSION_NUMBER >= 0x30000000L)
0993   }
0994 
0995   ec = translate_error(::ERR_get_error());
0996   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0997 }
0998 
0999 BOOST_ASIO_SYNC_OP_VOID context::use_private_key_file(
1000     const std::string& filename, context::file_format format,
1001     boost::system::error_code& ec)
1002 {
1003   int file_type;
1004   switch (format)
1005   {
1006   case context_base::asn1:
1007     file_type = SSL_FILETYPE_ASN1;
1008     break;
1009   case context_base::pem:
1010     file_type = SSL_FILETYPE_PEM;
1011     break;
1012   default:
1013     {
1014       ec = boost::asio::error::invalid_argument;
1015       BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1016     }
1017   }
1018 
1019   ::ERR_clear_error();
1020 
1021   if (::SSL_CTX_use_PrivateKey_file(handle_, filename.c_str(), file_type) != 1)
1022   {
1023     ec = translate_error(::ERR_get_error());
1024     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1025   }
1026 
1027   ec = boost::system::error_code();
1028   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1029 }
1030 
1031 void context::use_rsa_private_key_file(
1032     const std::string& filename, context::file_format format)
1033 {
1034   boost::system::error_code ec;
1035   use_rsa_private_key_file(filename, format, ec);
1036   boost::asio::detail::throw_error(ec, "use_rsa_private_key_file");
1037 }
1038 
1039 BOOST_ASIO_SYNC_OP_VOID context::use_rsa_private_key_file(
1040     const std::string& filename, context::file_format format,
1041     boost::system::error_code& ec)
1042 {
1043 #if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1044   ::ERR_clear_error();
1045 
1046   pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_);
1047   void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
1048 
1049   bio_cleanup bio = { ::BIO_new_file(filename.c_str(), "r") };
1050   if (bio.p)
1051   {
1052     evp_pkey_cleanup evp_private_key = { 0 };
1053     switch (format)
1054     {
1055     case context_base::asn1:
1056       evp_private_key.p = ::d2i_PrivateKey_bio(bio.p, 0);
1057       break;
1058     case context_base::pem:
1059       evp_private_key.p = ::PEM_read_bio_PrivateKey(
1060           bio.p, 0, callback,
1061           cb_userdata);
1062       break;
1063     default:
1064       {
1065         ec = boost::asio::error::invalid_argument;
1066         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1067       }
1068     }
1069 
1070     if (evp_private_key.p)
1071     {
1072       if (::EVP_PKEY_is_a(evp_private_key.p, "RSA") == 0)
1073       {
1074         ec = translate_error(
1075             ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_AN_RSA_KEY));
1076         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1077       }
1078 
1079       if (::SSL_CTX_use_PrivateKey(handle_, evp_private_key.p) == 1)
1080       {
1081         ec = boost::system::error_code();
1082         BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1083       }
1084     }
1085   }
1086 
1087   ec = translate_error(::ERR_get_error());
1088   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1089 #else // (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1090   int file_type;
1091   switch (format)
1092   {
1093   case context_base::asn1:
1094     file_type = SSL_FILETYPE_ASN1;
1095     break;
1096   case context_base::pem:
1097     file_type = SSL_FILETYPE_PEM;
1098     break;
1099   default:
1100     {
1101       ec = boost::asio::error::invalid_argument;
1102       BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1103     }
1104   }
1105 
1106   ::ERR_clear_error();
1107 
1108   if (::SSL_CTX_use_RSAPrivateKey_file(
1109         handle_, filename.c_str(), file_type) != 1)
1110   {
1111     ec = translate_error(::ERR_get_error());
1112     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1113   }
1114 
1115   ec = boost::system::error_code();
1116   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1117 #endif // (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1118 }
1119 
1120 void context::use_tmp_dh(const const_buffer& dh)
1121 {
1122   boost::system::error_code ec;
1123   use_tmp_dh(dh, ec);
1124   boost::asio::detail::throw_error(ec, "use_tmp_dh");
1125 }
1126 
1127 BOOST_ASIO_SYNC_OP_VOID context::use_tmp_dh(
1128     const const_buffer& dh, boost::system::error_code& ec)
1129 {
1130   ::ERR_clear_error();
1131 
1132   bio_cleanup bio = { make_buffer_bio(dh) };
1133   if (bio.p)
1134   {
1135     return do_use_tmp_dh(bio.p, ec);
1136   }
1137 
1138   ec = translate_error(::ERR_get_error());
1139   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1140 }
1141 
1142 void context::use_tmp_dh_file(const std::string& filename)
1143 {
1144   boost::system::error_code ec;
1145   use_tmp_dh_file(filename, ec);
1146   boost::asio::detail::throw_error(ec, "use_tmp_dh_file");
1147 }
1148 
1149 BOOST_ASIO_SYNC_OP_VOID context::use_tmp_dh_file(
1150     const std::string& filename, boost::system::error_code& ec)
1151 {
1152   ::ERR_clear_error();
1153 
1154   bio_cleanup bio = { ::BIO_new_file(filename.c_str(), "r") };
1155   if (bio.p)
1156   {
1157     return do_use_tmp_dh(bio.p, ec);
1158   }
1159 
1160   ec = translate_error(::ERR_get_error());
1161   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1162 }
1163 
1164 BOOST_ASIO_SYNC_OP_VOID context::do_use_tmp_dh(
1165     BIO* bio, boost::system::error_code& ec)
1166 {
1167   ::ERR_clear_error();
1168 
1169 #if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1170   EVP_PKEY* p = ::PEM_read_bio_Parameters(bio, 0);
1171   if (p)
1172   {
1173     if (::SSL_CTX_set0_tmp_dh_pkey(handle_, p) == 1)
1174     {
1175       ec = boost::system::error_code();
1176       BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1177     }
1178     else
1179       ::EVP_PKEY_free(p);
1180   }
1181 #else // (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1182   dh_cleanup dh = { ::PEM_read_bio_DHparams(bio, 0, 0, 0) };
1183   if (dh.p)
1184   {
1185     if (::SSL_CTX_set_tmp_dh(handle_, dh.p) == 1)
1186     {
1187       ec = boost::system::error_code();
1188       BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1189     }
1190   }
1191 #endif // (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1192 
1193   ec = translate_error(::ERR_get_error());
1194   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1195 }
1196 
1197 BOOST_ASIO_SYNC_OP_VOID context::do_set_verify_callback(
1198     detail::verify_callback_base* callback, boost::system::error_code& ec)
1199 {
1200   if (SSL_CTX_get_app_data(handle_))
1201   {
1202     delete static_cast<detail::verify_callback_base*>(
1203         SSL_CTX_get_app_data(handle_));
1204   }
1205 
1206   SSL_CTX_set_app_data(handle_, callback);
1207 
1208   ::SSL_CTX_set_verify(handle_,
1209       ::SSL_CTX_get_verify_mode(handle_),
1210       &context::verify_callback_function);
1211 
1212   ec = boost::system::error_code();
1213   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1214 }
1215 
1216 int context::verify_callback_function(int preverified, X509_STORE_CTX* ctx)
1217 {
1218   if (ctx)
1219   {
1220     if (SSL* ssl = static_cast<SSL*>(
1221           ::X509_STORE_CTX_get_ex_data(
1222             ctx, ::SSL_get_ex_data_X509_STORE_CTX_idx())))
1223     {
1224       if (SSL_CTX* handle = ::SSL_get_SSL_CTX(ssl))
1225       {
1226         if (SSL_CTX_get_app_data(handle))
1227         {
1228           detail::verify_callback_base* callback =
1229             static_cast<detail::verify_callback_base*>(
1230                 SSL_CTX_get_app_data(handle));
1231 
1232           verify_context verify_ctx(ctx);
1233           return callback->call(preverified != 0, verify_ctx) ? 1 : 0;
1234         }
1235       }
1236     }
1237   }
1238 
1239   return 0;
1240 }
1241 
1242 BOOST_ASIO_SYNC_OP_VOID context::do_set_password_callback(
1243     detail::password_callback_base* callback, boost::system::error_code& ec)
1244 {
1245 #if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \
1246       && (!defined(LIBRESSL_VERSION_NUMBER) \
1247         || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)) \
1248     || defined(BOOST_ASIO_USE_WOLFSSL)
1249   void* old_callback = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
1250   ::SSL_CTX_set_default_passwd_cb_userdata(handle_, callback);
1251 #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
1252   void* old_callback = handle_->default_passwd_callback_userdata;
1253   handle_->default_passwd_callback_userdata = callback;
1254 #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
1255 
1256   if (old_callback)
1257     delete static_cast<detail::password_callback_base*>(
1258         old_callback);
1259 
1260   SSL_CTX_set_default_passwd_cb(handle_, &context::password_callback_function);
1261 
1262   ec = boost::system::error_code();
1263   BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
1264 }
1265 
1266 int context::password_callback_function(
1267     char* buf, int size, int purpose, void* data)
1268 {
1269   using namespace std; // For strncat and strlen.
1270 
1271   if (data)
1272   {
1273     detail::password_callback_base* callback =
1274       static_cast<detail::password_callback_base*>(data);
1275 
1276     std::string passwd = callback->call(static_cast<std::size_t>(size),
1277         purpose ? context_base::for_writing : context_base::for_reading);
1278 
1279 #if defined(BOOST_ASIO_HAS_SECURE_RTL)
1280     strcpy_s(buf, size, passwd.c_str());
1281 #else // defined(BOOST_ASIO_HAS_SECURE_RTL)
1282     *buf = '\0';
1283     if (size > 0)
1284       strncat(buf, passwd.c_str(), size - 1);
1285 #endif // defined(BOOST_ASIO_HAS_SECURE_RTL)
1286 
1287     return static_cast<int>(strlen(buf));
1288   }
1289 
1290   return 0;
1291 }
1292 
1293 BIO* context::make_buffer_bio(const const_buffer& b)
1294 {
1295   return ::BIO_new_mem_buf(
1296       const_cast<void*>(b.data()),
1297       static_cast<int>(b.size()));
1298 }
1299 
1300 boost::system::error_code context::translate_error(long error)
1301 {
1302 #if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1303   if (ERR_SYSTEM_ERROR(error))
1304   {
1305     return boost::system::error_code(
1306         static_cast<int>(ERR_GET_REASON(error)),
1307         boost::asio::error::get_system_category());
1308   }
1309 #endif // (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1310 
1311   return boost::system::error_code(static_cast<int>(error),
1312       boost::asio::error::get_ssl_category());
1313 }
1314 
1315 } // namespace ssl
1316 } // namespace asio
1317 } // namespace boost
1318 
1319 #include <boost/asio/detail/pop_options.hpp>
1320 
1321 #endif // BOOST_ASIO_SSL_IMPL_CONTEXT_IPP