diff options
Diffstat (limited to 'lib/asio/ssl')
27 files changed, 5388 insertions, 0 deletions
diff --git a/lib/asio/ssl/context.hpp b/lib/asio/ssl/context.hpp new file mode 100644 index 0000000..9543aab --- /dev/null +++ b/lib/asio/ssl/context.hpp @@ -0,0 +1,758 @@ +// +// ssl/context.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_CONTEXT_HPP +#define ASIO_SSL_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include <string> +#include "asio/buffer.hpp" +#include "asio/io_context.hpp" +#include "asio/ssl/context_base.hpp" +#include "asio/ssl/detail/openssl_types.hpp" +#include "asio/ssl/detail/openssl_init.hpp" +#include "asio/ssl/detail/password_callback.hpp" +#include "asio/ssl/detail/verify_callback.hpp" +#include "asio/ssl/verify_mode.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { + +class context + : public context_base, + private noncopyable +{ +public: + /// The native handle type of the SSL context. + typedef SSL_CTX* native_handle_type; + + /// Constructor. + ASIO_DECL explicit context(method m); + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a context from another. + /** + * This constructor moves an SSL context from one object to another. + * + * @param other The other context object from which the move will occur. + * + * @note Following the move, the following operations only are valid for the + * moved-from object: + * @li Destruction. + * @li As a target for move-assignment. + */ + ASIO_DECL context(context&& other); + + /// Move-assign a context from another. + /** + * This assignment operator moves an SSL context from one object to another. + * + * @param other The other context object from which the move will occur. + * + * @note Following the move, the following operations only are valid for the + * moved-from object: + * @li Destruction. + * @li As a target for move-assignment. + */ + ASIO_DECL context& operator=(context&& other); +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destructor. + ASIO_DECL ~context(); + + /// Get the underlying implementation in the native type. + /** + * This function may be used to obtain the underlying implementation of the + * context. This is intended to allow access to context functionality that is + * not otherwise provided. + */ + ASIO_DECL native_handle_type native_handle(); + + /// Clear options on the context. + /** + * This function may be used to configure the SSL options used by the context. + * + * @param o A bitmask of options. The available option values are defined in + * the context_base class. The specified options, if currently enabled on the + * context, are cleared. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_clear_options. + */ + ASIO_DECL void clear_options(options o); + + /// Clear options on the context. + /** + * This function may be used to configure the SSL options used by the context. + * + * @param o A bitmask of options. The available option values are defined in + * the context_base class. The specified options, if currently enabled on the + * context, are cleared. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_clear_options. + */ + ASIO_DECL ASIO_SYNC_OP_VOID clear_options(options o, + asio::error_code& ec); + + /// Set options on the context. + /** + * This function may be used to configure the SSL options used by the context. + * + * @param o A bitmask of options. The available option values are defined in + * the context_base class. The options are bitwise-ored with any existing + * value for the options. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_set_options. + */ + ASIO_DECL void set_options(options o); + + /// Set options on the context. + /** + * This function may be used to configure the SSL options used by the context. + * + * @param o A bitmask of options. The available option values are defined in + * the context_base class. The options are bitwise-ored with any existing + * value for the options. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_set_options. + */ + ASIO_DECL ASIO_SYNC_OP_VOID set_options(options o, + asio::error_code& ec); + + /// Set the peer verification mode. + /** + * This function may be used to configure the peer verification mode used by + * the context. + * + * @param v A bitmask of peer verification modes. See @ref verify_mode for + * available values. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_set_verify. + */ + ASIO_DECL void set_verify_mode(verify_mode v); + + /// Set the peer verification mode. + /** + * This function may be used to configure the peer verification mode used by + * the context. + * + * @param v A bitmask of peer verification modes. See @ref verify_mode for + * available values. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_set_verify. + */ + ASIO_DECL ASIO_SYNC_OP_VOID set_verify_mode( + verify_mode v, asio::error_code& ec); + + /// Set the peer verification depth. + /** + * This function may be used to configure the maximum verification depth + * allowed by the context. + * + * @param depth Maximum depth for the certificate chain verification that + * shall be allowed. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_set_verify_depth. + */ + ASIO_DECL void set_verify_depth(int depth); + + /// Set the peer verification depth. + /** + * This function may be used to configure the maximum verification depth + * allowed by the context. + * + * @param depth Maximum depth for the certificate chain verification that + * shall be allowed. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_set_verify_depth. + */ + ASIO_DECL ASIO_SYNC_OP_VOID set_verify_depth( + int depth, asio::error_code& ec); + + /// Set the callback used to verify peer certificates. + /** + * This function is used to specify a callback function that will be called + * by the implementation when it needs to verify a peer certificate. + * + * @param callback The function object to be used for verifying a certificate. + * The function signature of the handler must be: + * @code bool verify_callback( + * bool preverified, // True if the certificate passed pre-verification. + * verify_context& ctx // The peer certificate and other context. + * ); @endcode + * The return value of the callback is true if the certificate has passed + * verification, false otherwise. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_set_verify. + */ + template <typename VerifyCallback> + void set_verify_callback(VerifyCallback callback); + + /// Set the callback used to verify peer certificates. + /** + * This function is used to specify a callback function that will be called + * by the implementation when it needs to verify a peer certificate. + * + * @param callback The function object to be used for verifying a certificate. + * The function signature of the handler must be: + * @code bool verify_callback( + * bool preverified, // True if the certificate passed pre-verification. + * verify_context& ctx // The peer certificate and other context. + * ); @endcode + * The return value of the callback is true if the certificate has passed + * verification, false otherwise. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_set_verify. + */ + template <typename VerifyCallback> + ASIO_SYNC_OP_VOID set_verify_callback(VerifyCallback callback, + asio::error_code& ec); + + /// Load a certification authority file for performing verification. + /** + * This function is used to load one or more trusted certification authorities + * from a file. + * + * @param filename The name of a file containing certification authority + * certificates in PEM format. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_load_verify_locations. + */ + ASIO_DECL void load_verify_file(const std::string& filename); + + /// Load a certification authority file for performing verification. + /** + * This function is used to load the certificates for one or more trusted + * certification authorities from a file. + * + * @param filename The name of a file containing certification authority + * certificates in PEM format. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_load_verify_locations. + */ + ASIO_DECL ASIO_SYNC_OP_VOID load_verify_file( + const std::string& filename, asio::error_code& ec); + + /// Add certification authority for performing verification. + /** + * This function is used to add one trusted certification authority + * from a memory buffer. + * + * @param ca The buffer containing the certification authority certificate. + * The certificate must use the PEM format. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_get_cert_store and @c X509_STORE_add_cert. + */ + ASIO_DECL void add_certificate_authority(const const_buffer& ca); + + /// Add certification authority for performing verification. + /** + * This function is used to add one trusted certification authority + * from a memory buffer. + * + * @param ca The buffer containing the certification authority certificate. + * The certificate must use the PEM format. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_get_cert_store and @c X509_STORE_add_cert. + */ + ASIO_DECL ASIO_SYNC_OP_VOID add_certificate_authority( + const const_buffer& ca, asio::error_code& ec); + + /// Configures the context to use the default directories for finding + /// certification authority certificates. + /** + * This function specifies that the context should use the default, + * system-dependent directories for locating certification authority + * certificates. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_set_default_verify_paths. + */ + ASIO_DECL void set_default_verify_paths(); + + /// Configures the context to use the default directories for finding + /// certification authority certificates. + /** + * This function specifies that the context should use the default, + * system-dependent directories for locating certification authority + * certificates. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_set_default_verify_paths. + */ + ASIO_DECL ASIO_SYNC_OP_VOID set_default_verify_paths( + asio::error_code& ec); + + /// Add a directory containing certificate authority files to be used for + /// performing verification. + /** + * This function is used to specify the name of a directory containing + * certification authority certificates. Each file in the directory must + * contain a single certificate. The files must be named using the subject + * name's hash and an extension of ".0". + * + * @param path The name of a directory containing the certificates. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_load_verify_locations. + */ + ASIO_DECL void add_verify_path(const std::string& path); + + /// Add a directory containing certificate authority files to be used for + /// performing verification. + /** + * This function is used to specify the name of a directory containing + * certification authority certificates. Each file in the directory must + * contain a single certificate. The files must be named using the subject + * name's hash and an extension of ".0". + * + * @param path The name of a directory containing the certificates. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_load_verify_locations. + */ + ASIO_DECL ASIO_SYNC_OP_VOID add_verify_path( + const std::string& path, asio::error_code& ec); + + /// Use a certificate from a memory buffer. + /** + * This function is used to load a certificate into the context from a buffer. + * + * @param certificate The buffer containing the certificate. + * + * @param format The certificate format (ASN.1 or PEM). + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_use_certificate or SSL_CTX_use_certificate_ASN1. + */ + ASIO_DECL void use_certificate( + const const_buffer& certificate, file_format format); + + /// Use a certificate from a memory buffer. + /** + * This function is used to load a certificate into the context from a buffer. + * + * @param certificate The buffer containing the certificate. + * + * @param format The certificate format (ASN.1 or PEM). + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_use_certificate or SSL_CTX_use_certificate_ASN1. + */ + ASIO_DECL ASIO_SYNC_OP_VOID use_certificate( + const const_buffer& certificate, file_format format, + asio::error_code& ec); + + /// Use a certificate from a file. + /** + * This function is used to load a certificate into the context from a file. + * + * @param filename The name of the file containing the certificate. + * + * @param format The file format (ASN.1 or PEM). + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_use_certificate_file. + */ + ASIO_DECL void use_certificate_file( + const std::string& filename, file_format format); + + /// Use a certificate from a file. + /** + * This function is used to load a certificate into the context from a file. + * + * @param filename The name of the file containing the certificate. + * + * @param format The file format (ASN.1 or PEM). + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_use_certificate_file. + */ + ASIO_DECL ASIO_SYNC_OP_VOID use_certificate_file( + const std::string& filename, file_format format, + asio::error_code& ec); + + /// Use a certificate chain from a memory buffer. + /** + * This function is used to load a certificate chain into the context from a + * buffer. + * + * @param chain The buffer containing the certificate chain. The certificate + * chain must use the PEM format. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_use_certificate and SSL_CTX_add_extra_chain_cert. + */ + ASIO_DECL void use_certificate_chain(const const_buffer& chain); + + /// Use a certificate chain from a memory buffer. + /** + * This function is used to load a certificate chain into the context from a + * buffer. + * + * @param chain The buffer containing the certificate chain. The certificate + * chain must use the PEM format. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_use_certificate and SSL_CTX_add_extra_chain_cert. + */ + ASIO_DECL ASIO_SYNC_OP_VOID use_certificate_chain( + const const_buffer& chain, asio::error_code& ec); + + /// Use a certificate chain from a file. + /** + * This function is used to load a certificate chain into the context from a + * file. + * + * @param filename The name of the file containing the certificate. The file + * must use the PEM format. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_use_certificate_chain_file. + */ + ASIO_DECL void use_certificate_chain_file(const std::string& filename); + + /// Use a certificate chain from a file. + /** + * This function is used to load a certificate chain into the context from a + * file. + * + * @param filename The name of the file containing the certificate. The file + * must use the PEM format. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_use_certificate_chain_file. + */ + ASIO_DECL ASIO_SYNC_OP_VOID use_certificate_chain_file( + const std::string& filename, asio::error_code& ec); + + /// Use a private key from a memory buffer. + /** + * This function is used to load a private key into the context from a buffer. + * + * @param private_key The buffer containing the private key. + * + * @param format The private key format (ASN.1 or PEM). + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_use_PrivateKey or SSL_CTX_use_PrivateKey_ASN1. + */ + ASIO_DECL void use_private_key( + const const_buffer& private_key, file_format format); + + /// Use a private key from a memory buffer. + /** + * This function is used to load a private key into the context from a buffer. + * + * @param private_key The buffer containing the private key. + * + * @param format The private key format (ASN.1 or PEM). + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_use_PrivateKey or SSL_CTX_use_PrivateKey_ASN1. + */ + ASIO_DECL ASIO_SYNC_OP_VOID use_private_key( + const const_buffer& private_key, file_format format, + asio::error_code& ec); + + /// Use a private key from a file. + /** + * This function is used to load a private key into the context from a file. + * + * @param filename The name of the file containing the private key. + * + * @param format The file format (ASN.1 or PEM). + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_use_PrivateKey_file. + */ + ASIO_DECL void use_private_key_file( + const std::string& filename, file_format format); + + /// Use a private key from a file. + /** + * This function is used to load a private key into the context from a file. + * + * @param filename The name of the file containing the private key. + * + * @param format The file format (ASN.1 or PEM). + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_use_PrivateKey_file. + */ + ASIO_DECL ASIO_SYNC_OP_VOID use_private_key_file( + const std::string& filename, file_format format, + asio::error_code& ec); + + /// Use an RSA private key from a memory buffer. + /** + * This function is used to load an RSA private key into the context from a + * buffer. + * + * @param private_key The buffer containing the RSA private key. + * + * @param format The private key format (ASN.1 or PEM). + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_use_RSAPrivateKey or SSL_CTX_use_RSAPrivateKey_ASN1. + */ + ASIO_DECL void use_rsa_private_key( + const const_buffer& private_key, file_format format); + + /// Use an RSA private key from a memory buffer. + /** + * This function is used to load an RSA private key into the context from a + * buffer. + * + * @param private_key The buffer containing the RSA private key. + * + * @param format The private key format (ASN.1 or PEM). + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_use_RSAPrivateKey or SSL_CTX_use_RSAPrivateKey_ASN1. + */ + ASIO_DECL ASIO_SYNC_OP_VOID use_rsa_private_key( + const const_buffer& private_key, file_format format, + asio::error_code& ec); + + /// Use an RSA private key from a file. + /** + * This function is used to load an RSA private key into the context from a + * file. + * + * @param filename The name of the file containing the RSA private key. + * + * @param format The file format (ASN.1 or PEM). + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_use_RSAPrivateKey_file. + */ + ASIO_DECL void use_rsa_private_key_file( + const std::string& filename, file_format format); + + /// Use an RSA private key from a file. + /** + * This function is used to load an RSA private key into the context from a + * file. + * + * @param filename The name of the file containing the RSA private key. + * + * @param format The file format (ASN.1 or PEM). + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_use_RSAPrivateKey_file. + */ + ASIO_DECL ASIO_SYNC_OP_VOID use_rsa_private_key_file( + const std::string& filename, file_format format, + asio::error_code& ec); + + /// Use the specified memory buffer to obtain the temporary Diffie-Hellman + /// parameters. + /** + * This function is used to load Diffie-Hellman parameters into the context + * from a buffer. + * + * @param dh The memory buffer containing the Diffie-Hellman parameters. The + * buffer must use the PEM format. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_set_tmp_dh. + */ + ASIO_DECL void use_tmp_dh(const const_buffer& dh); + + /// Use the specified memory buffer to obtain the temporary Diffie-Hellman + /// parameters. + /** + * This function is used to load Diffie-Hellman parameters into the context + * from a buffer. + * + * @param dh The memory buffer containing the Diffie-Hellman parameters. The + * buffer must use the PEM format. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_set_tmp_dh. + */ + ASIO_DECL ASIO_SYNC_OP_VOID use_tmp_dh( + const const_buffer& dh, asio::error_code& ec); + + /// Use the specified file to obtain the temporary Diffie-Hellman parameters. + /** + * This function is used to load Diffie-Hellman parameters into the context + * from a file. + * + * @param filename The name of the file containing the Diffie-Hellman + * parameters. The file must use the PEM format. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_set_tmp_dh. + */ + ASIO_DECL void use_tmp_dh_file(const std::string& filename); + + /// Use the specified file to obtain the temporary Diffie-Hellman parameters. + /** + * This function is used to load Diffie-Hellman parameters into the context + * from a file. + * + * @param filename The name of the file containing the Diffie-Hellman + * parameters. The file must use the PEM format. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_set_tmp_dh. + */ + ASIO_DECL ASIO_SYNC_OP_VOID use_tmp_dh_file( + const std::string& filename, asio::error_code& ec); + + /// Set the password callback. + /** + * This function is used to specify a callback function to obtain password + * information about an encrypted key in PEM format. + * + * @param callback The function object to be used for obtaining the password. + * The function signature of the handler must be: + * @code std::string password_callback( + * std::size_t max_length, // The maximum size for a password. + * password_purpose purpose // Whether password is for reading or writing. + * ); @endcode + * The return value of the callback is a string containing the password. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_CTX_set_default_passwd_cb. + */ + template <typename PasswordCallback> + void set_password_callback(PasswordCallback callback); + + /// Set the password callback. + /** + * This function is used to specify a callback function to obtain password + * information about an encrypted key in PEM format. + * + * @param callback The function object to be used for obtaining the password. + * The function signature of the handler must be: + * @code std::string password_callback( + * std::size_t max_length, // The maximum size for a password. + * password_purpose purpose // Whether password is for reading or writing. + * ); @endcode + * The return value of the callback is a string containing the password. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_CTX_set_default_passwd_cb. + */ + template <typename PasswordCallback> + ASIO_SYNC_OP_VOID set_password_callback(PasswordCallback callback, + asio::error_code& ec); + +private: + struct bio_cleanup; + struct x509_cleanup; + struct evp_pkey_cleanup; + struct rsa_cleanup; + struct dh_cleanup; + + // Helper function used to set a peer certificate verification callback. + ASIO_DECL ASIO_SYNC_OP_VOID do_set_verify_callback( + detail::verify_callback_base* callback, asio::error_code& ec); + + // Callback used when the SSL implementation wants to verify a certificate. + ASIO_DECL static int verify_callback_function( + int preverified, X509_STORE_CTX* ctx); + + // Helper function used to set a password callback. + ASIO_DECL ASIO_SYNC_OP_VOID do_set_password_callback( + detail::password_callback_base* callback, asio::error_code& ec); + + // Callback used when the SSL implementation wants a password. + ASIO_DECL static int password_callback_function( + char* buf, int size, int purpose, void* data); + + // Helper function to set the temporary Diffie-Hellman parameters from a BIO. + ASIO_DECL ASIO_SYNC_OP_VOID do_use_tmp_dh( + BIO* bio, asio::error_code& ec); + + // Helper function to make a BIO from a memory buffer. + ASIO_DECL BIO* make_buffer_bio(const const_buffer& b); + + // The underlying native implementation. + native_handle_type handle_; + + // Ensure openssl is initialised. + asio::ssl::detail::openssl_init<> init_; +}; + +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/ssl/impl/context.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/ssl/impl/context.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_SSL_CONTEXT_HPP diff --git a/lib/asio/ssl/context_base.hpp b/lib/asio/ssl/context_base.hpp new file mode 100644 index 0000000..56c7693 --- /dev/null +++ b/lib/asio/ssl/context_base.hpp @@ -0,0 +1,192 @@ +// +// ssl/context_base.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_CONTEXT_BASE_HPP +#define ASIO_SSL_CONTEXT_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/ssl/detail/openssl_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { + +/// The context_base class is used as a base for the basic_context class +/// template so that we have a common place to define various enums. +class context_base +{ +public: + /// Different methods supported by a context. + enum method + { + /// Generic SSL version 2. + sslv2, + + /// SSL version 2 client. + sslv2_client, + + /// SSL version 2 server. + sslv2_server, + + /// Generic SSL version 3. + sslv3, + + /// SSL version 3 client. + sslv3_client, + + /// SSL version 3 server. + sslv3_server, + + /// Generic TLS version 1. + tlsv1, + + /// TLS version 1 client. + tlsv1_client, + + /// TLS version 1 server. + tlsv1_server, + + /// Generic SSL/TLS. + sslv23, + + /// SSL/TLS client. + sslv23_client, + + /// SSL/TLS server. + sslv23_server, + + /// Generic TLS version 1.1. + tlsv11, + + /// TLS version 1.1 client. + tlsv11_client, + + /// TLS version 1.1 server. + tlsv11_server, + + /// Generic TLS version 1.2. + tlsv12, + + /// TLS version 1.2 client. + tlsv12_client, + + /// TLS version 1.2 server. + tlsv12_server, + + /// Generic TLS. + tls, + + /// TLS client. + tls_client, + + /// TLS server. + tls_server + }; + + /// Bitmask type for SSL options. + typedef long options; + +#if defined(GENERATING_DOCUMENTATION) + /// Implement various bug workarounds. + static const long default_workarounds = implementation_defined; + + /// Always create a new key when using tmp_dh parameters. + static const long single_dh_use = implementation_defined; + + /// Disable SSL v2. + static const long no_sslv2 = implementation_defined; + + /// Disable SSL v3. + static const long no_sslv3 = implementation_defined; + + /// Disable TLS v1. + static const long no_tlsv1 = implementation_defined; + + /// Disable TLS v1.1. + static const long no_tlsv1_1 = implementation_defined; + + /// Disable TLS v1.2. + static const long no_tlsv1_2 = implementation_defined; + + /// Disable compression. Compression is disabled by default. + static const long no_compression = implementation_defined; +#else + ASIO_STATIC_CONSTANT(long, default_workarounds = SSL_OP_ALL); + ASIO_STATIC_CONSTANT(long, single_dh_use = SSL_OP_SINGLE_DH_USE); + ASIO_STATIC_CONSTANT(long, no_sslv2 = SSL_OP_NO_SSLv2); + ASIO_STATIC_CONSTANT(long, no_sslv3 = SSL_OP_NO_SSLv3); + ASIO_STATIC_CONSTANT(long, no_tlsv1 = SSL_OP_NO_TLSv1); +# if defined(SSL_OP_NO_TLSv1_1) + ASIO_STATIC_CONSTANT(long, no_tlsv1_1 = SSL_OP_NO_TLSv1_1); +# else // defined(SSL_OP_NO_TLSv1_1) + ASIO_STATIC_CONSTANT(long, no_tlsv1_1 = 0x10000000L); +# endif // defined(SSL_OP_NO_TLSv1_1) +# if defined(SSL_OP_NO_TLSv1_2) + ASIO_STATIC_CONSTANT(long, no_tlsv1_2 = SSL_OP_NO_TLSv1_2); +# else // defined(SSL_OP_NO_TLSv1_2) + ASIO_STATIC_CONSTANT(long, no_tlsv1_2 = 0x08000000L); +# endif // defined(SSL_OP_NO_TLSv1_2) +# if defined(SSL_OP_NO_COMPRESSION) + ASIO_STATIC_CONSTANT(long, no_compression = SSL_OP_NO_COMPRESSION); +# else // defined(SSL_OP_NO_COMPRESSION) + ASIO_STATIC_CONSTANT(long, no_compression = 0x20000L); +# endif // defined(SSL_OP_NO_COMPRESSION) +#endif + + /// File format types. + enum file_format + { + /// ASN.1 file. + asn1, + + /// PEM file. + pem + }; + +#if !defined(GENERATING_DOCUMENTATION) + // The following types and constants are preserved for backward compatibility. + // New programs should use the equivalents of the same names that are defined + // in the asio::ssl namespace. + typedef int verify_mode; + ASIO_STATIC_CONSTANT(int, verify_none = SSL_VERIFY_NONE); + ASIO_STATIC_CONSTANT(int, verify_peer = SSL_VERIFY_PEER); + ASIO_STATIC_CONSTANT(int, + verify_fail_if_no_peer_cert = SSL_VERIFY_FAIL_IF_NO_PEER_CERT); + ASIO_STATIC_CONSTANT(int, verify_client_once = SSL_VERIFY_CLIENT_ONCE); +#endif + + /// Purpose of PEM password. + enum password_purpose + { + /// The password is needed for reading/decryption. + for_reading, + + /// The password is needed for writing/encryption. + for_writing + }; + +protected: + /// Protected destructor to prevent deletion through this type. + ~context_base() + { + } +}; + +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_CONTEXT_BASE_HPP diff --git a/lib/asio/ssl/detail/buffered_handshake_op.hpp b/lib/asio/ssl/detail/buffered_handshake_op.hpp new file mode 100644 index 0000000..38a03fc --- /dev/null +++ b/lib/asio/ssl/detail/buffered_handshake_op.hpp @@ -0,0 +1,114 @@ +// +// ssl/detail/buffered_handshake_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_BUFFERED_HANDSHAKE_OP_HPP +#define ASIO_SSL_DETAIL_BUFFERED_HANDSHAKE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/ssl/detail/engine.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +template <typename ConstBufferSequence> +class buffered_handshake_op +{ +public: + buffered_handshake_op(stream_base::handshake_type type, + const ConstBufferSequence& buffers) + : type_(type), + buffers_(buffers), + total_buffer_size_(asio::buffer_size(buffers_)) + { + } + + engine::want operator()(engine& eng, + asio::error_code& ec, + std::size_t& bytes_transferred) const + { + return this->process(eng, ec, bytes_transferred, + asio::buffer_sequence_begin(buffers_), + asio::buffer_sequence_end(buffers_)); + } + + template <typename Handler> + void call_handler(Handler& handler, + const asio::error_code& ec, + const std::size_t& bytes_transferred) const + { + handler(ec, bytes_transferred); + } + +private: + template <typename Iterator> + engine::want process(engine& eng, + asio::error_code& ec, + std::size_t& bytes_transferred, + Iterator begin, Iterator end) const + { + Iterator iter = begin; + std::size_t accumulated_size = 0; + + for (;;) + { + engine::want want = eng.handshake(type_, ec); + if (want != engine::want_input_and_retry + || bytes_transferred == total_buffer_size_) + return want; + + // Find the next buffer piece to be fed to the engine. + while (iter != end) + { + const_buffer buffer(*iter); + + // Skip over any buffers which have already been consumed by the engine. + if (bytes_transferred >= accumulated_size + buffer.size()) + { + accumulated_size += buffer.size(); + ++iter; + continue; + } + + // The current buffer may have been partially consumed by the engine on + // a previous iteration. If so, adjust the buffer to point to the + // unused portion. + if (bytes_transferred > accumulated_size) + buffer = buffer + (bytes_transferred - accumulated_size); + + // Pass the buffer to the engine, and update the bytes transferred to + // reflect the total number of bytes consumed so far. + bytes_transferred += buffer.size(); + buffer = eng.put_input(buffer); + bytes_transferred -= buffer.size(); + break; + } + } + } + + stream_base::handshake_type type_; + ConstBufferSequence buffers_; + std::size_t total_buffer_size_; +}; + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_BUFFERED_HANDSHAKE_OP_HPP diff --git a/lib/asio/ssl/detail/engine.hpp b/lib/asio/ssl/detail/engine.hpp new file mode 100644 index 0000000..2f033d6 --- /dev/null +++ b/lib/asio/ssl/detail/engine.hpp @@ -0,0 +1,160 @@ +// +// ssl/detail/engine.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_ENGINE_HPP +#define ASIO_SSL_DETAIL_ENGINE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/buffer.hpp" +#include "asio/detail/static_mutex.hpp" +#include "asio/ssl/detail/openssl_types.hpp" +#include "asio/ssl/detail/verify_callback.hpp" +#include "asio/ssl/stream_base.hpp" +#include "asio/ssl/verify_mode.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +class engine +{ +public: + enum want + { + // Returned by functions to indicate that the engine wants input. The input + // buffer should be updated to point to the data. The engine then needs to + // be called again to retry the operation. + want_input_and_retry = -2, + + // Returned by functions to indicate that the engine wants to write output. + // The output buffer points to the data to be written. The engine then + // needs to be called again to retry the operation. + want_output_and_retry = -1, + + // Returned by functions to indicate that the engine doesn't need input or + // output. + want_nothing = 0, + + // Returned by functions to indicate that the engine wants to write output. + // The output buffer points to the data to be written. After that the + // operation is complete, and the engine does not need to be called again. + want_output = 1 + }; + + // Construct a new engine for the specified context. + ASIO_DECL explicit engine(SSL_CTX* context); + + // Destructor. + ASIO_DECL ~engine(); + + // Get the underlying implementation in the native type. + ASIO_DECL SSL* native_handle(); + + // Set the peer verification mode. + ASIO_DECL asio::error_code set_verify_mode( + verify_mode v, asio::error_code& ec); + + // Set the peer verification depth. + ASIO_DECL asio::error_code set_verify_depth( + int depth, asio::error_code& ec); + + // Set a peer certificate verification callback. + ASIO_DECL asio::error_code set_verify_callback( + verify_callback_base* callback, asio::error_code& ec); + + // Perform an SSL handshake using either SSL_connect (client-side) or + // SSL_accept (server-side). + ASIO_DECL want handshake( + stream_base::handshake_type type, asio::error_code& ec); + + // Perform a graceful shutdown of the SSL session. + ASIO_DECL want shutdown(asio::error_code& ec); + + // Write bytes to the SSL session. + ASIO_DECL want write(const asio::const_buffer& data, + asio::error_code& ec, std::size_t& bytes_transferred); + + // Read bytes from the SSL session. + ASIO_DECL want read(const asio::mutable_buffer& data, + asio::error_code& ec, std::size_t& bytes_transferred); + + // Get output data to be written to the transport. + ASIO_DECL asio::mutable_buffer get_output( + const asio::mutable_buffer& data); + + // Put input data that was read from the transport. + ASIO_DECL asio::const_buffer put_input( + const asio::const_buffer& data); + + // Map an error::eof code returned by the underlying transport according to + // the type and state of the SSL session. Returns a const reference to the + // error code object, suitable for passing to a completion handler. + ASIO_DECL const asio::error_code& map_error_code( + asio::error_code& ec) const; + +private: + // Disallow copying and assignment. + engine(const engine&); + engine& operator=(const engine&); + + // Callback used when the SSL implementation wants to verify a certificate. + ASIO_DECL static int verify_callback_function( + int preverified, X509_STORE_CTX* ctx); + +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) + // The SSL_accept function may not be thread safe. This mutex is used to + // protect all calls to the SSL_accept function. + ASIO_DECL static asio::detail::static_mutex& accept_mutex(); +#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) + + // Perform one operation. Returns >= 0 on success or error, want_read if the + // operation needs more input, or want_write if it needs to write some output + // before the operation can complete. + ASIO_DECL want perform(int (engine::* op)(void*, std::size_t), + void* data, std::size_t length, asio::error_code& ec, + std::size_t* bytes_transferred); + + // Adapt the SSL_accept function to the signature needed for perform(). + ASIO_DECL int do_accept(void*, std::size_t); + + // Adapt the SSL_connect function to the signature needed for perform(). + ASIO_DECL int do_connect(void*, std::size_t); + + // Adapt the SSL_shutdown function to the signature needed for perform(). + ASIO_DECL int do_shutdown(void*, std::size_t); + + // Adapt the SSL_read function to the signature needed for perform(). + ASIO_DECL int do_read(void* data, std::size_t length); + + // Adapt the SSL_write function to the signature needed for perform(). + ASIO_DECL int do_write(void* data, std::size_t length); + + SSL* ssl_; + BIO* ext_bio_; +}; + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/ssl/detail/impl/engine.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_SSL_DETAIL_ENGINE_HPP diff --git a/lib/asio/ssl/detail/handshake_op.hpp b/lib/asio/ssl/detail/handshake_op.hpp new file mode 100644 index 0000000..f782023 --- /dev/null +++ b/lib/asio/ssl/detail/handshake_op.hpp @@ -0,0 +1,62 @@ +// +// ssl/detail/handshake_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_HANDSHAKE_OP_HPP +#define ASIO_SSL_DETAIL_HANDSHAKE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/ssl/detail/engine.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +class handshake_op +{ +public: + handshake_op(stream_base::handshake_type type) + : type_(type) + { + } + + engine::want operator()(engine& eng, + asio::error_code& ec, + std::size_t& bytes_transferred) const + { + bytes_transferred = 0; + return eng.handshake(type_, ec); + } + + template <typename Handler> + void call_handler(Handler& handler, + const asio::error_code& ec, + const std::size_t&) const + { + handler(ec); + } + +private: + stream_base::handshake_type type_; +}; + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_HANDSHAKE_OP_HPP diff --git a/lib/asio/ssl/detail/impl/engine.ipp b/lib/asio/ssl/detail/impl/engine.ipp new file mode 100644 index 0000000..e60e8d6 --- /dev/null +++ b/lib/asio/ssl/detail/impl/engine.ipp @@ -0,0 +1,322 @@ +// +// ssl/detail/impl/engine.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_IMPL_ENGINE_IPP +#define ASIO_SSL_DETAIL_IMPL_ENGINE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" +#include "asio/ssl/detail/engine.hpp" +#include "asio/ssl/error.hpp" +#include "asio/ssl/verify_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +engine::engine(SSL_CTX* context) + : ssl_(::SSL_new(context)) +{ + if (!ssl_) + { + asio::error_code ec( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + asio::detail::throw_error(ec, "engine"); + } + +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) + accept_mutex().init(); +#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) + + ::SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE); + ::SSL_set_mode(ssl_, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); +#if defined(SSL_MODE_RELEASE_BUFFERS) + ::SSL_set_mode(ssl_, SSL_MODE_RELEASE_BUFFERS); +#endif // defined(SSL_MODE_RELEASE_BUFFERS) + + ::BIO* int_bio = 0; + ::BIO_new_bio_pair(&int_bio, 0, &ext_bio_, 0); + ::SSL_set_bio(ssl_, int_bio, int_bio); +} + +engine::~engine() +{ + if (SSL_get_app_data(ssl_)) + { + delete static_cast<verify_callback_base*>(SSL_get_app_data(ssl_)); + SSL_set_app_data(ssl_, 0); + } + + ::BIO_free(ext_bio_); + ::SSL_free(ssl_); +} + +SSL* engine::native_handle() +{ + return ssl_; +} + +asio::error_code engine::set_verify_mode( + verify_mode v, asio::error_code& ec) +{ + ::SSL_set_verify(ssl_, v, ::SSL_get_verify_callback(ssl_)); + + ec = asio::error_code(); + return ec; +} + +asio::error_code engine::set_verify_depth( + int depth, asio::error_code& ec) +{ + ::SSL_set_verify_depth(ssl_, depth); + + ec = asio::error_code(); + return ec; +} + +asio::error_code engine::set_verify_callback( + verify_callback_base* callback, asio::error_code& ec) +{ + if (SSL_get_app_data(ssl_)) + delete static_cast<verify_callback_base*>(SSL_get_app_data(ssl_)); + + SSL_set_app_data(ssl_, callback); + + ::SSL_set_verify(ssl_, ::SSL_get_verify_mode(ssl_), + &engine::verify_callback_function); + + ec = asio::error_code(); + return ec; +} + +int engine::verify_callback_function(int preverified, X509_STORE_CTX* ctx) +{ + if (ctx) + { + if (SSL* ssl = static_cast<SSL*>( + ::X509_STORE_CTX_get_ex_data( + ctx, ::SSL_get_ex_data_X509_STORE_CTX_idx()))) + { + if (SSL_get_app_data(ssl)) + { + verify_callback_base* callback = + static_cast<verify_callback_base*>( + SSL_get_app_data(ssl)); + + verify_context verify_ctx(ctx); + return callback->call(preverified != 0, verify_ctx) ? 1 : 0; + } + } + } + + return 0; +} + +engine::want engine::handshake( + stream_base::handshake_type type, asio::error_code& ec) +{ + return perform((type == asio::ssl::stream_base::client) + ? &engine::do_connect : &engine::do_accept, 0, 0, ec, 0); +} + +engine::want engine::shutdown(asio::error_code& ec) +{ + return perform(&engine::do_shutdown, 0, 0, ec, 0); +} + +engine::want engine::write(const asio::const_buffer& data, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + if (data.size() == 0) + { + ec = asio::error_code(); + return engine::want_nothing; + } + + return perform(&engine::do_write, + const_cast<void*>(data.data()), + data.size(), ec, &bytes_transferred); +} + +engine::want engine::read(const asio::mutable_buffer& data, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + if (data.size() == 0) + { + ec = asio::error_code(); + return engine::want_nothing; + } + + return perform(&engine::do_read, data.data(), + data.size(), ec, &bytes_transferred); +} + +asio::mutable_buffer engine::get_output( + const asio::mutable_buffer& data) +{ + int length = ::BIO_read(ext_bio_, + data.data(), static_cast<int>(data.size())); + + return asio::buffer(data, + length > 0 ? static_cast<std::size_t>(length) : 0); +} + +asio::const_buffer engine::put_input( + const asio::const_buffer& data) +{ + int length = ::BIO_write(ext_bio_, + data.data(), static_cast<int>(data.size())); + + return asio::buffer(data + + (length > 0 ? static_cast<std::size_t>(length) : 0)); +} + +const asio::error_code& engine::map_error_code( + asio::error_code& ec) const +{ + // We only want to map the error::eof code. + if (ec != asio::error::eof) + return ec; + + // If there's data yet to be read, it's an error. + if (BIO_wpending(ext_bio_)) + { + ec = asio::ssl::error::stream_truncated; + return ec; + } + + // SSL v2 doesn't provide a protocol-level shutdown, so an eof on the + // underlying transport is passed through. +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) + if (SSL_version(ssl_) == SSL2_VERSION) + return ec; +#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L) + + // Otherwise, the peer should have negotiated a proper shutdown. + if ((::SSL_get_shutdown(ssl_) & SSL_RECEIVED_SHUTDOWN) == 0) + { + ec = asio::ssl::error::stream_truncated; + } + + return ec; +} + +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) +asio::detail::static_mutex& engine::accept_mutex() +{ + static asio::detail::static_mutex mutex = ASIO_STATIC_MUTEX_INIT; + return mutex; +} +#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) + +engine::want engine::perform(int (engine::* op)(void*, std::size_t), + void* data, std::size_t length, asio::error_code& ec, + std::size_t* bytes_transferred) +{ + std::size_t pending_output_before = ::BIO_ctrl_pending(ext_bio_); + ::ERR_clear_error(); + int result = (this->*op)(data, length); + int ssl_error = ::SSL_get_error(ssl_, result); + int sys_error = static_cast<int>(::ERR_get_error()); + std::size_t pending_output_after = ::BIO_ctrl_pending(ext_bio_); + + if (ssl_error == SSL_ERROR_SSL) + { + ec = asio::error_code(sys_error, + asio::error::get_ssl_category()); + return want_nothing; + } + + if (ssl_error == SSL_ERROR_SYSCALL) + { + ec = asio::error_code(sys_error, + asio::error::get_system_category()); + return want_nothing; + } + + if (result > 0 && bytes_transferred) + *bytes_transferred = static_cast<std::size_t>(result); + + if (ssl_error == SSL_ERROR_WANT_WRITE) + { + ec = asio::error_code(); + return want_output_and_retry; + } + else if (pending_output_after > pending_output_before) + { + ec = asio::error_code(); + return result > 0 ? want_output : want_output_and_retry; + } + else if (ssl_error == SSL_ERROR_WANT_READ) + { + ec = asio::error_code(); + return want_input_and_retry; + } + else if (::SSL_get_shutdown(ssl_) & SSL_RECEIVED_SHUTDOWN) + { + ec = asio::error::eof; + return want_nothing; + } + else + { + ec = asio::error_code(); + return want_nothing; + } +} + +int engine::do_accept(void*, std::size_t) +{ +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) + asio::detail::static_mutex::scoped_lock lock(accept_mutex()); +#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) + return ::SSL_accept(ssl_); +} + +int engine::do_connect(void*, std::size_t) +{ + return ::SSL_connect(ssl_); +} + +int engine::do_shutdown(void*, std::size_t) +{ + int result = ::SSL_shutdown(ssl_); + if (result == 0) + result = ::SSL_shutdown(ssl_); + return result; +} + +int engine::do_read(void* data, std::size_t length) +{ + return ::SSL_read(ssl_, data, + length < INT_MAX ? static_cast<int>(length) : INT_MAX); +} + +int engine::do_write(void* data, std::size_t length) +{ + return ::SSL_write(ssl_, data, + length < INT_MAX ? static_cast<int>(length) : INT_MAX); +} + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_IMPL_ENGINE_IPP diff --git a/lib/asio/ssl/detail/impl/openssl_init.ipp b/lib/asio/ssl/detail/impl/openssl_init.ipp new file mode 100644 index 0000000..fb0fff9 --- /dev/null +++ b/lib/asio/ssl/detail/impl/openssl_init.ipp @@ -0,0 +1,165 @@ +// +// ssl/detail/impl/openssl_init.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com +// Copyright (c) 2005-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_IMPL_OPENSSL_INIT_IPP +#define ASIO_SSL_DETAIL_IMPL_OPENSSL_INIT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <vector> +#include "asio/detail/assert.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/tss_ptr.hpp" +#include "asio/ssl/detail/openssl_init.hpp" +#include "asio/ssl/detail/openssl_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +class openssl_init_base::do_init +{ +public: + do_init() + { +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) + ::SSL_library_init(); + ::SSL_load_error_strings(); + ::OpenSSL_add_all_algorithms(); + + mutexes_.resize(::CRYPTO_num_locks()); + for (size_t i = 0; i < mutexes_.size(); ++i) + mutexes_[i].reset(new asio::detail::mutex); + ::CRYPTO_set_locking_callback(&do_init::openssl_locking_func); +#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L) +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) + ::CRYPTO_set_id_callback(&do_init::openssl_id_func); +#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) + +#if !defined(SSL_OP_NO_COMPRESSION) \ + && (OPENSSL_VERSION_NUMBER >= 0x00908000L) + null_compression_methods_ = sk_SSL_COMP_new_null(); +#endif // !defined(SSL_OP_NO_COMPRESSION) + // && (OPENSSL_VERSION_NUMBER >= 0x00908000L) + } + + ~do_init() + { +#if !defined(SSL_OP_NO_COMPRESSION) \ + && (OPENSSL_VERSION_NUMBER >= 0x00908000L) + sk_SSL_COMP_free(null_compression_methods_); +#endif // !defined(SSL_OP_NO_COMPRESSION) + // && (OPENSSL_VERSION_NUMBER >= 0x00908000L) + +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) + ::CRYPTO_set_id_callback(0); +#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) + ::CRYPTO_set_locking_callback(0); + ::ERR_free_strings(); + ::EVP_cleanup(); + ::CRYPTO_cleanup_all_ex_data(); +#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L) +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) + ::ERR_remove_state(0); +#elif (OPENSSL_VERSION_NUMBER < 0x10100000L) + ::ERR_remove_thread_state(NULL); +#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) +#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) \ + && (OPENSSL_VERSION_NUMBER < 0x10100000L) \ + && !defined(SSL_OP_NO_COMPRESSION) + ::SSL_COMP_free_compression_methods(); +#endif // (OPENSSL_VERSION_NUMBER >= 0x10002000L) + // && (OPENSSL_VERSION_NUMBER < 0x10100000L) + // && !defined(SSL_OP_NO_COMPRESSION) +#if !defined(OPENSSL_IS_BORINGSSL) + ::CONF_modules_unload(1); +#endif // !defined(OPENSSL_IS_BORINGSSL) +#if !defined(OPENSSL_NO_ENGINE) \ + && (OPENSSL_VERSION_NUMBER < 0x10100000L) + ::ENGINE_cleanup(); +#endif // !defined(OPENSSL_NO_ENGINE) + // && (OPENSSL_VERSION_NUMBER < 0x10100000L) + } + +#if !defined(SSL_OP_NO_COMPRESSION) \ + && (OPENSSL_VERSION_NUMBER >= 0x00908000L) + STACK_OF(SSL_COMP)* get_null_compression_methods() const + { + return null_compression_methods_; + } +#endif // !defined(SSL_OP_NO_COMPRESSION) + // && (OPENSSL_VERSION_NUMBER >= 0x00908000L) + +private: +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) + static unsigned long openssl_id_func() + { +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + return ::GetCurrentThreadId(); +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + void* id = &errno; + ASIO_ASSERT(sizeof(unsigned long) >= sizeof(void*)); + return reinterpret_cast<unsigned long>(id); +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + } +#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) + +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) + static void openssl_locking_func(int mode, int n, + const char* /*file*/, int /*line*/) + { + if (mode & CRYPTO_LOCK) + instance()->mutexes_[n]->lock(); + else + instance()->mutexes_[n]->unlock(); + } + + // Mutexes to be used in locking callbacks. + std::vector<asio::detail::shared_ptr< + asio::detail::mutex> > mutexes_; +#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L) + +#if !defined(SSL_OP_NO_COMPRESSION) \ + && (OPENSSL_VERSION_NUMBER >= 0x00908000L) + STACK_OF(SSL_COMP)* null_compression_methods_; +#endif // !defined(SSL_OP_NO_COMPRESSION) + // && (OPENSSL_VERSION_NUMBER >= 0x00908000L) +}; + +asio::detail::shared_ptr<openssl_init_base::do_init> +openssl_init_base::instance() +{ + static asio::detail::shared_ptr<do_init> init(new do_init); + return init; +} + +#if !defined(SSL_OP_NO_COMPRESSION) \ + && (OPENSSL_VERSION_NUMBER >= 0x00908000L) +STACK_OF(SSL_COMP)* openssl_init_base::get_null_compression_methods() +{ + return instance()->get_null_compression_methods(); +} +#endif // !defined(SSL_OP_NO_COMPRESSION) + // && (OPENSSL_VERSION_NUMBER >= 0x00908000L) + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_IMPL_OPENSSL_INIT_IPP diff --git a/lib/asio/ssl/detail/io.hpp b/lib/asio/ssl/detail/io.hpp new file mode 100644 index 0000000..0b0e51a --- /dev/null +++ b/lib/asio/ssl/detail/io.hpp @@ -0,0 +1,372 @@ +// +// ssl/detail/io.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_IO_HPP +#define ASIO_SSL_DETAIL_IO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/ssl/detail/engine.hpp" +#include "asio/ssl/detail/stream_core.hpp" +#include "asio/write.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +template <typename Stream, typename Operation> +std::size_t io(Stream& next_layer, stream_core& core, + const Operation& op, asio::error_code& ec) +{ + std::size_t bytes_transferred = 0; + do switch (op(core.engine_, ec, bytes_transferred)) + { + case engine::want_input_and_retry: + + // If the input buffer is empty then we need to read some more data from + // the underlying transport. + if (core.input_.size() == 0) + core.input_ = asio::buffer(core.input_buffer_, + next_layer.read_some(core.input_buffer_, ec)); + + // Pass the new input data to the engine. + core.input_ = core.engine_.put_input(core.input_); + + // Try the operation again. + continue; + + case engine::want_output_and_retry: + + // Get output data from the engine and write it to the underlying + // transport. + asio::write(next_layer, + core.engine_.get_output(core.output_buffer_), ec); + + // Try the operation again. + continue; + + case engine::want_output: + + // Get output data from the engine and write it to the underlying + // transport. + asio::write(next_layer, + core.engine_.get_output(core.output_buffer_), ec); + + // Operation is complete. Return result to caller. + core.engine_.map_error_code(ec); + return bytes_transferred; + + default: + + // Operation is complete. Return result to caller. + core.engine_.map_error_code(ec); + return bytes_transferred; + + } while (!ec); + + // Operation failed. Return result to caller. + core.engine_.map_error_code(ec); + return 0; +} + +template <typename Stream, typename Operation, typename Handler> +class io_op +{ +public: + io_op(Stream& next_layer, stream_core& core, + const Operation& op, Handler& handler) + : next_layer_(next_layer), + core_(core), + op_(op), + start_(0), + want_(engine::want_nothing), + bytes_transferred_(0), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + io_op(const io_op& other) + : next_layer_(other.next_layer_), + core_(other.core_), + op_(other.op_), + start_(other.start_), + want_(other.want_), + ec_(other.ec_), + bytes_transferred_(other.bytes_transferred_), + handler_(other.handler_) + { + } + + io_op(io_op&& other) + : next_layer_(other.next_layer_), + core_(other.core_), + op_(ASIO_MOVE_CAST(Operation)(other.op_)), + start_(other.start_), + want_(other.want_), + ec_(other.ec_), + bytes_transferred_(other.bytes_transferred_), + handler_(ASIO_MOVE_CAST(Handler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(asio::error_code ec, + std::size_t bytes_transferred = ~std::size_t(0), int start = 0) + { + switch (start_ = start) + { + case 1: // Called after at least one async operation. + do + { + switch (want_ = op_(core_.engine_, ec_, bytes_transferred_)) + { + case engine::want_input_and_retry: + + // If the input buffer already has data in it we can pass it to the + // engine and then retry the operation immediately. + if (core_.input_.size() != 0) + { + core_.input_ = core_.engine_.put_input(core_.input_); + continue; + } + + // The engine wants more data to be read from input. However, we + // cannot allow more than one read operation at a time on the + // underlying transport. The pending_read_ timer's expiry is set to + // pos_infin if a read is in progress, and neg_infin otherwise. + if (core_.expiry(core_.pending_read_) == core_.neg_infin()) + { + // Prevent other read operations from being started. + core_.pending_read_.expires_at(core_.pos_infin()); + + // Start reading some data from the underlying transport. + next_layer_.async_read_some( + asio::buffer(core_.input_buffer_), + ASIO_MOVE_CAST(io_op)(*this)); + } + else + { + // Wait until the current read operation completes. + core_.pending_read_.async_wait(ASIO_MOVE_CAST(io_op)(*this)); + } + + // Yield control until asynchronous operation completes. Control + // resumes at the "default:" label below. + return; + + case engine::want_output_and_retry: + case engine::want_output: + + // The engine wants some data to be written to the output. However, we + // cannot allow more than one write operation at a time on the + // underlying transport. The pending_write_ timer's expiry is set to + // pos_infin if a write is in progress, and neg_infin otherwise. + if (core_.expiry(core_.pending_write_) == core_.neg_infin()) + { + // Prevent other write operations from being started. + core_.pending_write_.expires_at(core_.pos_infin()); + + // Start writing all the data to the underlying transport. + asio::async_write(next_layer_, + core_.engine_.get_output(core_.output_buffer_), + ASIO_MOVE_CAST(io_op)(*this)); + } + else + { + // Wait until the current write operation completes. + core_.pending_write_.async_wait(ASIO_MOVE_CAST(io_op)(*this)); + } + + // Yield control until asynchronous operation completes. Control + // resumes at the "default:" label below. + return; + + default: + + // The SSL operation is done and we can invoke the handler, but we + // have to keep in mind that this function might be being called from + // the async operation's initiating function. In this case we're not + // allowed to call the handler directly. Instead, issue a zero-sized + // read so the handler runs "as-if" posted using io_context::post(). + if (start) + { + next_layer_.async_read_some( + asio::buffer(core_.input_buffer_, 0), + ASIO_MOVE_CAST(io_op)(*this)); + + // Yield control until asynchronous operation completes. Control + // resumes at the "default:" label below. + return; + } + else + { + // Continue on to run handler directly. + break; + } + } + + default: + if (bytes_transferred == ~std::size_t(0)) + bytes_transferred = 0; // Timer cancellation, no data transferred. + else if (!ec_) + ec_ = ec; + + switch (want_) + { + case engine::want_input_and_retry: + + // Add received data to the engine's input. + core_.input_ = asio::buffer( + core_.input_buffer_, bytes_transferred); + core_.input_ = core_.engine_.put_input(core_.input_); + + // Release any waiting read operations. + core_.pending_read_.expires_at(core_.neg_infin()); + + // Try the operation again. + continue; + + case engine::want_output_and_retry: + + // Release any waiting write operations. + core_.pending_write_.expires_at(core_.neg_infin()); + + // Try the operation again. + continue; + + case engine::want_output: + + // Release any waiting write operations. + core_.pending_write_.expires_at(core_.neg_infin()); + + // Fall through to call handler. + + default: + + // Pass the result to the handler. + op_.call_handler(handler_, + core_.engine_.map_error_code(ec_), + ec_ ? 0 : bytes_transferred_); + + // Our work here is done. + return; + } + } while (!ec_); + + // Operation failed. Pass the result to the handler. + op_.call_handler(handler_, core_.engine_.map_error_code(ec_), 0); + } + } + +//private: + Stream& next_layer_; + stream_core& core_; + Operation op_; + int start_; + engine::want want_; + asio::error_code ec_; + std::size_t bytes_transferred_; + Handler handler_; +}; + +template <typename Stream, typename Operation, typename Handler> +inline void* asio_handler_allocate(std::size_t size, + io_op<Stream, Operation, Handler>* this_handler) +{ + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template <typename Stream, typename Operation, typename Handler> +inline void asio_handler_deallocate(void* pointer, std::size_t size, + io_op<Stream, Operation, Handler>* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template <typename Stream, typename Operation, typename Handler> +inline bool asio_handler_is_continuation( + io_op<Stream, Operation, Handler>* this_handler) +{ + return this_handler->start_ == 0 ? true + : asio_handler_cont_helpers::is_continuation(this_handler->handler_); +} + +template <typename Function, typename Stream, + typename Operation, typename Handler> +inline void asio_handler_invoke(Function& function, + io_op<Stream, Operation, Handler>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template <typename Function, typename Stream, + typename Operation, typename Handler> +inline void asio_handler_invoke(const Function& function, + io_op<Stream, Operation, Handler>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template <typename Stream, typename Operation, typename Handler> +inline void async_io(Stream& next_layer, stream_core& core, + const Operation& op, Handler& handler) +{ + io_op<Stream, Operation, Handler>( + next_layer, core, op, handler)( + asio::error_code(), 0, 1); +} + +} // namespace detail +} // namespace ssl + +template <typename Stream, typename Operation, + typename Handler, typename Allocator> +struct associated_allocator< + ssl::detail::io_op<Stream, Operation, Handler>, Allocator> +{ + typedef typename associated_allocator<Handler, Allocator>::type type; + + static type get(const ssl::detail::io_op<Stream, Operation, Handler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<Handler, Allocator>::get(h.handler_, a); + } +}; + +template <typename Stream, typename Operation, + typename Handler, typename Executor> +struct associated_executor< + ssl::detail::io_op<Stream, Operation, Handler>, Executor> +{ + typedef typename associated_executor<Handler, Executor>::type type; + + static type get(const ssl::detail::io_op<Stream, Operation, Handler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<Handler, Executor>::get(h.handler_, ex); + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_IO_HPP diff --git a/lib/asio/ssl/detail/openssl_init.hpp b/lib/asio/ssl/detail/openssl_init.hpp new file mode 100644 index 0000000..c3e4727 --- /dev/null +++ b/lib/asio/ssl/detail/openssl_init.hpp @@ -0,0 +1,101 @@ +// +// ssl/detail/openssl_init.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_OPENSSL_INIT_HPP +#define ASIO_SSL_DETAIL_OPENSSL_INIT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <cstring> +#include "asio/detail/memory.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/ssl/detail/openssl_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +class openssl_init_base + : private noncopyable +{ +protected: + // Class that performs the actual initialisation. + class do_init; + + // Helper function to manage a do_init singleton. The static instance of the + // openssl_init object ensures that this function is always called before + // main, and therefore before any other threads can get started. The do_init + // instance must be static in this function to ensure that it gets + // initialised before any other global objects try to use it. + ASIO_DECL static asio::detail::shared_ptr<do_init> instance(); + +#if !defined(SSL_OP_NO_COMPRESSION) \ + && (OPENSSL_VERSION_NUMBER >= 0x00908000L) + // Get an empty stack of compression methods, to be used when disabling + // compression. + ASIO_DECL static STACK_OF(SSL_COMP)* get_null_compression_methods(); +#endif // !defined(SSL_OP_NO_COMPRESSION) + // && (OPENSSL_VERSION_NUMBER >= 0x00908000L) +}; + +template <bool Do_Init = true> +class openssl_init : private openssl_init_base +{ +public: + // Constructor. + openssl_init() + : ref_(instance()) + { + using namespace std; // For memmove. + + // Ensure openssl_init::instance_ is linked in. + openssl_init* tmp = &instance_; + memmove(&tmp, &tmp, sizeof(openssl_init*)); + } + + // Destructor. + ~openssl_init() + { + } + +#if !defined(SSL_OP_NO_COMPRESSION) \ + && (OPENSSL_VERSION_NUMBER >= 0x00908000L) + using openssl_init_base::get_null_compression_methods; +#endif // !defined(SSL_OP_NO_COMPRESSION) + // && (OPENSSL_VERSION_NUMBER >= 0x00908000L) + +private: + // Instance to force initialisation of openssl at global scope. + static openssl_init instance_; + + // Reference to singleton do_init object to ensure that openssl does not get + // cleaned up until the last user has finished with it. + asio::detail::shared_ptr<do_init> ref_; +}; + +template <bool Do_Init> +openssl_init<Do_Init> openssl_init<Do_Init>::instance_; + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/ssl/detail/impl/openssl_init.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_SSL_DETAIL_OPENSSL_INIT_HPP diff --git a/lib/asio/ssl/detail/openssl_types.hpp b/lib/asio/ssl/detail/openssl_types.hpp new file mode 100644 index 0000000..a044af3 --- /dev/null +++ b/lib/asio/ssl/detail/openssl_types.hpp @@ -0,0 +1,30 @@ +// +// ssl/detail/openssl_types.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP +#define ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/socket_types.hpp" +#include <openssl/conf.h> +#include <openssl/ssl.h> +#if !defined(OPENSSL_NO_ENGINE) +# include <openssl/engine.h> +#endif // !defined(OPENSSL_NO_ENGINE) +#include <openssl/dh.h> +#include <openssl/err.h> +#include <openssl/rsa.h> +#include <openssl/x509v3.h> + +#endif // ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP diff --git a/lib/asio/ssl/detail/password_callback.hpp b/lib/asio/ssl/detail/password_callback.hpp new file mode 100644 index 0000000..9b1dbee --- /dev/null +++ b/lib/asio/ssl/detail/password_callback.hpp @@ -0,0 +1,66 @@ +// +// ssl/detail/password_callback.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_PASSWORD_CALLBACK_HPP +#define ASIO_SSL_DETAIL_PASSWORD_CALLBACK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include <cstddef> +#include <string> +#include "asio/ssl/context_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +class password_callback_base +{ +public: + virtual ~password_callback_base() + { + } + + virtual std::string call(std::size_t size, + context_base::password_purpose purpose) = 0; +}; + +template <typename PasswordCallback> +class password_callback : public password_callback_base +{ +public: + explicit password_callback(PasswordCallback callback) + : callback_(callback) + { + } + + virtual std::string call(std::size_t size, + context_base::password_purpose purpose) + { + return callback_(size, purpose); + } + +private: + PasswordCallback callback_; +}; + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_PASSWORD_CALLBACK_HPP diff --git a/lib/asio/ssl/detail/read_op.hpp b/lib/asio/ssl/detail/read_op.hpp new file mode 100644 index 0000000..b0d6de2 --- /dev/null +++ b/lib/asio/ssl/detail/read_op.hpp @@ -0,0 +1,67 @@ +// +// ssl/detail/read_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_READ_OP_HPP +#define ASIO_SSL_DETAIL_READ_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/ssl/detail/engine.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +template <typename MutableBufferSequence> +class read_op +{ +public: + read_op(const MutableBufferSequence& buffers) + : buffers_(buffers) + { + } + + engine::want operator()(engine& eng, + asio::error_code& ec, + std::size_t& bytes_transferred) const + { + asio::mutable_buffer buffer = + asio::detail::buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::first(buffers_); + + return eng.read(buffer, ec, bytes_transferred); + } + + template <typename Handler> + void call_handler(Handler& handler, + const asio::error_code& ec, + const std::size_t& bytes_transferred) const + { + handler(ec, bytes_transferred); + } + +private: + MutableBufferSequence buffers_; +}; + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_READ_OP_HPP diff --git a/lib/asio/ssl/detail/shutdown_op.hpp b/lib/asio/ssl/detail/shutdown_op.hpp new file mode 100644 index 0000000..d20b430 --- /dev/null +++ b/lib/asio/ssl/detail/shutdown_op.hpp @@ -0,0 +1,54 @@ +// +// ssl/detail/shutdown_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_SHUTDOWN_OP_HPP +#define ASIO_SSL_DETAIL_SHUTDOWN_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/ssl/detail/engine.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +class shutdown_op +{ +public: + engine::want operator()(engine& eng, + asio::error_code& ec, + std::size_t& bytes_transferred) const + { + bytes_transferred = 0; + return eng.shutdown(ec); + } + + template <typename Handler> + void call_handler(Handler& handler, + const asio::error_code& ec, + const std::size_t&) const + { + handler(ec); + } +}; + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_SHUTDOWN_OP_HPP diff --git a/lib/asio/ssl/detail/stream_core.hpp b/lib/asio/ssl/detail/stream_core.hpp new file mode 100644 index 0000000..13fde74 --- /dev/null +++ b/lib/asio/ssl/detail/stream_core.hpp @@ -0,0 +1,134 @@ +// +// ssl/detail/stream_core.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_STREAM_CORE_HPP +#define ASIO_SSL_DETAIL_STREAM_CORE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_BOOST_DATE_TIME) +# include "asio/deadline_timer.hpp" +#else // defined(ASIO_HAS_BOOST_DATE_TIME) +# include "asio/steady_timer.hpp" +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) +#include "asio/ssl/detail/engine.hpp" +#include "asio/buffer.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +struct stream_core +{ + // According to the OpenSSL documentation, this is the buffer size that is + // sufficient to hold the largest possible TLS record. + enum { max_tls_record_size = 17 * 1024 }; + + stream_core(SSL_CTX* context, asio::io_context& io_context) + : engine_(context), + pending_read_(io_context), + pending_write_(io_context), + output_buffer_space_(max_tls_record_size), + output_buffer_(asio::buffer(output_buffer_space_)), + input_buffer_space_(max_tls_record_size), + input_buffer_(asio::buffer(input_buffer_space_)) + { + pending_read_.expires_at(neg_infin()); + pending_write_.expires_at(neg_infin()); + } + + ~stream_core() + { + } + + // The SSL engine. + engine engine_; + +#if defined(ASIO_HAS_BOOST_DATE_TIME) + // Timer used for storing queued read operations. + asio::deadline_timer pending_read_; + + // Timer used for storing queued write operations. + asio::deadline_timer pending_write_; + + // Helper function for obtaining a time value that always fires. + static asio::deadline_timer::time_type neg_infin() + { + return boost::posix_time::neg_infin; + } + + // Helper function for obtaining a time value that never fires. + static asio::deadline_timer::time_type pos_infin() + { + return boost::posix_time::pos_infin; + } + + // Helper function to get a timer's expiry time. + static asio::deadline_timer::time_type expiry( + const asio::deadline_timer& timer) + { + return timer.expires_at(); + } +#else // defined(ASIO_HAS_BOOST_DATE_TIME) + // Timer used for storing queued read operations. + asio::steady_timer pending_read_; + + // Timer used for storing queued write operations. + asio::steady_timer pending_write_; + + // Helper function for obtaining a time value that always fires. + static asio::steady_timer::time_point neg_infin() + { + return (asio::steady_timer::time_point::min)(); + } + + // Helper function for obtaining a time value that never fires. + static asio::steady_timer::time_point pos_infin() + { + return (asio::steady_timer::time_point::max)(); + } + + // Helper function to get a timer's expiry time. + static asio::steady_timer::time_point expiry( + const asio::steady_timer& timer) + { + return timer.expiry(); + } +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + + // Buffer space used to prepare output intended for the transport. + std::vector<unsigned char> output_buffer_space_; + + // A buffer that may be used to prepare output intended for the transport. + const asio::mutable_buffer output_buffer_; + + // Buffer space used to read input intended for the engine. + std::vector<unsigned char> input_buffer_space_; + + // A buffer that may be used to read input intended for the engine. + const asio::mutable_buffer input_buffer_; + + // The buffer pointing to the engine's unconsumed input. + asio::const_buffer input_; +}; + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_STREAM_CORE_HPP diff --git a/lib/asio/ssl/detail/verify_callback.hpp b/lib/asio/ssl/detail/verify_callback.hpp new file mode 100644 index 0000000..1c56a27 --- /dev/null +++ b/lib/asio/ssl/detail/verify_callback.hpp @@ -0,0 +1,62 @@ +// +// ssl/detail/verify_callback.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_VERIFY_CALLBACK_HPP +#define ASIO_SSL_DETAIL_VERIFY_CALLBACK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/ssl/verify_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +class verify_callback_base +{ +public: + virtual ~verify_callback_base() + { + } + + virtual bool call(bool preverified, verify_context& ctx) = 0; +}; + +template <typename VerifyCallback> +class verify_callback : public verify_callback_base +{ +public: + explicit verify_callback(VerifyCallback callback) + : callback_(callback) + { + } + + virtual bool call(bool preverified, verify_context& ctx) + { + return callback_(preverified, ctx); + } + +private: + VerifyCallback callback_; +}; + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_VERIFY_CALLBACK_HPP diff --git a/lib/asio/ssl/detail/write_op.hpp b/lib/asio/ssl/detail/write_op.hpp new file mode 100644 index 0000000..1d341c0 --- /dev/null +++ b/lib/asio/ssl/detail/write_op.hpp @@ -0,0 +1,67 @@ +// +// ssl/detail/write_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_DETAIL_WRITE_OP_HPP +#define ASIO_SSL_DETAIL_WRITE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/ssl/detail/engine.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { +namespace detail { + +template <typename ConstBufferSequence> +class write_op +{ +public: + write_op(const ConstBufferSequence& buffers) + : buffers_(buffers) + { + } + + engine::want operator()(engine& eng, + asio::error_code& ec, + std::size_t& bytes_transferred) const + { + asio::const_buffer buffer = + asio::detail::buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence>::first(buffers_); + + return eng.write(buffer, ec, bytes_transferred); + } + + template <typename Handler> + void call_handler(Handler& handler, + const asio::error_code& ec, + const std::size_t& bytes_transferred) const + { + handler(ec, bytes_transferred); + } + +private: + ConstBufferSequence buffers_; +}; + +} // namespace detail +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_DETAIL_WRITE_OP_HPP diff --git a/lib/asio/ssl/error.hpp b/lib/asio/ssl/error.hpp new file mode 100644 index 0000000..6165c5c --- /dev/null +++ b/lib/asio/ssl/error.hpp @@ -0,0 +1,111 @@ +// +// ssl/error.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_ERROR_HPP +#define ASIO_SSL_ERROR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/error_code.hpp" +#include "asio/ssl/detail/openssl_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace error { + +enum ssl_errors +{ + // Error numbers are those produced by openssl. +}; + +extern ASIO_DECL +const asio::error_category& get_ssl_category(); + +static const asio::error_category& + ssl_category ASIO_UNUSED_VARIABLE + = asio::error::get_ssl_category(); + +} // namespace error +namespace ssl { +namespace error { + +enum stream_errors +{ +#if defined(GENERATING_DOCUMENTATION) + /// The underlying stream closed before the ssl stream gracefully shut down. + stream_truncated +#elif (OPENSSL_VERSION_NUMBER < 0x10100000L) && !defined(OPENSSL_IS_BORINGSSL) + stream_truncated = ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ) +#else + stream_truncated = 1 +#endif +}; + +extern ASIO_DECL +const asio::error_category& get_stream_category(); + +static const asio::error_category& + stream_category ASIO_UNUSED_VARIABLE + = asio::ssl::error::get_stream_category(); + +} // namespace error +} // namespace ssl +} // namespace asio + +#if defined(ASIO_HAS_STD_SYSTEM_ERROR) +namespace std { + +template<> struct is_error_code_enum<asio::error::ssl_errors> +{ + static const bool value = true; +}; + +template<> struct is_error_code_enum<asio::ssl::error::stream_errors> +{ + static const bool value = true; +}; + +} // namespace std +#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR) + +namespace asio { +namespace error { + +inline asio::error_code make_error_code(ssl_errors e) +{ + return asio::error_code( + static_cast<int>(e), get_ssl_category()); +} + +} // namespace error +namespace ssl { +namespace error { + +inline asio::error_code make_error_code(stream_errors e) +{ + return asio::error_code( + static_cast<int>(e), get_stream_category()); +} + +} // namespace error +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/ssl/impl/error.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_SSL_ERROR_HPP diff --git a/lib/asio/ssl/impl/context.hpp b/lib/asio/ssl/impl/context.hpp new file mode 100644 index 0000000..40199c1 --- /dev/null +++ b/lib/asio/ssl/impl/context.hpp @@ -0,0 +1,67 @@ +// +// ssl/impl/context.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com +// Copyright (c) 2005-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_IMPL_CONTEXT_HPP +#define ASIO_SSL_IMPL_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { + +template <typename VerifyCallback> +void context::set_verify_callback(VerifyCallback callback) +{ + asio::error_code ec; + this->set_verify_callback(callback, ec); + asio::detail::throw_error(ec, "set_verify_callback"); +} + +template <typename VerifyCallback> +ASIO_SYNC_OP_VOID context::set_verify_callback( + VerifyCallback callback, asio::error_code& ec) +{ + do_set_verify_callback( + new detail::verify_callback<VerifyCallback>(callback), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +template <typename PasswordCallback> +void context::set_password_callback(PasswordCallback callback) +{ + asio::error_code ec; + this->set_password_callback(callback, ec); + asio::detail::throw_error(ec, "set_password_callback"); +} + +template <typename PasswordCallback> +ASIO_SYNC_OP_VOID context::set_password_callback( + PasswordCallback callback, asio::error_code& ec) +{ + do_set_password_callback( + new detail::password_callback<PasswordCallback>(callback), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_IMPL_CONTEXT_HPP diff --git a/lib/asio/ssl/impl/context.ipp b/lib/asio/ssl/impl/context.ipp new file mode 100644 index 0000000..b756fd2 --- /dev/null +++ b/lib/asio/ssl/impl/context.ipp @@ -0,0 +1,1159 @@ +// +// ssl/impl/context.ipp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com +// Copyright (c) 2005-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_IMPL_CONTEXT_IPP +#define ASIO_SSL_IMPL_CONTEXT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include <cstring> +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" +#include "asio/ssl/context.hpp" +#include "asio/ssl/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { + +struct context::bio_cleanup +{ + BIO* p; + ~bio_cleanup() { if (p) ::BIO_free(p); } +}; + +struct context::x509_cleanup +{ + X509* p; + ~x509_cleanup() { if (p) ::X509_free(p); } +}; + +struct context::evp_pkey_cleanup +{ + EVP_PKEY* p; + ~evp_pkey_cleanup() { if (p) ::EVP_PKEY_free(p); } +}; + +struct context::rsa_cleanup +{ + RSA* p; + ~rsa_cleanup() { if (p) ::RSA_free(p); } +}; + +struct context::dh_cleanup +{ + DH* p; + ~dh_cleanup() { if (p) ::DH_free(p); } +}; + +context::context(context::method m) + : handle_(0) +{ + ::ERR_clear_error(); + + switch (m) + { + // SSL v2. +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(OPENSSL_NO_SSL2) + case context::sslv2: + case context::sslv2_client: + case context::sslv2_server: + asio::detail::throw_error( + asio::error::invalid_argument, "context"); + break; +#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(OPENSSL_NO_SSL2) + case context::sslv2: + handle_ = ::SSL_CTX_new(::SSLv2_method()); + break; + case context::sslv2_client: + handle_ = ::SSL_CTX_new(::SSLv2_client_method()); + break; + case context::sslv2_server: + handle_ = ::SSL_CTX_new(::SSLv2_server_method()); + break; +#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(OPENSSL_NO_SSL2) + + // SSL v3. +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) + case context::sslv3: + handle_ = ::SSL_CTX_new(::TLS_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, SSL3_VERSION); + SSL_CTX_set_max_proto_version(handle_, SSL3_VERSION); + } + break; + case context::sslv3_client: + handle_ = ::SSL_CTX_new(::TLS_client_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, SSL3_VERSION); + SSL_CTX_set_max_proto_version(handle_, SSL3_VERSION); + } + break; + case context::sslv3_server: + handle_ = ::SSL_CTX_new(::TLS_server_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, SSL3_VERSION); + SSL_CTX_set_max_proto_version(handle_, SSL3_VERSION); + } + break; +#elif defined(OPENSSL_NO_SSL3) + case context::sslv3: + case context::sslv3_client: + case context::sslv3_server: + asio::detail::throw_error( + asio::error::invalid_argument, "context"); + break; +#else // defined(OPENSSL_NO_SSL3) + case context::sslv3: + handle_ = ::SSL_CTX_new(::SSLv3_method()); + break; + case context::sslv3_client: + handle_ = ::SSL_CTX_new(::SSLv3_client_method()); + break; + case context::sslv3_server: + handle_ = ::SSL_CTX_new(::SSLv3_server_method()); + break; +#endif // defined(OPENSSL_NO_SSL3) + + // TLS v1.0. +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) + case context::tlsv1: + handle_ = ::SSL_CTX_new(::TLS_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_VERSION); + } + break; + case context::tlsv1_client: + handle_ = ::SSL_CTX_new(::TLS_client_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_VERSION); + } + break; + case context::tlsv1_server: + handle_ = ::SSL_CTX_new(::TLS_server_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_VERSION); + } + break; +#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) + case context::tlsv1: + handle_ = ::SSL_CTX_new(::TLSv1_method()); + break; + case context::tlsv1_client: + handle_ = ::SSL_CTX_new(::TLSv1_client_method()); + break; + case context::tlsv1_server: + handle_ = ::SSL_CTX_new(::TLSv1_server_method()); + break; +#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) + + // TLS v1.1. +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) + case context::tlsv11: + handle_ = ::SSL_CTX_new(::TLS_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_1_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_1_VERSION); + } + break; + case context::tlsv11_client: + handle_ = ::SSL_CTX_new(::TLS_client_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_1_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_1_VERSION); + } + break; + case context::tlsv11_server: + handle_ = ::SSL_CTX_new(::TLS_server_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_1_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_1_VERSION); + } + break; +#elif defined(SSL_TXT_TLSV1_1) + case context::tlsv11: + handle_ = ::SSL_CTX_new(::TLSv1_1_method()); + break; + case context::tlsv11_client: + handle_ = ::SSL_CTX_new(::TLSv1_1_client_method()); + break; + case context::tlsv11_server: + handle_ = ::SSL_CTX_new(::TLSv1_1_server_method()); + break; +#else // defined(SSL_TXT_TLSV1_1) + case context::tlsv11: + case context::tlsv11_client: + case context::tlsv11_server: + asio::detail::throw_error( + asio::error::invalid_argument, "context"); + break; +#endif // defined(SSL_TXT_TLSV1_1) + + // TLS v1.2. +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) + case context::tlsv12: + handle_ = ::SSL_CTX_new(::TLS_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_2_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_2_VERSION); + } + break; + case context::tlsv12_client: + handle_ = ::SSL_CTX_new(::TLS_client_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_2_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_2_VERSION); + } + break; + case context::tlsv12_server: + handle_ = ::SSL_CTX_new(::TLS_server_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_2_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_2_VERSION); + } + break; +#elif defined(SSL_TXT_TLSV1_1) + case context::tlsv12: + handle_ = ::SSL_CTX_new(::TLSv1_2_method()); + break; + case context::tlsv12_client: + handle_ = ::SSL_CTX_new(::TLSv1_2_client_method()); + break; + case context::tlsv12_server: + handle_ = ::SSL_CTX_new(::TLSv1_2_server_method()); + break; +#else // defined(SSL_TXT_TLSV1_1) + case context::tlsv12: + case context::tlsv12_client: + case context::tlsv12_server: + asio::detail::throw_error( + asio::error::invalid_argument, "context"); + break; +#endif // defined(SSL_TXT_TLSV1_1) + + // Any supported SSL/TLS version. + case context::sslv23: + handle_ = ::SSL_CTX_new(::SSLv23_method()); + break; + case context::sslv23_client: + handle_ = ::SSL_CTX_new(::SSLv23_client_method()); + break; + case context::sslv23_server: + handle_ = ::SSL_CTX_new(::SSLv23_server_method()); + break; + + // Any supported TLS version. +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) + case context::tls: + handle_ = ::SSL_CTX_new(::TLS_method()); + if (handle_) + SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION); + break; + case context::tls_client: + handle_ = ::SSL_CTX_new(::TLS_client_method()); + if (handle_) + SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION); + break; + case context::tls_server: + handle_ = ::SSL_CTX_new(::TLS_server_method()); + if (handle_) + SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION); + break; +#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) + case context::tls: + handle_ = ::SSL_CTX_new(::SSLv23_method()); + if (handle_) + SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + break; + case context::tls_client: + handle_ = ::SSL_CTX_new(::SSLv23_client_method()); + if (handle_) + SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + break; + case context::tls_server: + handle_ = ::SSL_CTX_new(::SSLv23_server_method()); + if (handle_) + SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + break; +#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) + + default: + handle_ = ::SSL_CTX_new(0); + break; + } + + if (handle_ == 0) + { + asio::error_code ec( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + asio::detail::throw_error(ec, "context"); + } + + set_options(no_compression); +} + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) +context::context(context&& other) +{ + handle_ = other.handle_; + other.handle_ = 0; +} + +context& context::operator=(context&& other) +{ + context tmp(ASIO_MOVE_CAST(context)(*this)); + handle_ = other.handle_; + other.handle_ = 0; + return *this; +} +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + +context::~context() +{ + if (handle_) + { +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) + void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_); +#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) + void* cb_userdata = handle_->default_passwd_callback_userdata; +#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) + if (cb_userdata) + { + detail::password_callback_base* callback = + static_cast<detail::password_callback_base*>( + cb_userdata); + delete callback; +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) + ::SSL_CTX_set_default_passwd_cb_userdata(handle_, 0); +#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) + handle_->default_passwd_callback_userdata = 0; +#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) + } + + if (SSL_CTX_get_app_data(handle_)) + { + detail::verify_callback_base* callback = + static_cast<detail::verify_callback_base*>( + SSL_CTX_get_app_data(handle_)); + delete callback; + SSL_CTX_set_app_data(handle_, 0); + } + + ::SSL_CTX_free(handle_); + } +} + +context::native_handle_type context::native_handle() +{ + return handle_; +} + +void context::clear_options(context::options o) +{ + asio::error_code ec; + clear_options(o, ec); + asio::detail::throw_error(ec, "clear_options"); +} + +ASIO_SYNC_OP_VOID context::clear_options( + context::options o, asio::error_code& ec) +{ +#if (OPENSSL_VERSION_NUMBER >= 0x009080DFL) \ + && (OPENSSL_VERSION_NUMBER != 0x00909000L) +# if !defined(SSL_OP_NO_COMPRESSION) + if ((o & context::no_compression) != 0) + { +# if (OPENSSL_VERSION_NUMBER >= 0x00908000L) + handle_->comp_methods = SSL_COMP_get_compression_methods(); +# endif // (OPENSSL_VERSION_NUMBER >= 0x00908000L) + o ^= context::no_compression; + } +# endif // !defined(SSL_OP_NO_COMPRESSION) + + ::SSL_CTX_clear_options(handle_, o); + + ec = asio::error_code(); +#else // (OPENSSL_VERSION_NUMBER >= 0x009080DFL) + // && (OPENSSL_VERSION_NUMBER != 0x00909000L) + (void)o; + ec = asio::error::operation_not_supported; +#endif // (OPENSSL_VERSION_NUMBER >= 0x009080DFL) + // && (OPENSSL_VERSION_NUMBER != 0x00909000L) + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +void context::set_options(context::options o) +{ + asio::error_code ec; + set_options(o, ec); + asio::detail::throw_error(ec, "set_options"); +} + +ASIO_SYNC_OP_VOID context::set_options( + context::options o, asio::error_code& ec) +{ +#if !defined(SSL_OP_NO_COMPRESSION) + if ((o & context::no_compression) != 0) + { +#if (OPENSSL_VERSION_NUMBER >= 0x00908000L) + handle_->comp_methods = + asio::ssl::detail::openssl_init<>::get_null_compression_methods(); +#endif // (OPENSSL_VERSION_NUMBER >= 0x00908000L) + o ^= context::no_compression; + } +#endif // !defined(SSL_OP_NO_COMPRESSION) + + ::SSL_CTX_set_options(handle_, o); + + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +void context::set_verify_mode(verify_mode v) +{ + asio::error_code ec; + set_verify_mode(v, ec); + asio::detail::throw_error(ec, "set_verify_mode"); +} + +ASIO_SYNC_OP_VOID context::set_verify_mode( + verify_mode v, asio::error_code& ec) +{ + ::SSL_CTX_set_verify(handle_, v, ::SSL_CTX_get_verify_callback(handle_)); + + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +void context::set_verify_depth(int depth) +{ + asio::error_code ec; + set_verify_depth(depth, ec); + asio::detail::throw_error(ec, "set_verify_depth"); +} + +ASIO_SYNC_OP_VOID context::set_verify_depth( + int depth, asio::error_code& ec) +{ + ::SSL_CTX_set_verify_depth(handle_, depth); + + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +void context::load_verify_file(const std::string& filename) +{ + asio::error_code ec; + load_verify_file(filename, ec); + asio::detail::throw_error(ec, "load_verify_file"); +} + +ASIO_SYNC_OP_VOID context::load_verify_file( + const std::string& filename, asio::error_code& ec) +{ + ::ERR_clear_error(); + + if (::SSL_CTX_load_verify_locations(handle_, filename.c_str(), 0) != 1) + { + ec = asio::error_code( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +void context::add_certificate_authority(const const_buffer& ca) +{ + asio::error_code ec; + add_certificate_authority(ca, ec); + asio::detail::throw_error(ec, "add_certificate_authority"); +} + +ASIO_SYNC_OP_VOID context::add_certificate_authority( + const const_buffer& ca, asio::error_code& ec) +{ + ::ERR_clear_error(); + + bio_cleanup bio = { make_buffer_bio(ca) }; + if (bio.p) + { + if (X509_STORE* store = ::SSL_CTX_get_cert_store(handle_)) + { + for (;;) + { + x509_cleanup cert = { ::PEM_read_bio_X509(bio.p, 0, 0, 0) }; + if (!cert.p) + break; + + if (::X509_STORE_add_cert(store, cert.p) != 1) + { + ec = asio::error_code( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + } + } + } + + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +void context::set_default_verify_paths() +{ + asio::error_code ec; + set_default_verify_paths(ec); + asio::detail::throw_error(ec, "set_default_verify_paths"); +} + +ASIO_SYNC_OP_VOID context::set_default_verify_paths( + asio::error_code& ec) +{ + ::ERR_clear_error(); + + if (::SSL_CTX_set_default_verify_paths(handle_) != 1) + { + ec = asio::error_code( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +void context::add_verify_path(const std::string& path) +{ + asio::error_code ec; + add_verify_path(path, ec); + asio::detail::throw_error(ec, "add_verify_path"); +} + +ASIO_SYNC_OP_VOID context::add_verify_path( + const std::string& path, asio::error_code& ec) +{ + ::ERR_clear_error(); + + if (::SSL_CTX_load_verify_locations(handle_, 0, path.c_str()) != 1) + { + ec = asio::error_code( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +void context::use_certificate( + const const_buffer& certificate, file_format format) +{ + asio::error_code ec; + use_certificate(certificate, format, ec); + asio::detail::throw_error(ec, "use_certificate"); +} + +ASIO_SYNC_OP_VOID context::use_certificate( + const const_buffer& certificate, file_format format, + asio::error_code& ec) +{ + ::ERR_clear_error(); + + if (format == context_base::asn1) + { + if (::SSL_CTX_use_certificate_ASN1(handle_, + static_cast<int>(certificate.size()), + static_cast<const unsigned char*>(certificate.data())) == 1) + { + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + } + else if (format == context_base::pem) + { + bio_cleanup bio = { make_buffer_bio(certificate) }; + if (bio.p) + { + x509_cleanup cert = { ::PEM_read_bio_X509(bio.p, 0, 0, 0) }; + if (cert.p) + { + if (::SSL_CTX_use_certificate(handle_, cert.p) == 1) + { + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + } + } + } + else + { + ec = asio::error::invalid_argument; + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + ec = asio::error_code( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +void context::use_certificate_file( + const std::string& filename, file_format format) +{ + asio::error_code ec; + use_certificate_file(filename, format, ec); + asio::detail::throw_error(ec, "use_certificate_file"); +} + +ASIO_SYNC_OP_VOID context::use_certificate_file( + const std::string& filename, file_format format, + asio::error_code& ec) +{ + int file_type; + switch (format) + { + case context_base::asn1: + file_type = SSL_FILETYPE_ASN1; + break; + case context_base::pem: + file_type = SSL_FILETYPE_PEM; + break; + default: + { + ec = asio::error::invalid_argument; + ASIO_SYNC_OP_VOID_RETURN(ec); + } + } + + ::ERR_clear_error(); + + if (::SSL_CTX_use_certificate_file(handle_, filename.c_str(), file_type) != 1) + { + ec = asio::error_code( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +void context::use_certificate_chain(const const_buffer& chain) +{ + asio::error_code ec; + use_certificate_chain(chain, ec); + asio::detail::throw_error(ec, "use_certificate_chain"); +} + +ASIO_SYNC_OP_VOID context::use_certificate_chain( + const const_buffer& chain, asio::error_code& ec) +{ + ::ERR_clear_error(); + + bio_cleanup bio = { make_buffer_bio(chain) }; + if (bio.p) + { +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) + pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_); + void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_); +#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) + pem_password_cb* callback = handle_->default_passwd_callback; + void* cb_userdata = handle_->default_passwd_callback_userdata; +#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) + x509_cleanup cert = { + ::PEM_read_bio_X509_AUX(bio.p, 0, + callback, + cb_userdata) }; + if (!cert.p) + { + ec = asio::error_code(ERR_R_PEM_LIB, + asio::error::get_ssl_category()); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + int result = ::SSL_CTX_use_certificate(handle_, cert.p); + if (result == 0 || ::ERR_peek_error() != 0) + { + ec = asio::error_code( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + +#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && !defined(LIBRESSL_VERSION_NUMBER) + ::SSL_CTX_clear_chain_certs(handle_); +#else + if (handle_->extra_certs) + { + ::sk_X509_pop_free(handle_->extra_certs, X509_free); + handle_->extra_certs = 0; + } +#endif // (OPENSSL_VERSION_NUMBER >= 0x10002000L) + + while (X509* cacert = ::PEM_read_bio_X509(bio.p, 0, + callback, + cb_userdata)) + { + if (!::SSL_CTX_add_extra_chain_cert(handle_, cacert)) + { + ec = asio::error_code( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + } + + result = ::ERR_peek_last_error(); + if ((ERR_GET_LIB(result) == ERR_LIB_PEM) + && (ERR_GET_REASON(result) == PEM_R_NO_START_LINE)) + { + ::ERR_clear_error(); + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + } + + ec = asio::error_code( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +void context::use_certificate_chain_file(const std::string& filename) +{ + asio::error_code ec; + use_certificate_chain_file(filename, ec); + asio::detail::throw_error(ec, "use_certificate_chain_file"); +} + +ASIO_SYNC_OP_VOID context::use_certificate_chain_file( + const std::string& filename, asio::error_code& ec) +{ + ::ERR_clear_error(); + + if (::SSL_CTX_use_certificate_chain_file(handle_, filename.c_str()) != 1) + { + ec = asio::error_code( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +void context::use_private_key( + const const_buffer& private_key, context::file_format format) +{ + asio::error_code ec; + use_private_key(private_key, format, ec); + asio::detail::throw_error(ec, "use_private_key"); +} + +ASIO_SYNC_OP_VOID context::use_private_key( + const const_buffer& private_key, context::file_format format, + asio::error_code& ec) +{ + ::ERR_clear_error(); + +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) + pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_); + void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_); +#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) + pem_password_cb* callback = handle_->default_passwd_callback; + void* cb_userdata = handle_->default_passwd_callback_userdata; +#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) + + bio_cleanup bio = { make_buffer_bio(private_key) }; + if (bio.p) + { + evp_pkey_cleanup evp_private_key = { 0 }; + switch (format) + { + case context_base::asn1: + evp_private_key.p = ::d2i_PrivateKey_bio(bio.p, 0); + break; + case context_base::pem: + evp_private_key.p = ::PEM_read_bio_PrivateKey( + bio.p, 0, callback, + cb_userdata); + break; + default: + { + ec = asio::error::invalid_argument; + ASIO_SYNC_OP_VOID_RETURN(ec); + } + } + + if (evp_private_key.p) + { + if (::SSL_CTX_use_PrivateKey(handle_, evp_private_key.p) == 1) + { + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + } + } + + ec = asio::error_code( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +void context::use_private_key_file( + const std::string& filename, context::file_format format) +{ + asio::error_code ec; + use_private_key_file(filename, format, ec); + asio::detail::throw_error(ec, "use_private_key_file"); +} + +void context::use_rsa_private_key( + const const_buffer& private_key, context::file_format format) +{ + asio::error_code ec; + use_rsa_private_key(private_key, format, ec); + asio::detail::throw_error(ec, "use_rsa_private_key"); +} + +ASIO_SYNC_OP_VOID context::use_rsa_private_key( + const const_buffer& private_key, context::file_format format, + asio::error_code& ec) +{ + ::ERR_clear_error(); + +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) + pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_); + void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_); +#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) + pem_password_cb* callback = handle_->default_passwd_callback; + void* cb_userdata = handle_->default_passwd_callback_userdata; +#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) + + bio_cleanup bio = { make_buffer_bio(private_key) }; + if (bio.p) + { + rsa_cleanup rsa_private_key = { 0 }; + switch (format) + { + case context_base::asn1: + rsa_private_key.p = ::d2i_RSAPrivateKey_bio(bio.p, 0); + break; + case context_base::pem: + rsa_private_key.p = ::PEM_read_bio_RSAPrivateKey( + bio.p, 0, callback, + cb_userdata); + break; + default: + { + ec = asio::error::invalid_argument; + ASIO_SYNC_OP_VOID_RETURN(ec); + } + } + + if (rsa_private_key.p) + { + if (::SSL_CTX_use_RSAPrivateKey(handle_, rsa_private_key.p) == 1) + { + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + } + } + + ec = asio::error_code( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +ASIO_SYNC_OP_VOID context::use_private_key_file( + const std::string& filename, context::file_format format, + asio::error_code& ec) +{ + int file_type; + switch (format) + { + case context_base::asn1: + file_type = SSL_FILETYPE_ASN1; + break; + case context_base::pem: + file_type = SSL_FILETYPE_PEM; + break; + default: + { + ec = asio::error::invalid_argument; + ASIO_SYNC_OP_VOID_RETURN(ec); + } + } + + ::ERR_clear_error(); + + if (::SSL_CTX_use_PrivateKey_file(handle_, filename.c_str(), file_type) != 1) + { + ec = asio::error_code( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +void context::use_rsa_private_key_file( + const std::string& filename, context::file_format format) +{ + asio::error_code ec; + use_rsa_private_key_file(filename, format, ec); + asio::detail::throw_error(ec, "use_rsa_private_key_file"); +} + +ASIO_SYNC_OP_VOID context::use_rsa_private_key_file( + const std::string& filename, context::file_format format, + asio::error_code& ec) +{ + int file_type; + switch (format) + { + case context_base::asn1: + file_type = SSL_FILETYPE_ASN1; + break; + case context_base::pem: + file_type = SSL_FILETYPE_PEM; + break; + default: + { + ec = asio::error::invalid_argument; + ASIO_SYNC_OP_VOID_RETURN(ec); + } + } + + ::ERR_clear_error(); + + if (::SSL_CTX_use_RSAPrivateKey_file( + handle_, filename.c_str(), file_type) != 1) + { + ec = asio::error_code( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +void context::use_tmp_dh(const const_buffer& dh) +{ + asio::error_code ec; + use_tmp_dh(dh, ec); + asio::detail::throw_error(ec, "use_tmp_dh"); +} + +ASIO_SYNC_OP_VOID context::use_tmp_dh( + const const_buffer& dh, asio::error_code& ec) +{ + ::ERR_clear_error(); + + bio_cleanup bio = { make_buffer_bio(dh) }; + if (bio.p) + { + return do_use_tmp_dh(bio.p, ec); + } + + ec = asio::error_code( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +void context::use_tmp_dh_file(const std::string& filename) +{ + asio::error_code ec; + use_tmp_dh_file(filename, ec); + asio::detail::throw_error(ec, "use_tmp_dh_file"); +} + +ASIO_SYNC_OP_VOID context::use_tmp_dh_file( + const std::string& filename, asio::error_code& ec) +{ + ::ERR_clear_error(); + + bio_cleanup bio = { ::BIO_new_file(filename.c_str(), "r") }; + if (bio.p) + { + return do_use_tmp_dh(bio.p, ec); + } + + ec = asio::error_code( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +ASIO_SYNC_OP_VOID context::do_use_tmp_dh( + BIO* bio, asio::error_code& ec) +{ + ::ERR_clear_error(); + + dh_cleanup dh = { ::PEM_read_bio_DHparams(bio, 0, 0, 0) }; + if (dh.p) + { + if (::SSL_CTX_set_tmp_dh(handle_, dh.p) == 1) + { + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + } + + ec = asio::error_code( + static_cast<int>(::ERR_get_error()), + asio::error::get_ssl_category()); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +ASIO_SYNC_OP_VOID context::do_set_verify_callback( + detail::verify_callback_base* callback, asio::error_code& ec) +{ + if (SSL_CTX_get_app_data(handle_)) + { + delete static_cast<detail::verify_callback_base*>( + SSL_CTX_get_app_data(handle_)); + } + + SSL_CTX_set_app_data(handle_, callback); + + ::SSL_CTX_set_verify(handle_, + ::SSL_CTX_get_verify_mode(handle_), + &context::verify_callback_function); + + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +int context::verify_callback_function(int preverified, X509_STORE_CTX* ctx) +{ + if (ctx) + { + if (SSL* ssl = static_cast<SSL*>( + ::X509_STORE_CTX_get_ex_data( + ctx, ::SSL_get_ex_data_X509_STORE_CTX_idx()))) + { + if (SSL_CTX* handle = ::SSL_get_SSL_CTX(ssl)) + { + if (SSL_CTX_get_app_data(handle)) + { + detail::verify_callback_base* callback = + static_cast<detail::verify_callback_base*>( + SSL_CTX_get_app_data(handle)); + + verify_context verify_ctx(ctx); + return callback->call(preverified != 0, verify_ctx) ? 1 : 0; + } + } + } + } + + return 0; +} + +ASIO_SYNC_OP_VOID context::do_set_password_callback( + detail::password_callback_base* callback, asio::error_code& ec) +{ +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) + void* old_callback = ::SSL_CTX_get_default_passwd_cb_userdata(handle_); + ::SSL_CTX_set_default_passwd_cb_userdata(handle_, callback); +#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) + void* old_callback = handle_->default_passwd_callback_userdata; + handle_->default_passwd_callback_userdata = callback; +#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) + + if (old_callback) + delete static_cast<detail::password_callback_base*>( + old_callback); + + SSL_CTX_set_default_passwd_cb(handle_, &context::password_callback_function); + + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +int context::password_callback_function( + char* buf, int size, int purpose, void* data) +{ + using namespace std; // For strncat and strlen. + + if (data) + { + detail::password_callback_base* callback = + static_cast<detail::password_callback_base*>(data); + + std::string passwd = callback->call(static_cast<std::size_t>(size), + purpose ? context_base::for_writing : context_base::for_reading); + +#if defined(ASIO_HAS_SECURE_RTL) + strcpy_s(buf, size, passwd.c_str()); +#else // defined(ASIO_HAS_SECURE_RTL) + *buf = '\0'; + if (size > 0) + strncat(buf, passwd.c_str(), size - 1); +#endif // defined(ASIO_HAS_SECURE_RTL) + + return static_cast<int>(strlen(buf)); + } + + return 0; +} + +BIO* context::make_buffer_bio(const const_buffer& b) +{ + return ::BIO_new_mem_buf( + const_cast<void*>(b.data()), + static_cast<int>(b.size())); +} + +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_IMPL_CONTEXT_IPP diff --git a/lib/asio/ssl/impl/error.ipp b/lib/asio/ssl/impl/error.ipp new file mode 100644 index 0000000..98e8c91 --- /dev/null +++ b/lib/asio/ssl/impl/error.ipp @@ -0,0 +1,100 @@ +// +// ssl/impl/error.ipp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_IMPL_ERROR_IPP +#define ASIO_SSL_IMPL_ERROR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/ssl/error.hpp" +#include "asio/ssl/detail/openssl_init.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace error { +namespace detail { + +class ssl_category : public asio::error_category +{ +public: + const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT + { + return "asio.ssl"; + } + + std::string message(int value) const + { + const char* s = ::ERR_reason_error_string(value); + return s ? s : "asio.ssl error"; + } +}; + +} // namespace detail + +const asio::error_category& get_ssl_category() +{ + static detail::ssl_category instance; + return instance; +} + +} // namespace error +namespace ssl { +namespace error { + +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) && !defined(OPENSSL_IS_BORINGSSL) + +const asio::error_category& get_stream_category() +{ + return asio::error::get_ssl_category(); +} + +#else + +namespace detail { + +class stream_category : public asio::error_category +{ +public: + const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT + { + return "asio.ssl.stream"; + } + + std::string message(int value) const + { + switch (value) + { + case stream_truncated: return "stream truncated"; + default: return "asio.ssl.stream error"; + } + } +}; + +} // namespace detail + +const asio::error_category& get_stream_category() +{ + static detail::stream_category instance; + return instance; +} + +#endif + +} // namespace error +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_IMPL_ERROR_IPP diff --git a/lib/asio/ssl/impl/rfc2818_verification.ipp b/lib/asio/ssl/impl/rfc2818_verification.ipp new file mode 100644 index 0000000..577e4a1 --- /dev/null +++ b/lib/asio/ssl/impl/rfc2818_verification.ipp @@ -0,0 +1,160 @@ +// +// ssl/impl/rfc2818_verification.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_IMPL_RFC2818_VERIFICATION_IPP +#define ASIO_SSL_IMPL_RFC2818_VERIFICATION_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include <cctype> +#include <cstring> +#include "asio/ip/address.hpp" +#include "asio/ssl/rfc2818_verification.hpp" +#include "asio/ssl/detail/openssl_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { + +bool rfc2818_verification::operator()( + bool preverified, verify_context& ctx) const +{ + using namespace std; // For memcmp. + + // Don't bother looking at certificates that have failed pre-verification. + if (!preverified) + return false; + + // We're only interested in checking the certificate at the end of the chain. + int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle()); + if (depth > 0) + return true; + + // Try converting the host name to an address. If it is an address then we + // need to look for an IP address in the certificate rather than a host name. + asio::error_code ec; + ip::address address = ip::make_address(host_, ec); + bool is_address = !ec; + + X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); + + // Go through the alternate names in the certificate looking for matching DNS + // or IP address entries. + GENERAL_NAMES* gens = static_cast<GENERAL_NAMES*>( + X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0)); + for (int i = 0; i < sk_GENERAL_NAME_num(gens); ++i) + { + GENERAL_NAME* gen = sk_GENERAL_NAME_value(gens, i); + if (gen->type == GEN_DNS && !is_address) + { + ASN1_IA5STRING* domain = gen->d.dNSName; + if (domain->type == V_ASN1_IA5STRING && domain->data && domain->length) + { + const char* pattern = reinterpret_cast<const char*>(domain->data); + std::size_t pattern_length = domain->length; + if (match_pattern(pattern, pattern_length, host_.c_str())) + { + GENERAL_NAMES_free(gens); + return true; + } + } + } + else if (gen->type == GEN_IPADD && is_address) + { + ASN1_OCTET_STRING* ip_address = gen->d.iPAddress; + if (ip_address->type == V_ASN1_OCTET_STRING && ip_address->data) + { + if (address.is_v4() && ip_address->length == 4) + { + ip::address_v4::bytes_type bytes = address.to_v4().to_bytes(); + if (memcmp(bytes.data(), ip_address->data, 4) == 0) + { + GENERAL_NAMES_free(gens); + return true; + } + } + else if (address.is_v6() && ip_address->length == 16) + { + ip::address_v6::bytes_type bytes = address.to_v6().to_bytes(); + if (memcmp(bytes.data(), ip_address->data, 16) == 0) + { + GENERAL_NAMES_free(gens); + return true; + } + } + } + } + } + GENERAL_NAMES_free(gens); + + // No match in the alternate names, so try the common names. We should only + // use the "most specific" common name, which is the last one in the list. + X509_NAME* name = X509_get_subject_name(cert); + int i = -1; + ASN1_STRING* common_name = 0; + while ((i = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0) + { + X509_NAME_ENTRY* name_entry = X509_NAME_get_entry(name, i); + common_name = X509_NAME_ENTRY_get_data(name_entry); + } + if (common_name && common_name->data && common_name->length) + { + const char* pattern = reinterpret_cast<const char*>(common_name->data); + std::size_t pattern_length = common_name->length; + if (match_pattern(pattern, pattern_length, host_.c_str())) + return true; + } + + return false; +} + +bool rfc2818_verification::match_pattern(const char* pattern, + std::size_t pattern_length, const char* host) +{ + using namespace std; // For tolower. + + const char* p = pattern; + const char* p_end = p + pattern_length; + const char* h = host; + + while (p != p_end && *h) + { + if (*p == '*') + { + ++p; + while (*h && *h != '.') + if (match_pattern(p, p_end - p, h++)) + return true; + } + else if (tolower(*p) == tolower(*h)) + { + ++p; + ++h; + } + else + { + return false; + } + } + + return p == p_end && !*h; +} + +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_IMPL_RFC2818_VERIFICATION_IPP diff --git a/lib/asio/ssl/impl/src.hpp b/lib/asio/ssl/impl/src.hpp new file mode 100644 index 0000000..9a1b038 --- /dev/null +++ b/lib/asio/ssl/impl/src.hpp @@ -0,0 +1,28 @@ +// +// impl/ssl/src.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_IMPL_SRC_HPP +#define ASIO_SSL_IMPL_SRC_HPP + +#define ASIO_SOURCE + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HEADER_ONLY) +# error Do not compile Asio library source with ASIO_HEADER_ONLY defined +#endif + +#include "asio/ssl/impl/context.ipp" +#include "asio/ssl/impl/error.ipp" +#include "asio/ssl/detail/impl/engine.ipp" +#include "asio/ssl/detail/impl/openssl_init.ipp" +#include "asio/ssl/impl/rfc2818_verification.ipp" + +#endif // ASIO_SSL_IMPL_SRC_HPP diff --git a/lib/asio/ssl/rfc2818_verification.hpp b/lib/asio/ssl/rfc2818_verification.hpp new file mode 100644 index 0000000..3589f53 --- /dev/null +++ b/lib/asio/ssl/rfc2818_verification.hpp @@ -0,0 +1,94 @@ +// +// ssl/rfc2818_verification.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_RFC2818_VERIFICATION_HPP +#define ASIO_SSL_RFC2818_VERIFICATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include <string> +#include "asio/ssl/detail/openssl_types.hpp" +#include "asio/ssl/verify_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { + +/// Verifies a certificate against a hostname according to the rules described +/// in RFC 2818. +/** + * @par Example + * The following example shows how to synchronously open a secure connection to + * a given host name: + * @code + * using asio::ip::tcp; + * namespace ssl = asio::ssl; + * typedef ssl::stream<tcp::socket> ssl_socket; + * + * // Create a context that uses the default paths for finding CA certificates. + * ssl::context ctx(ssl::context::sslv23); + * ctx.set_default_verify_paths(); + * + * // Open a socket and connect it to the remote host. + * asio::io_context io_context; + * ssl_socket sock(io_context, ctx); + * tcp::resolver resolver(io_context); + * tcp::resolver::query query("host.name", "https"); + * asio::connect(sock.lowest_layer(), resolver.resolve(query)); + * sock.lowest_layer().set_option(tcp::no_delay(true)); + * + * // Perform SSL handshake and verify the remote host's certificate. + * sock.set_verify_mode(ssl::verify_peer); + * sock.set_verify_callback(ssl::rfc2818_verification("host.name")); + * sock.handshake(ssl_socket::client); + * + * // ... read and write as normal ... + * @endcode + */ +class rfc2818_verification +{ +public: + /// The type of the function object's result. + typedef bool result_type; + + /// Constructor. + explicit rfc2818_verification(const std::string& host) + : host_(host) + { + } + + /// Perform certificate verification. + ASIO_DECL bool operator()(bool preverified, verify_context& ctx) const; + +private: + // Helper function to check a host name against a pattern. + ASIO_DECL static bool match_pattern(const char* pattern, + std::size_t pattern_length, const char* host); + + // Helper function to check a host name against an IPv4 address + // The host name to be checked. + std::string host_; +}; + +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/ssl/impl/rfc2818_verification.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_SSL_RFC2818_VERIFICATION_HPP diff --git a/lib/asio/ssl/stream.hpp b/lib/asio/ssl/stream.hpp new file mode 100644 index 0000000..2b221ed --- /dev/null +++ b/lib/asio/ssl/stream.hpp @@ -0,0 +1,761 @@ +// +// ssl/stream.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_STREAM_HPP +#define ASIO_SSL_STREAM_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/async_result.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/ssl/context.hpp" +#include "asio/ssl/detail/buffered_handshake_op.hpp" +#include "asio/ssl/detail/handshake_op.hpp" +#include "asio/ssl/detail/io.hpp" +#include "asio/ssl/detail/read_op.hpp" +#include "asio/ssl/detail/shutdown_op.hpp" +#include "asio/ssl/detail/stream_core.hpp" +#include "asio/ssl/detail/write_op.hpp" +#include "asio/ssl/stream_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { + +/// Provides stream-oriented functionality using SSL. +/** + * The stream class template provides asynchronous and blocking stream-oriented + * functionality using SSL. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. The application must also ensure that all + * asynchronous operations are performed within the same implicit or explicit + * strand. + * + * @par Example + * To use the SSL stream template with an ip::tcp::socket, you would write: + * @code + * asio::io_context io_context; + * asio::ssl::context ctx(asio::ssl::context::sslv23); + * asio::ssl::stream<asio:ip::tcp::socket> sock(io_context, ctx); + * @endcode + * + * @par Concepts: + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. + */ +template <typename Stream> +class stream : + public stream_base, + private noncopyable +{ +public: + /// The native handle type of the SSL stream. + typedef SSL* native_handle_type; + + /// Structure for use with deprecated impl_type. + struct impl_struct + { + SSL* ssl; + }; + + /// The type of the next layer. + typedef typename remove_reference<Stream>::type next_layer_type; + + /// The type of the lowest layer. + typedef typename next_layer_type::lowest_layer_type lowest_layer_type; + + /// The type of the executor associated with the object. + typedef typename lowest_layer_type::executor_type executor_type; + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Construct a stream. + /** + * This constructor creates a stream and initialises the underlying stream + * object. + * + * @param arg The argument to be passed to initialise the underlying stream. + * + * @param ctx The SSL context to be used for the stream. + */ + template <typename Arg> + stream(Arg&& arg, context& ctx) + : next_layer_(ASIO_MOVE_CAST(Arg)(arg)), + core_(ctx.native_handle(), + next_layer_.lowest_layer().get_executor().context()) + { + } +#else // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + template <typename Arg> + stream(Arg& arg, context& ctx) + : next_layer_(arg), + core_(ctx.native_handle(), + next_layer_.lowest_layer().get_executor().context()) + { + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destructor. + /** + * @note A @c stream object must not be destroyed while there are pending + * asynchronous operations associated with it. + */ + ~stream() + { + } + + /// Get the executor associated with the object. + /** + * This function may be used to obtain the executor object that the stream + * uses to dispatch handlers for asynchronous operations. + * + * @return A copy of the executor that stream will use to dispatch handlers. + */ + executor_type get_executor() ASIO_NOEXCEPT + { + return next_layer_.lowest_layer().get_executor(); + } + +#if !defined(ASIO_NO_DEPRECATED) + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + asio::io_context& get_io_context() + { + return next_layer_.lowest_layer().get_io_context(); + } + + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + asio::io_context& get_io_service() + { + return next_layer_.lowest_layer().get_io_service(); + } +#endif // !defined(ASIO_NO_DEPRECATED) + + /// Get the underlying implementation in the native type. + /** + * This function may be used to obtain the underlying implementation of the + * context. This is intended to allow access to context functionality that is + * not otherwise provided. + * + * @par Example + * The native_handle() function returns a pointer of type @c SSL* that is + * suitable for passing to functions such as @c SSL_get_verify_result and + * @c SSL_get_peer_certificate: + * @code + * asio::ssl::stream<asio:ip::tcp::socket> sock(io_context, ctx); + * + * // ... establish connection and perform handshake ... + * + * if (X509* cert = SSL_get_peer_certificate(sock.native_handle())) + * { + * if (SSL_get_verify_result(sock.native_handle()) == X509_V_OK) + * { + * // ... + * } + * } + * @endcode + */ + native_handle_type native_handle() + { + return core_.engine_.native_handle(); + } + + /// Get a reference to the next layer. + /** + * This function returns a reference to the next layer in a stack of stream + * layers. + * + * @return A reference to the next layer in the stack of stream layers. + * Ownership is not transferred to the caller. + */ + const next_layer_type& next_layer() const + { + return next_layer_; + } + + /// Get a reference to the next layer. + /** + * This function returns a reference to the next layer in a stack of stream + * layers. + * + * @return A reference to the next layer in the stack of stream layers. + * Ownership is not transferred to the caller. + */ + next_layer_type& next_layer() + { + return next_layer_; + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * stream layers. + * + * @return A reference to the lowest layer in the stack of stream layers. + * Ownership is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return next_layer_.lowest_layer(); + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * stream layers. + * + * @return A reference to the lowest layer in the stack of stream layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return next_layer_.lowest_layer(); + } + + /// Set the peer verification mode. + /** + * This function may be used to configure the peer verification mode used by + * the stream. The new mode will override the mode inherited from the context. + * + * @param v A bitmask of peer verification modes. See @ref verify_mode for + * available values. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_set_verify. + */ + void set_verify_mode(verify_mode v) + { + asio::error_code ec; + set_verify_mode(v, ec); + asio::detail::throw_error(ec, "set_verify_mode"); + } + + /// Set the peer verification mode. + /** + * This function may be used to configure the peer verification mode used by + * the stream. The new mode will override the mode inherited from the context. + * + * @param v A bitmask of peer verification modes. See @ref verify_mode for + * available values. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_set_verify. + */ + ASIO_SYNC_OP_VOID set_verify_mode( + verify_mode v, asio::error_code& ec) + { + core_.engine_.set_verify_mode(v, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Set the peer verification depth. + /** + * This function may be used to configure the maximum verification depth + * allowed by the stream. + * + * @param depth Maximum depth for the certificate chain verification that + * shall be allowed. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_set_verify_depth. + */ + void set_verify_depth(int depth) + { + asio::error_code ec; + set_verify_depth(depth, ec); + asio::detail::throw_error(ec, "set_verify_depth"); + } + + /// Set the peer verification depth. + /** + * This function may be used to configure the maximum verification depth + * allowed by the stream. + * + * @param depth Maximum depth for the certificate chain verification that + * shall be allowed. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_set_verify_depth. + */ + ASIO_SYNC_OP_VOID set_verify_depth( + int depth, asio::error_code& ec) + { + core_.engine_.set_verify_depth(depth, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Set the callback used to verify peer certificates. + /** + * This function is used to specify a callback function that will be called + * by the implementation when it needs to verify a peer certificate. + * + * @param callback The function object to be used for verifying a certificate. + * The function signature of the handler must be: + * @code bool verify_callback( + * bool preverified, // True if the certificate passed pre-verification. + * verify_context& ctx // The peer certificate and other context. + * ); @endcode + * The return value of the callback is true if the certificate has passed + * verification, false otherwise. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls @c SSL_set_verify. + */ + template <typename VerifyCallback> + void set_verify_callback(VerifyCallback callback) + { + asio::error_code ec; + this->set_verify_callback(callback, ec); + asio::detail::throw_error(ec, "set_verify_callback"); + } + + /// Set the callback used to verify peer certificates. + /** + * This function is used to specify a callback function that will be called + * by the implementation when it needs to verify a peer certificate. + * + * @param callback The function object to be used for verifying a certificate. + * The function signature of the handler must be: + * @code bool verify_callback( + * bool preverified, // True if the certificate passed pre-verification. + * verify_context& ctx // The peer certificate and other context. + * ); @endcode + * The return value of the callback is true if the certificate has passed + * verification, false otherwise. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls @c SSL_set_verify. + */ + template <typename VerifyCallback> + ASIO_SYNC_OP_VOID set_verify_callback(VerifyCallback callback, + asio::error_code& ec) + { + core_.engine_.set_verify_callback( + new detail::verify_callback<VerifyCallback>(callback), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Perform SSL handshaking. + /** + * This function is used to perform SSL handshaking on the stream. The + * function call will block until handshaking is complete or an error occurs. + * + * @param type The type of handshaking to be performed, i.e. as a client or as + * a server. + * + * @throws asio::system_error Thrown on failure. + */ + void handshake(handshake_type type) + { + asio::error_code ec; + handshake(type, ec); + asio::detail::throw_error(ec, "handshake"); + } + + /// Perform SSL handshaking. + /** + * This function is used to perform SSL handshaking on the stream. The + * function call will block until handshaking is complete or an error occurs. + * + * @param type The type of handshaking to be performed, i.e. as a client or as + * a server. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID handshake(handshake_type type, + asio::error_code& ec) + { + detail::io(next_layer_, core_, detail::handshake_op(type), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Perform SSL handshaking. + /** + * This function is used to perform SSL handshaking on the stream. The + * function call will block until handshaking is complete or an error occurs. + * + * @param type The type of handshaking to be performed, i.e. as a client or as + * a server. + * + * @param buffers The buffered data to be reused for the handshake. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ConstBufferSequence> + void handshake(handshake_type type, const ConstBufferSequence& buffers) + { + asio::error_code ec; + handshake(type, buffers, ec); + asio::detail::throw_error(ec, "handshake"); + } + + /// Perform SSL handshaking. + /** + * This function is used to perform SSL handshaking on the stream. The + * function call will block until handshaking is complete or an error occurs. + * + * @param type The type of handshaking to be performed, i.e. as a client or as + * a server. + * + * @param buffers The buffered data to be reused for the handshake. + * + * @param ec Set to indicate what error occurred, if any. + */ + template <typename ConstBufferSequence> + ASIO_SYNC_OP_VOID handshake(handshake_type type, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + detail::io(next_layer_, core_, + detail::buffered_handshake_op<ConstBufferSequence>(type, buffers), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Start an asynchronous SSL handshake. + /** + * This function is used to asynchronously perform an SSL handshake on the + * stream. This function call always returns immediately. + * + * @param type The type of handshaking to be performed, i.e. as a client or as + * a server. + * + * @param handler The handler to be called when the handshake operation + * completes. Copies will be made of the handler as required. The equivalent + * function signature of the handler must be: + * @code void handler( + * const asio::error_code& error // Result of operation. + * ); @endcode + */ + template <typename HandshakeHandler> + ASIO_INITFN_RESULT_TYPE(HandshakeHandler, + void (asio::error_code)) + async_handshake(handshake_type type, + ASIO_MOVE_ARG(HandshakeHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a HandshakeHandler. + ASIO_HANDSHAKE_HANDLER_CHECK(HandshakeHandler, handler) type_check; + + asio::async_completion<HandshakeHandler, + void (asio::error_code)> init(handler); + + detail::async_io(next_layer_, core_, + detail::handshake_op(type), init.completion_handler); + + return init.result.get(); + } + + /// Start an asynchronous SSL handshake. + /** + * This function is used to asynchronously perform an SSL handshake on the + * stream. This function call always returns immediately. + * + * @param type The type of handshaking to be performed, i.e. as a client or as + * a server. + * + * @param buffers The buffered data to be reused for the handshake. Although + * the buffers object may be copied as necessary, ownership of the underlying + * buffers is retained by the caller, which must guarantee that they remain + * valid until the handler is called. + * + * @param handler The handler to be called when the handshake operation + * completes. Copies will be made of the handler as required. The equivalent + * function signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Amount of buffers used in handshake. + * ); @endcode + */ + template <typename ConstBufferSequence, typename BufferedHandshakeHandler> + ASIO_INITFN_RESULT_TYPE(BufferedHandshakeHandler, + void (asio::error_code, std::size_t)) + async_handshake(handshake_type type, const ConstBufferSequence& buffers, + ASIO_MOVE_ARG(BufferedHandshakeHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a BufferedHandshakeHandler. + ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( + BufferedHandshakeHandler, handler) type_check; + + asio::async_completion<BufferedHandshakeHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::async_io(next_layer_, core_, + detail::buffered_handshake_op<ConstBufferSequence>(type, buffers), + init.completion_handler); + + return init.result.get(); + } + + /// Shut down SSL on the stream. + /** + * This function is used to shut down SSL on the stream. The function call + * will block until SSL has been shut down or an error occurs. + * + * @throws asio::system_error Thrown on failure. + */ + void shutdown() + { + asio::error_code ec; + shutdown(ec); + asio::detail::throw_error(ec, "shutdown"); + } + + /// Shut down SSL on the stream. + /** + * This function is used to shut down SSL on the stream. The function call + * will block until SSL has been shut down or an error occurs. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID shutdown(asio::error_code& ec) + { + detail::io(next_layer_, core_, detail::shutdown_op(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Asynchronously shut down SSL on the stream. + /** + * This function is used to asynchronously shut down SSL on the stream. This + * function call always returns immediately. + * + * @param handler The handler to be called when the handshake operation + * completes. Copies will be made of the handler as required. The equivalent + * function signature of the handler must be: + * @code void handler( + * const asio::error_code& error // Result of operation. + * ); @endcode + */ + template <typename ShutdownHandler> + ASIO_INITFN_RESULT_TYPE(ShutdownHandler, + void (asio::error_code)) + async_shutdown(ASIO_MOVE_ARG(ShutdownHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ShutdownHandler. + ASIO_SHUTDOWN_HANDLER_CHECK(ShutdownHandler, handler) type_check; + + asio::async_completion<ShutdownHandler, + void (asio::error_code)> init(handler); + + detail::async_io(next_layer_, core_, detail::shutdown_op(), + init.completion_handler); + + return init.result.get(); + } + + /// Write some data to the stream. + /** + * This function is used to write data on the stream. The function call will + * block until one or more bytes of data has been written successfully, or + * until an error occurs. + * + * @param buffers The data to be written. + * + * @returns The number of bytes written. + * + * @throws asio::system_error Thrown on failure. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that all + * data is written before the blocking operation completes. + */ + template <typename ConstBufferSequence> + std::size_t write_some(const ConstBufferSequence& buffers) + { + asio::error_code ec; + std::size_t n = write_some(buffers, ec); + asio::detail::throw_error(ec, "write_some"); + return n; + } + + /// Write some data to the stream. + /** + * This function is used to write data on the stream. The function call will + * block until one or more bytes of data has been written successfully, or + * until an error occurs. + * + * @param buffers The data to be written to the stream. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. Returns 0 if an error occurred. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that all + * data is written before the blocking operation completes. + */ + template <typename ConstBufferSequence> + std::size_t write_some(const ConstBufferSequence& buffers, + asio::error_code& ec) + { + return detail::io(next_layer_, core_, + detail::write_op<ConstBufferSequence>(buffers), ec); + } + + /// Start an asynchronous write. + /** + * This function is used to asynchronously write one or more bytes of data to + * the stream. The function call always returns immediately. + * + * @param buffers The data to be written to the stream. Although the buffers + * object may be copied as necessary, ownership of the underlying buffers is + * retained by the caller, which must guarantee that they remain valid until + * the handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The equivalent function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. + * ); @endcode + * + * @note The async_write_some operation may not transmit all of the data to + * the peer. Consider using the @ref async_write function if you need to + * ensure that all data is written before the blocking operation completes. + */ + template <typename ConstBufferSequence, typename WriteHandler> + ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + ASIO_MOVE_ARG(WriteHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + asio::async_completion<WriteHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::async_io(next_layer_, core_, + detail::write_op<ConstBufferSequence>(buffers), + init.completion_handler); + + return init.result.get(); + } + + /// Read some data from the stream. + /** + * This function is used to read data from the stream. The function call will + * block until one or more bytes of data has been read successfully, or until + * an error occurs. + * + * @param buffers The buffers into which the data will be read. + * + * @returns The number of bytes read. + * + * @throws asio::system_error Thrown on failure. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that the + * requested amount of data is read before the blocking operation completes. + */ + template <typename MutableBufferSequence> + std::size_t read_some(const MutableBufferSequence& buffers) + { + asio::error_code ec; + std::size_t n = read_some(buffers, ec); + asio::detail::throw_error(ec, "read_some"); + return n; + } + + /// Read some data from the stream. + /** + * This function is used to read data from the stream. The function call will + * block until one or more bytes of data has been read successfully, or until + * an error occurs. + * + * @param buffers The buffers into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. Returns 0 if an error occurred. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that the + * requested amount of data is read before the blocking operation completes. + */ + template <typename MutableBufferSequence> + std::size_t read_some(const MutableBufferSequence& buffers, + asio::error_code& ec) + { + return detail::io(next_layer_, core_, + detail::read_op<MutableBufferSequence>(buffers), ec); + } + + /// Start an asynchronous read. + /** + * This function is used to asynchronously read one or more bytes of data from + * the stream. The function call always returns immediately. + * + * @param buffers The buffers into which the data will be read. Although the + * buffers object may be copied as necessary, ownership of the underlying + * buffers is retained by the caller, which must guarantee that they remain + * valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The equivalent function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. + * ); @endcode + * + * @note The async_read_some operation may not read all of the requested + * number of bytes. Consider using the @ref async_read function if you need to + * ensure that the requested amount of data is read before the asynchronous + * operation completes. + */ + template <typename MutableBufferSequence, typename ReadHandler> + ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + ASIO_MOVE_ARG(ReadHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + asio::async_completion<ReadHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::async_io(next_layer_, core_, + detail::read_op<MutableBufferSequence>(buffers), + init.completion_handler); + + return init.result.get(); + } + +private: + Stream next_layer_; + detail::stream_core core_; +}; + +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_STREAM_HPP diff --git a/lib/asio/ssl/stream_base.hpp b/lib/asio/ssl/stream_base.hpp new file mode 100644 index 0000000..56873e4 --- /dev/null +++ b/lib/asio/ssl/stream_base.hpp @@ -0,0 +1,52 @@ +// +// ssl/stream_base.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_STREAM_BASE_HPP +#define ASIO_SSL_STREAM_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { + +/// The stream_base class is used as a base for the asio::ssl::stream +/// class template so that we have a common place to define various enums. +class stream_base +{ +public: + /// Different handshake types. + enum handshake_type + { + /// Perform handshaking as a client. + client, + + /// Perform handshaking as a server. + server + }; + +protected: + /// Protected destructor to prevent deletion through this type. + ~stream_base() + { + } +}; + +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_STREAM_BASE_HPP diff --git a/lib/asio/ssl/verify_context.hpp b/lib/asio/ssl/verify_context.hpp new file mode 100644 index 0000000..e172697 --- /dev/null +++ b/lib/asio/ssl/verify_context.hpp @@ -0,0 +1,67 @@ +// +// ssl/verify_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_VERIFY_CONTEXT_HPP +#define ASIO_SSL_VERIFY_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/noncopyable.hpp" +#include "asio/ssl/detail/openssl_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { + +/// A simple wrapper around the X509_STORE_CTX type, used during verification of +/// a peer certificate. +/** + * @note The verify_context does not own the underlying X509_STORE_CTX object. + */ +class verify_context + : private noncopyable +{ +public: + /// The native handle type of the verification context. + typedef X509_STORE_CTX* native_handle_type; + + /// Constructor. + explicit verify_context(native_handle_type handle) + : handle_(handle) + { + } + + /// Get the underlying implementation in the native type. + /** + * This function may be used to obtain the underlying implementation of the + * context. This is intended to allow access to context functionality that is + * not otherwise provided. + */ + native_handle_type native_handle() + { + return handle_; + } + +private: + // The underlying native implementation. + native_handle_type handle_; +}; + +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_VERIFY_CONTEXT_HPP diff --git a/lib/asio/ssl/verify_mode.hpp b/lib/asio/ssl/verify_mode.hpp new file mode 100644 index 0000000..8c4b394 --- /dev/null +++ b/lib/asio/ssl/verify_mode.hpp @@ -0,0 +1,63 @@ +// +// ssl/verify_mode.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SSL_VERIFY_MODE_HPP +#define ASIO_SSL_VERIFY_MODE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/ssl/detail/openssl_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { + +/// Bitmask type for peer verification. +/** + * Possible values are: + * + * @li @ref verify_none + * @li @ref verify_peer + * @li @ref verify_fail_if_no_peer_cert + * @li @ref verify_client_once + */ +typedef int verify_mode; + +#if defined(GENERATING_DOCUMENTATION) +/// No verification. +const int verify_none = implementation_defined; + +/// Verify the peer. +const int verify_peer = implementation_defined; + +/// Fail verification if the peer has no certificate. Ignored unless +/// @ref verify_peer is set. +const int verify_fail_if_no_peer_cert = implementation_defined; + +/// Do not request client certificate on renegotiation. Ignored unless +/// @ref verify_peer is set. +const int verify_client_once = implementation_defined; +#else +const int verify_none = SSL_VERIFY_NONE; +const int verify_peer = SSL_VERIFY_PEER; +const int verify_fail_if_no_peer_cert = SSL_VERIFY_FAIL_IF_NO_PEER_CERT; +const int verify_client_once = SSL_VERIFY_CLIENT_ONCE; +#endif + +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_VERIFY_MODE_HPP |