1 | // |
2 | // OpenSSLInitializer.cpp |
3 | // |
4 | // Library: Crypto |
5 | // Package: CryptoCore |
6 | // Module: OpenSSLInitializer |
7 | // |
8 | // Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/Crypto/OpenSSLInitializer.h" |
16 | #include "Poco/RandomStream.h" |
17 | #include "Poco/Thread.h" |
18 | #include <openssl/ssl.h> |
19 | #include <openssl/rand.h> |
20 | #include <openssl/crypto.h> |
21 | #include <openssl/err.h> |
22 | #if OPENSSL_VERSION_NUMBER >= 0x0907000L |
23 | #include <openssl/conf.h> |
24 | #endif |
25 | #if defined(POCO_OS_FAMILY_WINDOWS) |
26 | #define POCO_STR_HELPER(x) #x |
27 | #define POCO_STR(x) POCO_STR_HELPER(x) |
28 | #if defined POCO_INTERNAL_OPENSSL_MSVC_VER |
29 | #define POCO_INTERNAL_OPENSSL_BUILD \ |
30 | " (POCO internal build, MSVC version " \ |
31 | POCO_STR(POCO_INTERNAL_OPENSSL_MSVC_VER) ")" |
32 | #else |
33 | #define POCO_INTERNAL_OPENSSL_BUILD "" |
34 | #endif |
35 | #pragma message (OPENSSL_VERSION_TEXT POCO_INTERNAL_OPENSSL_BUILD) |
36 | #endif |
37 | |
38 | |
39 | using Poco::RandomInputStream; |
40 | using Poco::Thread; |
41 | |
42 | |
43 | #if defined(_MSC_VER) && !defined(_DLL) && defined(POCO_INTERNAL_OPENSSL_MSVC_VER) |
44 | |
45 | #if (POCO_MSVS_VERSION >= 2015) |
46 | FILE _iob[] = { *stdin, *stdout, *stderr }; |
47 | extern "C" FILE * __cdecl __iob_func(void) { return _iob; } |
48 | #endif // (POCO_MSVS_VERSION >= 2015) |
49 | |
50 | #if (POCO_MSVS_VERSION < 2012) |
51 | extern "C" __declspec(noreturn) void __cdecl __report_rangecheckfailure(void) { ::ExitProcess(1); } |
52 | #endif // (POCO_MSVS_VERSION < 2012) |
53 | |
54 | #endif // defined(_MSC_VER) && !defined(_DLL) && defined(POCO_INTERNAL_OPENSSL_MSVC_VER) |
55 | |
56 | |
57 | namespace Poco { |
58 | namespace Crypto { |
59 | |
60 | Poco::FastMutex OpenSSLInitializer::_mutex; |
61 | Poco::FastMutex* OpenSSLInitializer::_mutexes(0); |
62 | int OpenSSLInitializer::_rc(0); |
63 | bool OpenSSLInitializer::_disableSSLInitialization = false; |
64 | |
65 | OpenSSLInitializer::OpenSSLInitializer() |
66 | { |
67 | initialize(); |
68 | } |
69 | |
70 | |
71 | OpenSSLInitializer::~OpenSSLInitializer() |
72 | { |
73 | try |
74 | { |
75 | uninitialize(); |
76 | } |
77 | catch (...) |
78 | { |
79 | poco_unexpected(); |
80 | } |
81 | } |
82 | |
83 | |
84 | void OpenSSLInitializer::initialize() |
85 | { |
86 | FastMutex::ScopedLock lock(_mutex); |
87 | if (++_rc == 1) |
88 | { |
89 | #if OPENSSL_VERSION_NUMBER >= 0x0907000L |
90 | OPENSSL_config(NULL); |
91 | #endif |
92 | if(! _disableSSLInitialization) |
93 | { |
94 | SSL_library_init(); |
95 | SSL_load_error_strings(); |
96 | OpenSSL_add_all_algorithms(); |
97 | } |
98 | |
99 | char seed[SEEDSIZE]; |
100 | RandomInputStream rnd; |
101 | rnd.read(seed, sizeof(seed)); |
102 | RAND_seed(seed, SEEDSIZE); |
103 | |
104 | if(CRYPTO_get_locking_callback() == NULL) |
105 | { |
106 | int nMutexes = CRYPTO_num_locks(); |
107 | _mutexes = new Poco::FastMutex[nMutexes]; |
108 | CRYPTO_set_locking_callback(&OpenSSLInitializer::lock); |
109 | #ifndef POCO_OS_FAMILY_WINDOWS |
110 | // Not needed on Windows (see SF #110: random unhandled exceptions when linking with ssl). |
111 | // https://sourceforge.net/p/poco/bugs/110/ |
112 | // |
113 | // From http://www.openssl.org/docs/crypto/threads.html : |
114 | // "If the application does not register such a callback using CRYPTO_THREADID_set_callback(), |
115 | // then a default implementation is used - on Windows and BeOS this uses the system's |
116 | // default thread identifying APIs" |
117 | #ifndef OPENSSL_NO_DEPRECATED |
118 | CRYPTO_set_id_callback(&OpenSSLInitializer::id); |
119 | #else |
120 | CRYPTO_THREADID tid; |
121 | CRYPTO_THREADID_set_numeric(&tid, OpenSSLInitializer::id()); |
122 | #endif /* OPENSSL_NO_DEPRECATED */ |
123 | #endif |
124 | CRYPTO_set_dynlock_create_callback(&OpenSSLInitializer::dynlockCreate); |
125 | CRYPTO_set_dynlock_lock_callback(&OpenSSLInitializer::dynlock); |
126 | CRYPTO_set_dynlock_destroy_callback(&OpenSSLInitializer::dynlockDestroy); |
127 | } |
128 | } |
129 | } |
130 | |
131 | |
132 | void OpenSSLInitializer::uninitialize() |
133 | { |
134 | FastMutex::ScopedLock lock(_mutex); |
135 | if (--_rc == 0) |
136 | { |
137 | if(_mutexes != NULL) |
138 | { |
139 | CRYPTO_set_dynlock_create_callback(0); |
140 | CRYPTO_set_dynlock_lock_callback(0); |
141 | CRYPTO_set_dynlock_destroy_callback(0); |
142 | CRYPTO_set_locking_callback(0); |
143 | #ifndef POCO_OS_FAMILY_WINDOWS |
144 | #ifndef OPENSSL_NO_DEPRECATED |
145 | CRYPTO_set_id_callback(0); |
146 | #else |
147 | CRYPTO_THREADID tid; |
148 | CRYPTO_THREADID_set_numeric(&tid, 0); |
149 | #endif /* OPENSSL_NO_DEPRECATED */ |
150 | #endif |
151 | delete [] _mutexes; |
152 | } |
153 | |
154 | if(! _disableSSLInitialization) |
155 | { |
156 | EVP_cleanup(); |
157 | ERR_free_strings(); |
158 | CONF_modules_free(); |
159 | } |
160 | } |
161 | } |
162 | |
163 | |
164 | void OpenSSLInitializer::lock(int mode, int n, const char* file, int line) |
165 | { |
166 | if (mode & CRYPTO_LOCK) |
167 | _mutexes[n].lock(); |
168 | else |
169 | _mutexes[n].unlock(); |
170 | } |
171 | |
172 | |
173 | #ifndef POCO_OS_FAMILY_WINDOWS |
174 | |
175 | unsigned long OpenSSLInitializer::id() |
176 | { |
177 | // Note: we use an old-style C cast here because |
178 | // neither static_cast<> nor reinterpret_cast<> |
179 | // work uniformly across all platforms. |
180 | return (unsigned long) Poco::Thread::currentTid(); |
181 | } |
182 | |
183 | #endif |
184 | |
185 | |
186 | struct CRYPTO_dynlock_value* OpenSSLInitializer::dynlockCreate(const char* file, int line) |
187 | { |
188 | return new CRYPTO_dynlock_value; |
189 | } |
190 | |
191 | |
192 | void OpenSSLInitializer::dynlock(int mode, struct CRYPTO_dynlock_value* lock, const char* file, int line) |
193 | { |
194 | poco_check_ptr (lock); |
195 | |
196 | if (mode & CRYPTO_LOCK) |
197 | lock->_mutex.lock(); |
198 | else |
199 | lock->_mutex.unlock(); |
200 | } |
201 | |
202 | |
203 | void OpenSSLInitializer::dynlockDestroy(struct CRYPTO_dynlock_value* lock, const char* file, int line) |
204 | { |
205 | delete lock; |
206 | } |
207 | |
208 | |
209 | void initializeCrypto() |
210 | { |
211 | OpenSSLInitializer::initialize(); |
212 | } |
213 | |
214 | |
215 | void uninitializeCrypto() |
216 | { |
217 | OpenSSLInitializer::uninitialize(); |
218 | } |
219 | |
220 | |
221 | } } // namespace Poco::Crypto |
222 | |