Automatically disable SSL compression. To mitigate the risk of certain attacks, SSL compression is now disabled by default. To enable, you can use the new ssl::context::clear_options() function like so: my_context.clear_options(asio::ssl::context::no_compression);
diff --git a/asio/include/asio/ssl/context.hpp b/asio/include/asio/ssl/context.hpp index e6524eb..f4c1c69 100644 --- a/asio/include/asio/ssl/context.hpp +++ b/asio/include/asio/ssl/context.hpp
@@ -109,6 +109,35 @@ */ ASIO_DECL impl_type impl(); + /// 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::error_code 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.
diff --git a/asio/include/asio/ssl/context_base.hpp b/asio/include/asio/ssl/context_base.hpp index 5eddbc3..0c27186 100644 --- a/asio/include/asio/ssl/context_base.hpp +++ b/asio/include/asio/ssl/context_base.hpp
@@ -104,12 +104,20 @@ /// Disable TLS v1. static const long no_tlsv1 = 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_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.
diff --git a/asio/include/asio/ssl/detail/impl/openssl_init.ipp b/asio/include/asio/ssl/detail/impl/openssl_init.ipp index 1eee361..383eb84 100644 --- a/asio/include/asio/ssl/detail/impl/openssl_init.ipp +++ b/asio/include/asio/ssl/detail/impl/openssl_init.ipp
@@ -44,10 +44,22 @@ mutexes_[i].reset(new asio::detail::mutex); ::CRYPTO_set_locking_callback(&do_init::openssl_locking_func); ::CRYPTO_set_id_callback(&do_init::openssl_id_func); + +#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) + ::CRYPTO_set_id_callback(0); ::CRYPTO_set_locking_callback(0); ::ERR_free_strings(); @@ -60,6 +72,15 @@ #endif // !defined(OPENSSL_NO_ENGINE) } +#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: static unsigned long openssl_id_func() { @@ -91,6 +112,12 @@ // The thread identifiers to be used by openssl. asio::detail::tss_ptr<void> thread_id_; #endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#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> @@ -100,6 +127,15 @@ 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
diff --git a/asio/include/asio/ssl/detail/openssl_init.hpp b/asio/include/asio/ssl/detail/openssl_init.hpp index c48b49c..5043cf1 100644 --- a/asio/include/asio/ssl/detail/openssl_init.hpp +++ b/asio/include/asio/ssl/detail/openssl_init.hpp
@@ -19,6 +19,7 @@ #include <cstring> #include "asio/detail/noncopyable.hpp" #include "asio/detail/shared_ptr.hpp" +#include "asio/ssl/detail/openssl_types.hpp" #include "asio/detail/push_options.hpp" @@ -39,6 +40,14 @@ // 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> @@ -61,6 +70,12 @@ { } +#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_;
diff --git a/asio/include/asio/ssl/impl/context.ipp b/asio/include/asio/ssl/impl/context.ipp index e4bd1d5..f15df35 100644 --- a/asio/include/asio/ssl/impl/context.ipp +++ b/asio/include/asio/ssl/impl/context.ipp
@@ -161,6 +161,8 @@ asio::error::get_ssl_category()); asio::detail::throw_error(ec, "context"); } + + set_options(no_compression); } context::context(asio::io_service&, context::method m) @@ -223,6 +225,32 @@ 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::error_code context::clear_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 = 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(); + return ec; +} + void context::set_options(context::options o) { asio::error_code ec; @@ -233,6 +261,17 @@ asio::error_code 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();