1//
2// ssl/detail/impl/openssl_init.ipp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
6// Copyright (c) 2005-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7//
8// Distributed under the Boost Software License, Version 1.0. (See accompanying
9// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10//
11
12#ifndef BOOST_ASIO_SSL_DETAIL_IMPL_OPENSSL_INIT_IPP
13#define BOOST_ASIO_SSL_DETAIL_IMPL_OPENSSL_INIT_IPP
14
15#if defined(_MSC_VER) && (_MSC_VER >= 1200)
16# pragma once
17#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18
19#include <boost/asio/detail/config.hpp>
20#include <vector>
21#include <boost/asio/detail/assert.hpp>
22#include <boost/asio/detail/mutex.hpp>
23#include <boost/asio/detail/tss_ptr.hpp>
24#include <boost/asio/ssl/detail/openssl_init.hpp>
25#include <boost/asio/ssl/detail/openssl_types.hpp>
26
27#include <boost/asio/detail/push_options.hpp>
28
29namespace boost {
30namespace asio {
31namespace ssl {
32namespace detail {
33
34class openssl_init_base::do_init
35{
36public:
37  do_init()
38  {
39#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
40    ::SSL_library_init();
41    ::SSL_load_error_strings();
42    ::OpenSSL_add_all_algorithms();
43
44    mutexes_.resize(::CRYPTO_num_locks());
45    for (size_t i = 0; i < mutexes_.size(); ++i)
46      mutexes_[i].reset(new boost::asio::detail::mutex);
47    ::CRYPTO_set_locking_callback(&do_init::openssl_locking_func);
48#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L)
49#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
50    ::CRYPTO_set_id_callback(&do_init::openssl_id_func);
51#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
52
53#if !defined(SSL_OP_NO_COMPRESSION) \
54  && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
55    null_compression_methods_ = sk_SSL_COMP_new_null();
56#endif // !defined(SSL_OP_NO_COMPRESSION)
57       // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
58  }
59
60  ~do_init()
61  {
62#if !defined(SSL_OP_NO_COMPRESSION) \
63  && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
64    sk_SSL_COMP_free(null_compression_methods_);
65#endif // !defined(SSL_OP_NO_COMPRESSION)
66       // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
67
68#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
69    ::CRYPTO_set_id_callback(0);
70#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
71#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
72    ::CRYPTO_set_locking_callback(0);
73    ::ERR_free_strings();
74    ::EVP_cleanup();
75    ::CRYPTO_cleanup_all_ex_data();
76#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L)
77#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
78    ::ERR_remove_state(0);
79#elif (OPENSSL_VERSION_NUMBER < 0x10100000L)
80    ::ERR_remove_thread_state(NULL);
81#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
82#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) \
83    && (OPENSSL_VERSION_NUMBER < 0x10100000L) \
84    && !defined(SSL_OP_NO_COMPRESSION)
85    ::SSL_COMP_free_compression_methods();
86#endif // (OPENSSL_VERSION_NUMBER >= 0x10002000L)
87       // && (OPENSSL_VERSION_NUMBER < 0x10100000L)
88       // && !defined(SSL_OP_NO_COMPRESSION)
89#if !defined(OPENSSL_IS_BORINGSSL) && !defined(BOOST_ASIO_USE_WOLFSSL)
90    ::CONF_modules_unload(1);
91#endif // !defined(OPENSSL_IS_BORINGSSL) && !defined(BOOST_ASIO_USE_WOLFSSL)
92#if !defined(OPENSSL_NO_ENGINE) \
93  && (OPENSSL_VERSION_NUMBER < 0x10100000L)
94    ::ENGINE_cleanup();
95#endif // !defined(OPENSSL_NO_ENGINE)
96       // && (OPENSSL_VERSION_NUMBER < 0x10100000L)
97  }
98
99#if !defined(SSL_OP_NO_COMPRESSION) \
100  && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
101  STACK_OF(SSL_COMP)* get_null_compression_methods() const
102  {
103    return null_compression_methods_;
104  }
105#endif // !defined(SSL_OP_NO_COMPRESSION)
106       // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
107
108private:
109#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
110  static unsigned long openssl_id_func()
111  {
112#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
113    return ::GetCurrentThreadId();
114#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
115    void* id = &errno;
116    BOOST_ASIO_ASSERT(sizeof(unsigned long) >= sizeof(void*));
117    return reinterpret_cast<unsigned long>(id);
118#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
119  }
120#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
121
122#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
123  static void openssl_locking_func(int mode, int n,
124    const char* /*file*/, int /*line*/)
125  {
126    if (mode & CRYPTO_LOCK)
127      instance()->mutexes_[n]->lock();
128    else
129      instance()->mutexes_[n]->unlock();
130  }
131
132  // Mutexes to be used in locking callbacks.
133  std::vector<boost::asio::detail::shared_ptr<
134        boost::asio::detail::mutex> > mutexes_;
135#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L)
136
137#if !defined(SSL_OP_NO_COMPRESSION) \
138  && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
139  STACK_OF(SSL_COMP)* null_compression_methods_;
140#endif // !defined(SSL_OP_NO_COMPRESSION)
141       // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
142};
143
144boost::asio::detail::shared_ptr<openssl_init_base::do_init>
145openssl_init_base::instance()
146{
147  static boost::asio::detail::shared_ptr<do_init> init(new do_init);
148  return init;
149}
150
151#if !defined(SSL_OP_NO_COMPRESSION) \
152  && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
153STACK_OF(SSL_COMP)* openssl_init_base::get_null_compression_methods()
154{
155  return instance()->get_null_compression_methods();
156}
157#endif // !defined(SSL_OP_NO_COMPRESSION)
158       // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)
159
160} // namespace detail
161} // namespace ssl
162} // namespace asio
163} // namespace boost
164
165#include <boost/asio/detail/pop_options.hpp>
166
167#endif // BOOST_ASIO_SSL_DETAIL_IMPL_OPENSSL_INIT_IPP
168