Chris@16: // Chris@16: // ssl/impl/context.ipp Chris@16: // ~~~~~~~~~~~~~~~~~~~~ Chris@16: // Chris@16: // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com Chris@101: // Copyright (c) 2005-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: Chris@16: #ifndef BOOST_ASIO_SSL_IMPL_CONTEXT_IPP Chris@16: #define BOOST_ASIO_SSL_IMPL_CONTEXT_IPP Chris@16: Chris@16: #if defined(_MSC_VER) && (_MSC_VER >= 1200) Chris@16: # pragma once Chris@16: #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) Chris@16: Chris@16: #include Chris@16: Chris@16: #if !defined(BOOST_ASIO_ENABLE_OLD_SSL) Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: #endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: namespace asio { Chris@16: namespace ssl { Chris@16: Chris@16: #if !defined(BOOST_ASIO_ENABLE_OLD_SSL) Chris@16: Chris@16: struct context::bio_cleanup Chris@16: { Chris@16: BIO* p; Chris@16: ~bio_cleanup() { if (p) ::BIO_free(p); } Chris@16: }; Chris@16: Chris@16: struct context::x509_cleanup Chris@16: { Chris@16: X509* p; Chris@16: ~x509_cleanup() { if (p) ::X509_free(p); } Chris@16: }; Chris@16: Chris@16: struct context::evp_pkey_cleanup Chris@16: { Chris@16: EVP_PKEY* p; Chris@16: ~evp_pkey_cleanup() { if (p) ::EVP_PKEY_free(p); } Chris@16: }; Chris@16: Chris@16: struct context::rsa_cleanup Chris@16: { Chris@16: RSA* p; Chris@16: ~rsa_cleanup() { if (p) ::RSA_free(p); } Chris@16: }; Chris@16: Chris@16: struct context::dh_cleanup Chris@16: { Chris@16: DH* p; Chris@16: ~dh_cleanup() { if (p) ::DH_free(p); } Chris@16: }; Chris@16: Chris@16: context::context(context::method m) Chris@16: : handle_(0) Chris@16: { Chris@101: ::ERR_clear_error(); Chris@101: Chris@16: switch (m) Chris@16: { Chris@16: #if defined(OPENSSL_NO_SSL2) Chris@16: case context::sslv2: Chris@16: case context::sslv2_client: Chris@16: case context::sslv2_server: Chris@16: boost::asio::detail::throw_error( Chris@16: boost::asio::error::invalid_argument, "context"); Chris@16: break; Chris@16: #else // defined(OPENSSL_NO_SSL2) Chris@16: case context::sslv2: Chris@16: handle_ = ::SSL_CTX_new(::SSLv2_method()); Chris@16: break; Chris@16: case context::sslv2_client: Chris@16: handle_ = ::SSL_CTX_new(::SSLv2_client_method()); Chris@16: break; Chris@16: case context::sslv2_server: Chris@16: handle_ = ::SSL_CTX_new(::SSLv2_server_method()); Chris@16: break; Chris@16: #endif // defined(OPENSSL_NO_SSL2) Chris@16: case context::sslv3: Chris@16: handle_ = ::SSL_CTX_new(::SSLv3_method()); Chris@16: break; Chris@16: case context::sslv3_client: Chris@16: handle_ = ::SSL_CTX_new(::SSLv3_client_method()); Chris@16: break; Chris@16: case context::sslv3_server: Chris@16: handle_ = ::SSL_CTX_new(::SSLv3_server_method()); Chris@16: break; Chris@16: case context::tlsv1: Chris@16: handle_ = ::SSL_CTX_new(::TLSv1_method()); Chris@16: break; Chris@16: case context::tlsv1_client: Chris@16: handle_ = ::SSL_CTX_new(::TLSv1_client_method()); Chris@16: break; Chris@16: case context::tlsv1_server: Chris@16: handle_ = ::SSL_CTX_new(::TLSv1_server_method()); Chris@16: break; Chris@16: case context::sslv23: Chris@16: handle_ = ::SSL_CTX_new(::SSLv23_method()); Chris@16: break; Chris@16: case context::sslv23_client: Chris@16: handle_ = ::SSL_CTX_new(::SSLv23_client_method()); Chris@16: break; Chris@16: case context::sslv23_server: Chris@16: handle_ = ::SSL_CTX_new(::SSLv23_server_method()); Chris@16: break; Chris@16: #if defined(SSL_TXT_TLSV1_1) Chris@16: case context::tlsv11: Chris@16: handle_ = ::SSL_CTX_new(::TLSv1_1_method()); Chris@16: break; Chris@16: case context::tlsv11_client: Chris@16: handle_ = ::SSL_CTX_new(::TLSv1_1_client_method()); Chris@16: break; Chris@16: case context::tlsv11_server: Chris@16: handle_ = ::SSL_CTX_new(::TLSv1_1_server_method()); Chris@16: break; Chris@16: #else // defined(SSL_TXT_TLSV1_1) Chris@16: case context::tlsv11: Chris@16: case context::tlsv11_client: Chris@16: case context::tlsv11_server: Chris@16: boost::asio::detail::throw_error( Chris@16: boost::asio::error::invalid_argument, "context"); Chris@16: break; Chris@16: #endif // defined(SSL_TXT_TLSV1_1) Chris@16: #if defined(SSL_TXT_TLSV1_2) Chris@16: case context::tlsv12: Chris@16: handle_ = ::SSL_CTX_new(::TLSv1_2_method()); Chris@16: break; Chris@16: case context::tlsv12_client: Chris@16: handle_ = ::SSL_CTX_new(::TLSv1_2_client_method()); Chris@16: break; Chris@16: case context::tlsv12_server: Chris@16: handle_ = ::SSL_CTX_new(::TLSv1_2_server_method()); Chris@16: break; Chris@16: #else // defined(SSL_TXT_TLSV1_2) Chris@16: case context::tlsv12: Chris@16: case context::tlsv12_client: Chris@16: case context::tlsv12_server: Chris@16: boost::asio::detail::throw_error( Chris@16: boost::asio::error::invalid_argument, "context"); Chris@16: break; Chris@16: #endif // defined(SSL_TXT_TLSV1_2) Chris@16: default: Chris@16: handle_ = ::SSL_CTX_new(0); Chris@16: break; Chris@16: } Chris@16: Chris@16: if (handle_ == 0) Chris@16: { Chris@16: boost::system::error_code ec( Chris@16: static_cast(::ERR_get_error()), Chris@16: boost::asio::error::get_ssl_category()); Chris@16: boost::asio::detail::throw_error(ec, "context"); Chris@16: } Chris@16: Chris@16: set_options(no_compression); Chris@16: } Chris@16: Chris@16: context::context(boost::asio::io_service&, context::method m) Chris@16: : handle_(0) Chris@16: { Chris@16: context tmp(m); Chris@16: handle_ = tmp.handle_; Chris@16: tmp.handle_ = 0; Chris@16: } Chris@16: Chris@16: #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) Chris@16: context::context(context&& other) Chris@16: { Chris@16: handle_ = other.handle_; Chris@16: other.handle_ = 0; Chris@16: } Chris@16: Chris@16: context& context::operator=(context&& other) Chris@16: { Chris@16: context tmp(BOOST_ASIO_MOVE_CAST(context)(*this)); Chris@16: handle_ = other.handle_; Chris@16: other.handle_ = 0; Chris@16: return *this; Chris@16: } Chris@16: #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) Chris@16: Chris@16: context::~context() Chris@16: { Chris@16: if (handle_) Chris@16: { Chris@16: if (handle_->default_passwd_callback_userdata) Chris@16: { Chris@16: detail::password_callback_base* callback = Chris@16: static_cast( Chris@16: handle_->default_passwd_callback_userdata); Chris@16: delete callback; Chris@16: handle_->default_passwd_callback_userdata = 0; Chris@16: } Chris@16: Chris@16: if (SSL_CTX_get_app_data(handle_)) Chris@16: { Chris@16: detail::verify_callback_base* callback = Chris@16: static_cast( Chris@16: SSL_CTX_get_app_data(handle_)); Chris@16: delete callback; Chris@16: SSL_CTX_set_app_data(handle_, 0); Chris@16: } Chris@16: Chris@16: ::SSL_CTX_free(handle_); Chris@16: } Chris@16: } Chris@16: Chris@16: context::native_handle_type context::native_handle() Chris@16: { Chris@16: return handle_; Chris@16: } Chris@16: Chris@16: context::impl_type context::impl() Chris@16: { Chris@16: return handle_; Chris@16: } Chris@16: Chris@16: void context::clear_options(context::options o) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: clear_options(o, ec); Chris@16: boost::asio::detail::throw_error(ec, "clear_options"); Chris@16: } Chris@16: Chris@16: boost::system::error_code context::clear_options( Chris@16: context::options o, boost::system::error_code& ec) Chris@16: { Chris@16: #if (OPENSSL_VERSION_NUMBER >= 0x009080DFL) \ Chris@16: && (OPENSSL_VERSION_NUMBER != 0x00909000L) Chris@16: # if !defined(SSL_OP_NO_COMPRESSION) Chris@16: if ((o & context::no_compression) != 0) Chris@16: { Chris@16: # if (OPENSSL_VERSION_NUMBER >= 0x00908000L) Chris@16: handle_->comp_methods = SSL_COMP_get_compression_methods(); Chris@16: # endif // (OPENSSL_VERSION_NUMBER >= 0x00908000L) Chris@16: o ^= context::no_compression; Chris@16: } Chris@16: # endif // !defined(SSL_OP_NO_COMPRESSION) Chris@16: Chris@16: ::SSL_CTX_clear_options(handle_, o); Chris@16: Chris@16: ec = boost::system::error_code(); Chris@16: #else // (OPENSSL_VERSION_NUMBER >= 0x009080DFL) Chris@16: // && (OPENSSL_VERSION_NUMBER != 0x00909000L) Chris@16: (void)o; Chris@16: ec = boost::asio::error::operation_not_supported; Chris@16: #endif // (OPENSSL_VERSION_NUMBER >= 0x009080DFL) Chris@16: // && (OPENSSL_VERSION_NUMBER != 0x00909000L) Chris@16: return ec; Chris@16: } Chris@16: Chris@16: void context::set_options(context::options o) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: set_options(o, ec); Chris@16: boost::asio::detail::throw_error(ec, "set_options"); Chris@16: } Chris@16: Chris@16: boost::system::error_code context::set_options( Chris@16: context::options o, boost::system::error_code& ec) Chris@16: { Chris@16: #if !defined(SSL_OP_NO_COMPRESSION) Chris@16: if ((o & context::no_compression) != 0) Chris@16: { Chris@16: #if (OPENSSL_VERSION_NUMBER >= 0x00908000L) Chris@16: handle_->comp_methods = Chris@16: boost::asio::ssl::detail::openssl_init<>::get_null_compression_methods(); Chris@16: #endif // (OPENSSL_VERSION_NUMBER >= 0x00908000L) Chris@16: o ^= context::no_compression; Chris@16: } Chris@16: #endif // !defined(SSL_OP_NO_COMPRESSION) Chris@16: Chris@16: ::SSL_CTX_set_options(handle_, o); Chris@16: Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: void context::set_verify_mode(verify_mode v) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: set_verify_mode(v, ec); Chris@16: boost::asio::detail::throw_error(ec, "set_verify_mode"); Chris@16: } Chris@16: Chris@16: boost::system::error_code context::set_verify_mode( Chris@16: verify_mode v, boost::system::error_code& ec) Chris@16: { Chris@16: ::SSL_CTX_set_verify(handle_, v, ::SSL_CTX_get_verify_callback(handle_)); Chris@16: Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: void context::set_verify_depth(int depth) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: set_verify_depth(depth, ec); Chris@16: boost::asio::detail::throw_error(ec, "set_verify_depth"); Chris@16: } Chris@16: Chris@16: boost::system::error_code context::set_verify_depth( Chris@16: int depth, boost::system::error_code& ec) Chris@16: { Chris@16: ::SSL_CTX_set_verify_depth(handle_, depth); Chris@16: Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: void context::load_verify_file(const std::string& filename) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: load_verify_file(filename, ec); Chris@16: boost::asio::detail::throw_error(ec, "load_verify_file"); Chris@16: } Chris@16: Chris@16: boost::system::error_code context::load_verify_file( Chris@16: const std::string& filename, boost::system::error_code& ec) Chris@16: { Chris@101: ::ERR_clear_error(); Chris@101: Chris@16: if (::SSL_CTX_load_verify_locations(handle_, filename.c_str(), 0) != 1) Chris@16: { Chris@16: ec = boost::system::error_code( Chris@16: static_cast(::ERR_get_error()), Chris@16: boost::asio::error::get_ssl_category()); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: void context::add_certificate_authority(const const_buffer& ca) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: add_certificate_authority(ca, ec); Chris@16: boost::asio::detail::throw_error(ec, "add_certificate_authority"); Chris@16: } Chris@16: Chris@16: boost::system::error_code context::add_certificate_authority( Chris@16: const const_buffer& ca, boost::system::error_code& ec) Chris@16: { Chris@16: ::ERR_clear_error(); Chris@16: Chris@16: bio_cleanup bio = { make_buffer_bio(ca) }; Chris@16: if (bio.p) Chris@16: { Chris@16: x509_cleanup cert = { ::PEM_read_bio_X509(bio.p, 0, 0, 0) }; Chris@16: if (cert.p) Chris@16: { Chris@16: if (X509_STORE* store = ::SSL_CTX_get_cert_store(handle_)) Chris@16: { Chris@16: if (::X509_STORE_add_cert(store, cert.p) == 1) Chris@16: { Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: ec = boost::system::error_code( Chris@16: static_cast(::ERR_get_error()), Chris@16: boost::asio::error::get_ssl_category()); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: void context::set_default_verify_paths() Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: set_default_verify_paths(ec); Chris@16: boost::asio::detail::throw_error(ec, "set_default_verify_paths"); Chris@16: } Chris@16: Chris@16: boost::system::error_code context::set_default_verify_paths( Chris@16: boost::system::error_code& ec) Chris@16: { Chris@101: ::ERR_clear_error(); Chris@101: Chris@16: if (::SSL_CTX_set_default_verify_paths(handle_) != 1) Chris@16: { Chris@16: ec = boost::system::error_code( Chris@16: static_cast(::ERR_get_error()), Chris@16: boost::asio::error::get_ssl_category()); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: void context::add_verify_path(const std::string& path) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: add_verify_path(path, ec); Chris@16: boost::asio::detail::throw_error(ec, "add_verify_path"); Chris@16: } Chris@16: Chris@16: boost::system::error_code context::add_verify_path( Chris@16: const std::string& path, boost::system::error_code& ec) Chris@16: { Chris@101: ::ERR_clear_error(); Chris@101: Chris@16: if (::SSL_CTX_load_verify_locations(handle_, 0, path.c_str()) != 1) Chris@16: { Chris@16: ec = boost::system::error_code( Chris@16: static_cast(::ERR_get_error()), Chris@16: boost::asio::error::get_ssl_category()); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: void context::use_certificate( Chris@16: const const_buffer& certificate, file_format format) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: use_certificate(certificate, format, ec); Chris@16: boost::asio::detail::throw_error(ec, "use_certificate"); Chris@16: } Chris@16: Chris@16: boost::system::error_code context::use_certificate( Chris@16: const const_buffer& certificate, file_format format, Chris@16: boost::system::error_code& ec) Chris@16: { Chris@16: ::ERR_clear_error(); Chris@16: Chris@16: if (format == context_base::asn1) Chris@16: { Chris@16: if (::SSL_CTX_use_certificate_ASN1(handle_, Chris@16: static_cast(buffer_size(certificate)), Chris@16: buffer_cast(certificate)) == 1) Chris@16: { Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: } Chris@16: else if (format == context_base::pem) Chris@16: { Chris@16: bio_cleanup bio = { make_buffer_bio(certificate) }; Chris@16: if (bio.p) Chris@16: { Chris@16: x509_cleanup cert = { ::PEM_read_bio_X509(bio.p, 0, 0, 0) }; Chris@16: if (cert.p) Chris@16: { Chris@16: if (::SSL_CTX_use_certificate(handle_, cert.p) == 1) Chris@16: { Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: } Chris@16: } Chris@16: } Chris@16: else Chris@16: { Chris@16: ec = boost::asio::error::invalid_argument; Chris@16: return ec; Chris@16: } Chris@16: Chris@16: ec = boost::system::error_code( Chris@16: static_cast(::ERR_get_error()), Chris@16: boost::asio::error::get_ssl_category()); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: void context::use_certificate_file( Chris@16: const std::string& filename, file_format format) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: use_certificate_file(filename, format, ec); Chris@16: boost::asio::detail::throw_error(ec, "use_certificate_file"); Chris@16: } Chris@16: Chris@16: boost::system::error_code context::use_certificate_file( Chris@16: const std::string& filename, file_format format, Chris@16: boost::system::error_code& ec) Chris@16: { Chris@16: int file_type; Chris@16: switch (format) Chris@16: { Chris@16: case context_base::asn1: Chris@16: file_type = SSL_FILETYPE_ASN1; Chris@16: break; Chris@16: case context_base::pem: Chris@16: file_type = SSL_FILETYPE_PEM; Chris@16: break; Chris@16: default: Chris@16: { Chris@16: ec = boost::asio::error::invalid_argument; Chris@16: return ec; Chris@16: } Chris@16: } Chris@16: Chris@101: ::ERR_clear_error(); Chris@101: Chris@16: if (::SSL_CTX_use_certificate_file(handle_, filename.c_str(), file_type) != 1) Chris@16: { Chris@16: ec = boost::system::error_code( Chris@16: static_cast(::ERR_get_error()), Chris@16: boost::asio::error::get_ssl_category()); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: void context::use_certificate_chain(const const_buffer& chain) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: use_certificate_chain(chain, ec); Chris@16: boost::asio::detail::throw_error(ec, "use_certificate_chain"); Chris@16: } Chris@16: Chris@16: boost::system::error_code context::use_certificate_chain( Chris@16: const const_buffer& chain, boost::system::error_code& ec) Chris@16: { Chris@16: ::ERR_clear_error(); Chris@16: Chris@16: bio_cleanup bio = { make_buffer_bio(chain) }; Chris@16: if (bio.p) Chris@16: { Chris@16: x509_cleanup cert = { Chris@16: ::PEM_read_bio_X509_AUX(bio.p, 0, Chris@16: handle_->default_passwd_callback, Chris@16: handle_->default_passwd_callback_userdata) }; Chris@16: if (!cert.p) Chris@16: { Chris@16: ec = boost::system::error_code(ERR_R_PEM_LIB, Chris@16: boost::asio::error::get_ssl_category()); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: int result = ::SSL_CTX_use_certificate(handle_, cert.p); Chris@16: if (result == 0 || ::ERR_peek_error() != 0) Chris@16: { Chris@16: ec = boost::system::error_code( Chris@16: static_cast(::ERR_get_error()), Chris@16: boost::asio::error::get_ssl_category()); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: if (handle_->extra_certs) Chris@16: { Chris@16: ::sk_X509_pop_free(handle_->extra_certs, X509_free); Chris@16: handle_->extra_certs = 0; Chris@16: } Chris@16: Chris@16: while (X509* cacert = ::PEM_read_bio_X509(bio.p, 0, Chris@16: handle_->default_passwd_callback, Chris@16: handle_->default_passwd_callback_userdata)) Chris@16: { Chris@16: if (!::SSL_CTX_add_extra_chain_cert(handle_, cacert)) Chris@16: { Chris@16: ec = boost::system::error_code( Chris@16: static_cast(::ERR_get_error()), Chris@16: boost::asio::error::get_ssl_category()); Chris@16: return ec; Chris@16: } Chris@16: } Chris@16: Chris@16: result = ::ERR_peek_last_error(); Chris@16: if ((ERR_GET_LIB(result) == ERR_LIB_PEM) Chris@16: && (ERR_GET_REASON(result) == PEM_R_NO_START_LINE)) Chris@16: { Chris@16: ::ERR_clear_error(); Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: } Chris@16: Chris@16: ec = boost::system::error_code( Chris@16: static_cast(::ERR_get_error()), Chris@16: boost::asio::error::get_ssl_category()); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: void context::use_certificate_chain_file(const std::string& filename) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: use_certificate_chain_file(filename, ec); Chris@16: boost::asio::detail::throw_error(ec, "use_certificate_chain_file"); Chris@16: } Chris@16: Chris@16: boost::system::error_code context::use_certificate_chain_file( Chris@16: const std::string& filename, boost::system::error_code& ec) Chris@16: { Chris@101: ::ERR_clear_error(); Chris@101: Chris@16: if (::SSL_CTX_use_certificate_chain_file(handle_, filename.c_str()) != 1) Chris@16: { Chris@16: ec = boost::system::error_code( Chris@16: static_cast(::ERR_get_error()), Chris@16: boost::asio::error::get_ssl_category()); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: void context::use_private_key( Chris@16: const const_buffer& private_key, context::file_format format) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: use_private_key(private_key, format, ec); Chris@16: boost::asio::detail::throw_error(ec, "use_private_key"); Chris@16: } Chris@16: Chris@16: boost::system::error_code context::use_private_key( Chris@16: const const_buffer& private_key, context::file_format format, Chris@16: boost::system::error_code& ec) Chris@16: { Chris@16: ::ERR_clear_error(); Chris@16: Chris@16: bio_cleanup bio = { make_buffer_bio(private_key) }; Chris@16: if (bio.p) Chris@16: { Chris@16: evp_pkey_cleanup evp_private_key = { 0 }; Chris@16: switch (format) Chris@16: { Chris@16: case context_base::asn1: Chris@16: evp_private_key.p = ::d2i_PrivateKey_bio(bio.p, 0); Chris@16: break; Chris@16: case context_base::pem: Chris@101: evp_private_key.p = ::PEM_read_bio_PrivateKey( Chris@101: bio.p, 0, handle_->default_passwd_callback, Chris@101: handle_->default_passwd_callback_userdata); Chris@16: break; Chris@16: default: Chris@16: { Chris@16: ec = boost::asio::error::invalid_argument; Chris@16: return ec; Chris@16: } Chris@16: } Chris@16: Chris@16: if (evp_private_key.p) Chris@16: { Chris@16: if (::SSL_CTX_use_PrivateKey(handle_, evp_private_key.p) == 1) Chris@16: { Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: ec = boost::system::error_code( Chris@16: static_cast(::ERR_get_error()), Chris@16: boost::asio::error::get_ssl_category()); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: void context::use_private_key_file( Chris@16: const std::string& filename, context::file_format format) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: use_private_key_file(filename, format, ec); Chris@16: boost::asio::detail::throw_error(ec, "use_private_key_file"); Chris@16: } Chris@16: Chris@16: void context::use_rsa_private_key( Chris@16: const const_buffer& private_key, context::file_format format) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: use_rsa_private_key(private_key, format, ec); Chris@16: boost::asio::detail::throw_error(ec, "use_rsa_private_key"); Chris@16: } Chris@16: Chris@16: boost::system::error_code context::use_rsa_private_key( Chris@16: const const_buffer& private_key, context::file_format format, Chris@16: boost::system::error_code& ec) Chris@16: { Chris@16: ::ERR_clear_error(); Chris@16: Chris@16: bio_cleanup bio = { make_buffer_bio(private_key) }; Chris@16: if (bio.p) Chris@16: { Chris@16: rsa_cleanup rsa_private_key = { 0 }; Chris@16: switch (format) Chris@16: { Chris@16: case context_base::asn1: Chris@16: rsa_private_key.p = ::d2i_RSAPrivateKey_bio(bio.p, 0); Chris@16: break; Chris@16: case context_base::pem: Chris@101: rsa_private_key.p = ::PEM_read_bio_RSAPrivateKey( Chris@101: bio.p, 0, handle_->default_passwd_callback, Chris@101: handle_->default_passwd_callback_userdata); Chris@16: break; Chris@16: default: Chris@16: { Chris@16: ec = boost::asio::error::invalid_argument; Chris@16: return ec; Chris@16: } Chris@16: } Chris@16: Chris@16: if (rsa_private_key.p) Chris@16: { Chris@16: if (::SSL_CTX_use_RSAPrivateKey(handle_, rsa_private_key.p) == 1) Chris@16: { Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: ec = boost::system::error_code( Chris@16: static_cast(::ERR_get_error()), Chris@16: boost::asio::error::get_ssl_category()); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: boost::system::error_code context::use_private_key_file( Chris@16: const std::string& filename, context::file_format format, Chris@16: boost::system::error_code& ec) Chris@16: { Chris@16: int file_type; Chris@16: switch (format) Chris@16: { Chris@16: case context_base::asn1: Chris@16: file_type = SSL_FILETYPE_ASN1; Chris@16: break; Chris@16: case context_base::pem: Chris@16: file_type = SSL_FILETYPE_PEM; Chris@16: break; Chris@16: default: Chris@16: { Chris@16: ec = boost::asio::error::invalid_argument; Chris@16: return ec; Chris@16: } Chris@16: } Chris@16: Chris@101: ::ERR_clear_error(); Chris@101: Chris@16: if (::SSL_CTX_use_PrivateKey_file(handle_, filename.c_str(), file_type) != 1) Chris@16: { Chris@16: ec = boost::system::error_code( Chris@16: static_cast(::ERR_get_error()), Chris@16: boost::asio::error::get_ssl_category()); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: void context::use_rsa_private_key_file( Chris@16: const std::string& filename, context::file_format format) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: use_rsa_private_key_file(filename, format, ec); Chris@16: boost::asio::detail::throw_error(ec, "use_rsa_private_key_file"); Chris@16: } Chris@16: Chris@16: boost::system::error_code context::use_rsa_private_key_file( Chris@16: const std::string& filename, context::file_format format, Chris@16: boost::system::error_code& ec) Chris@16: { Chris@16: int file_type; Chris@16: switch (format) Chris@16: { Chris@16: case context_base::asn1: Chris@16: file_type = SSL_FILETYPE_ASN1; Chris@16: break; Chris@16: case context_base::pem: Chris@16: file_type = SSL_FILETYPE_PEM; Chris@16: break; Chris@16: default: Chris@16: { Chris@16: ec = boost::asio::error::invalid_argument; Chris@16: return ec; Chris@16: } Chris@16: } Chris@16: Chris@101: ::ERR_clear_error(); Chris@101: Chris@16: if (::SSL_CTX_use_RSAPrivateKey_file( Chris@16: handle_, filename.c_str(), file_type) != 1) Chris@16: { Chris@16: ec = boost::system::error_code( Chris@16: static_cast(::ERR_get_error()), Chris@16: boost::asio::error::get_ssl_category()); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: void context::use_tmp_dh(const const_buffer& dh) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: use_tmp_dh(dh, ec); Chris@16: boost::asio::detail::throw_error(ec, "use_tmp_dh"); Chris@16: } Chris@16: Chris@16: boost::system::error_code context::use_tmp_dh( Chris@16: const const_buffer& dh, boost::system::error_code& ec) Chris@16: { Chris@101: ::ERR_clear_error(); Chris@101: Chris@16: bio_cleanup bio = { make_buffer_bio(dh) }; Chris@16: if (bio.p) Chris@16: { Chris@16: return do_use_tmp_dh(bio.p, ec); Chris@16: } Chris@16: Chris@16: ec = boost::system::error_code( Chris@16: static_cast(::ERR_get_error()), Chris@16: boost::asio::error::get_ssl_category()); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: void context::use_tmp_dh_file(const std::string& filename) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: use_tmp_dh_file(filename, ec); Chris@16: boost::asio::detail::throw_error(ec, "use_tmp_dh_file"); Chris@16: } Chris@16: Chris@16: boost::system::error_code context::use_tmp_dh_file( Chris@16: const std::string& filename, boost::system::error_code& ec) Chris@16: { Chris@101: ::ERR_clear_error(); Chris@101: Chris@16: bio_cleanup bio = { ::BIO_new_file(filename.c_str(), "r") }; Chris@16: if (bio.p) Chris@16: { Chris@16: return do_use_tmp_dh(bio.p, ec); Chris@16: } Chris@16: Chris@16: ec = boost::system::error_code( Chris@16: static_cast(::ERR_get_error()), Chris@16: boost::asio::error::get_ssl_category()); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: boost::system::error_code context::do_use_tmp_dh( Chris@16: BIO* bio, boost::system::error_code& ec) Chris@16: { Chris@16: ::ERR_clear_error(); Chris@16: Chris@16: dh_cleanup dh = { ::PEM_read_bio_DHparams(bio, 0, 0, 0) }; Chris@16: if (dh.p) Chris@16: { Chris@16: if (::SSL_CTX_set_tmp_dh(handle_, dh.p) == 1) Chris@16: { Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: } Chris@16: Chris@16: ec = boost::system::error_code( Chris@16: static_cast(::ERR_get_error()), Chris@16: boost::asio::error::get_ssl_category()); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: boost::system::error_code context::do_set_verify_callback( Chris@16: detail::verify_callback_base* callback, boost::system::error_code& ec) Chris@16: { Chris@16: if (SSL_CTX_get_app_data(handle_)) Chris@16: { Chris@16: delete static_cast( Chris@16: SSL_CTX_get_app_data(handle_)); Chris@16: } Chris@16: Chris@16: SSL_CTX_set_app_data(handle_, callback); Chris@16: Chris@16: ::SSL_CTX_set_verify(handle_, Chris@16: ::SSL_CTX_get_verify_mode(handle_), Chris@16: &context::verify_callback_function); Chris@16: Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: int context::verify_callback_function(int preverified, X509_STORE_CTX* ctx) Chris@16: { Chris@16: if (ctx) Chris@16: { Chris@16: if (SSL* ssl = static_cast( Chris@16: ::X509_STORE_CTX_get_ex_data( Chris@16: ctx, ::SSL_get_ex_data_X509_STORE_CTX_idx()))) Chris@16: { Chris@16: if (SSL_CTX* handle = ::SSL_get_SSL_CTX(ssl)) Chris@16: { Chris@16: if (SSL_CTX_get_app_data(handle)) Chris@16: { Chris@16: detail::verify_callback_base* callback = Chris@16: static_cast( Chris@16: SSL_CTX_get_app_data(handle)); Chris@16: Chris@16: verify_context verify_ctx(ctx); Chris@16: return callback->call(preverified != 0, verify_ctx) ? 1 : 0; Chris@16: } Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: return 0; Chris@16: } Chris@16: Chris@16: boost::system::error_code context::do_set_password_callback( Chris@16: detail::password_callback_base* callback, boost::system::error_code& ec) Chris@16: { Chris@16: if (handle_->default_passwd_callback_userdata) Chris@16: delete static_cast( Chris@16: handle_->default_passwd_callback_userdata); Chris@16: Chris@16: handle_->default_passwd_callback_userdata = callback; Chris@16: Chris@16: SSL_CTX_set_default_passwd_cb(handle_, &context::password_callback_function); Chris@16: Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: int context::password_callback_function( Chris@16: char* buf, int size, int purpose, void* data) Chris@16: { Chris@16: using namespace std; // For strncat and strlen. Chris@16: Chris@16: if (data) Chris@16: { Chris@16: detail::password_callback_base* callback = Chris@16: static_cast(data); Chris@16: Chris@16: std::string passwd = callback->call(static_cast(size), Chris@16: purpose ? context_base::for_writing : context_base::for_reading); Chris@16: Chris@16: #if defined(BOOST_ASIO_HAS_SECURE_RTL) Chris@16: strcpy_s(buf, size, passwd.c_str()); Chris@16: #else // defined(BOOST_ASIO_HAS_SECURE_RTL) Chris@16: *buf = '\0'; Chris@16: strncat(buf, passwd.c_str(), size); Chris@16: #endif // defined(BOOST_ASIO_HAS_SECURE_RTL) Chris@16: Chris@16: return static_cast(strlen(buf)); Chris@16: } Chris@16: Chris@16: return 0; Chris@16: } Chris@16: Chris@16: BIO* context::make_buffer_bio(const const_buffer& b) Chris@16: { Chris@16: return ::BIO_new_mem_buf( Chris@16: const_cast(buffer_cast(b)), Chris@16: static_cast(buffer_size(b))); Chris@16: } Chris@16: Chris@16: #endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) Chris@16: Chris@16: } // namespace ssl Chris@16: } // namespace asio Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // BOOST_ASIO_SSL_IMPL_CONTEXT_IPP